static void print_node(topo_hdl_t *thp, tnode_t *node, nvlist_t *nvl, const char *fmri) { int err, ret; (void) printf("%s\n", (char *)fmri); if (opt_p && !(pcnt > 0 || opt_V || opt_all)) { char *aname = NULL, *fname = NULL, *lname = NULL; nvlist_t *asru = NULL; nvlist_t *fru = NULL; if (topo_node_asru(node, &asru, NULL, &err) == 0) (void) topo_fmri_nvl2str(thp, asru, &aname, &err); if (topo_node_fru(node, &fru, NULL, &err) == 0) (void) topo_fmri_nvl2str(thp, fru, &fname, &err); (void) topo_node_label(node, &lname, &err); if (aname != NULL) { nvlist_free(asru); (void) printf("\tASRU: %s\n", aname); topo_hdl_strfree(thp, aname); } else { (void) printf("\tASRU: -\n"); } if (fname != NULL) { nvlist_free(fru); (void) printf("\tFRU: %s\n", fname); topo_hdl_strfree(thp, fname); } else { (void) printf("\tFRU: -\n"); } if (lname != NULL) { (void) printf("\tLabel: %s\n", lname); topo_hdl_strfree(thp, lname); } else { (void) printf("\tLabel: -\n"); } } if (opt_S) { if ((ret = topo_fmri_present(thp, nvl, &err)) < 0) (void) printf("\tPresent: -\n"); else (void) printf("\tPresent: %s\n", ret ? "true" : "false"); if ((ret = topo_fmri_unusable(thp, nvl, &err)) < 0) (void) printf("\tUnusable: -\n"); else (void) printf("\tUnusable: %s\n", ret ? "true" : "false"); } }
/* * Look up the FMRI corresponding to the node in the global * hash table and return the pointer stored (if any). Save the * FMRI string in *str if str is non-NULL. */ static void * fmri2ptr(topo_hdl_t *thp, tnode_t *node, char **str, int *err) { nvlist_t *fmri = NULL; char *cstr = NULL; uint64_t u64val; void *p = NULL; if (topo_node_resource(node, &fmri, err) != 0) return (NULL); if (topo_fmri_nvl2str(thp, fmri, &cstr, err) != 0) { nvlist_free(fmri); return (NULL); } if (nvlist_lookup_uint64(g_topo2diskmon, cstr, &u64val) == 0) { p = (void *)(uintptr_t)u64val; } nvlist_free(fmri); if (str != NULL) *str = dstrdup(cstr); topo_hdl_strfree(thp, cstr); return (p); }
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); }
ssize_t fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) { int err; ssize_t len; topo_hdl_t *thp; char *str; if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) return (fmd_fmri_set_errno(EINVAL)); if (topo_fmri_nvl2str(thp, nvl, &str, &err) != 0) { fmd_fmri_topo_rele(thp); return (fmd_fmri_set_errno(EINVAL)); } if (buf != NULL) len = snprintf(buf, buflen, "%s", str); else len = strlen(str); topo_hdl_strfree(thp, str); fmd_fmri_topo_rele(thp); return (len); }
static int topo_add_disk(topo_hdl_t *thp, tnode_t *node, diskmon_t *target_diskp) { nvlist_t *fmri = NULL; nvlist_t *asru_fmri; nvlist_t *fru_fmri; char *devpath = NULL; char *capacity = NULL; char *firmrev = NULL; char *serial = NULL; char *manuf = NULL; char *model = NULL; char *cstr = NULL; char *buf; char *label; char *p; uint64_t ptr = 0; int buflen; int err; int orig_cstr_len; dm_fru_t *frup; diskmon_t *diskp; /* * Match this node to a disk in the configuration by looking at * our parent's fmri (and do that by getting our FMRI and chopping * off the last part). */ if (topo_node_resource(node, &fmri, &err) != 0) { log_msg(MM_TOPO, "topo_add_disk: Could not generate FMRI for " "node %p!\n", (void *)node); return (-1); } if (topo_fmri_nvl2str(thp, fmri, &cstr, &err) != 0) { log_msg(MM_TOPO, "topo_add_disk: Could not create string for " "node %p's FMRI!\n", (void *)node); nvlist_free(fmri); return (-1); } nvlist_free(fmri); /* * Chop off all but last path (since there's no way to get * the node's parent in the libtopo API). */ orig_cstr_len = strlen(cstr) + 1; p = strrchr(cstr, '/'); dm_assert(p != NULL); *p = 0; if (nvlist_lookup_uint64(g_topo2diskmon, cstr, &ptr) != 0) { log_msg(MM_TOPO, "No diskmon for parent of node %p.\n", node); topo_hdl_free(thp, cstr, orig_cstr_len); /* Skip this disk: */ return (0); } topo_hdl_free(thp, cstr, orig_cstr_len); diskp = (diskmon_t *)(uintptr_t)ptr; /* If we were called upon to update a particular disk, do it */ if (target_diskp != NULL && diskp != target_diskp) { return (0); } /* * Update the diskmon's ASRU and FRU with our information (this * information is cached in the diskmon so we don't have to do a * time-consuming topo traversal when we get an ereport). */ if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, &asru_fmri, &err) == 0) { diskmon_add_asru(diskp, asru_fmri); nvlist_free(asru_fmri); } if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, &fru_fmri, &err) == 0) { diskmon_add_fru(diskp, fru_fmri); nvlist_free(fru_fmri); } if (topo_node_resource(node, &fmri, &err) == 0) { diskmon_add_disk_fmri(diskp, fmri); nvlist_free(fmri); } /* * Update the diskmon's location field with the disk's label */ if (diskp->location) dstrfree(diskp->location); if (topo_node_label(node, &label, &err) == 0) { diskp->location = dstrdup(label); topo_hdl_strfree(thp, label); } else diskp->location = dstrdup("unknown location"); /* * Check for a device path property (if the disk is configured, * it will be present) and add it to the diskmon's properties) */ if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH, &devpath, &err) == 0) { char devp[PATH_MAX]; /* * Consumers of the DISK_PROP_DEVPATH property expect a raw * minor device node */ (void) snprintf(devp, PATH_MAX, "%s:q,raw", devpath); (void) nvlist_add_string(diskp->props, DISK_PROP_DEVPATH, devp); topo_hdl_strfree(thp, devpath); } /* * Add the logical disk node, if it exists */ if (topo_prop_get_string(node, TOPO_STORAGE_PGROUP, TOPO_STORAGE_LOGICAL_DISK_NAME, &devpath, &err) == 0) { (void) nvlist_add_string(diskp->props, DISK_PROP_LOGNAME, devpath); topo_hdl_strfree(thp, devpath); } /* * Add the FRU information (if present in the node) to the diskmon's * fru data structure: */ (void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP, TOPO_STORAGE_MODEL, &model, &err); (void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP, TOPO_STORAGE_MANUFACTURER, &manuf, &err); (void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP, TOPO_STORAGE_SERIAL_NUM, &serial, &err); (void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP, TOPO_STORAGE_FIRMWARE_REV, &firmrev, &err); (void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP, TOPO_STORAGE_CAPACITY, &capacity, &err); frup = new_dmfru(manuf, model, firmrev, serial, capacity == NULL ? 0 : strtoull(capacity, 0, 0)); /* * Update the disk's resource FMRI with the * SunService-required members: * FM_FMRI_HC_SERIAL_ID, FM_FMRI_HC_PART, and * FM_FMRI_HC_REVISION */ (void) nvlist_add_string(diskp->disk_res_fmri, FM_FMRI_HC_SERIAL_ID, serial); transform_model_string(manuf, model, &buf, &buflen); (void) nvlist_add_string(diskp->disk_res_fmri, FM_FMRI_HC_PART, buf); /* * Add the serial number to the ASRU so that when the resource * is marked faulty in the fmd resource cache, the hc scheme * plugin can detect when the disk is no longer installed (and so, * can clear the faulty state automatically across fmd restarts). * * The serial number is only updated when a disk comes online * because that's when the disk node exists in the topo tree. * It's ok to keep a stale value in the ASRU when the disk is removed * because it's only used as part of fault creation when the disk * is configured (online), at which point it will be updated with * the (current) serial number of the disk inserted. */ (void) nvlist_add_string(diskp->asru_fmri, FM_FMRI_HC_SERIAL_ID, serial); dfree(buf, buflen); (void) nvlist_add_string(diskp->disk_res_fmri, FM_FMRI_HC_REVISION, firmrev); if (model) { topo_hdl_strfree(thp, model); } if (manuf) { topo_hdl_strfree(thp, manuf); } if (serial) { topo_hdl_strfree(thp, serial); } if (firmrev) { topo_hdl_strfree(thp, firmrev); } if (capacity) { topo_hdl_strfree(thp, capacity); } /* Add the fru information to the diskmon: */ dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0); dm_assert(diskp->frup == NULL); diskp->frup = frup; dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0); return (0); }
/*ARGSUSED*/ static int walk_node(topo_hdl_t *thp, tnode_t *node, void *arg) { int err; nvlist_t *nvl; nvlist_t *rsrc, *out; char *s; if (opt_e && strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0) { print_everstyle(node); return (TOPO_WALK_NEXT); } if (topo_node_resource(node, &rsrc, &err) < 0) { (void) fprintf(stderr, "%s: failed to get resource: " "%s", g_pname, topo_strerror(err)); return (TOPO_WALK_NEXT); } if (topo_fmri_nvl2str(thp, rsrc, &s, &err) < 0) { (void) fprintf(stderr, "%s: failed to convert " "resource to FMRI string: %s", g_pname, topo_strerror(err)); nvlist_free(rsrc); return (TOPO_WALK_NEXT); } if (g_fmri != NULL && fnmatch(g_fmri, s, 0) != 0) { nvlist_free(rsrc); topo_hdl_strfree(thp, s); return (TOPO_WALK_NEXT); } print_node(thp, node, rsrc, s); topo_hdl_strfree(thp, s); nvlist_free(rsrc); if (opt_m != NULL) { if (topo_method_invoke(node, opt_m, 0, NULL, &out, &err) == 0) { nvlist_print(stdout, out); nvlist_free(out); } else if (err != ETOPO_METHOD_NOTSUP) (void) fprintf(stderr, "%s: method failed unexpectedly " "on %s=%d (%s)\n", g_pname, topo_node_name(node), topo_node_instance(node), topo_strerror(err)); } if (opt_V || opt_all) { if ((nvl = topo_prop_getprops(node, &err)) == NULL) { (void) fprintf(stderr, "%s: failed to get " "properties for %s=%d: %s\n", g_pname, topo_node_name(node), topo_node_instance(node), topo_strerror(err)); } else { print_all_props(thp, node, nvl, ALL); nvlist_free(nvl); } } else if (pcnt > 0) print_props(thp, node); (void) printf("\n"); return (TOPO_WALK_NEXT); }
static void print_prop_nameval(topo_hdl_t *thp, tnode_t *node, nvlist_t *nvl) { int err; topo_type_t type; char *tstr, *propn, buf[48], *factype; nvpair_t *pv_nvp; int i; uint_t nelem; if ((pv_nvp = nvlist_next_nvpair(nvl, NULL)) == NULL) return; /* Print property name */ if ((pv_nvp = nvlist_next_nvpair(nvl, NULL)) == NULL || nvpair_name(pv_nvp) == NULL || strcmp(TOPO_PROP_VAL_NAME, nvpair_name(pv_nvp)) != 0) { (void) fprintf(stderr, "%s: malformed property name\n", g_pname); return; } else { (void) nvpair_value_string(pv_nvp, &propn); } if ((pv_nvp = nvlist_next_nvpair(nvl, pv_nvp)) == NULL || nvpair_name(pv_nvp) == NULL || strcmp(nvpair_name(pv_nvp), TOPO_PROP_VAL_TYPE) != 0 || nvpair_type(pv_nvp) != DATA_TYPE_UINT32) { (void) fprintf(stderr, "%s: malformed property type for %s\n", g_pname, propn); return; } else { (void) nvpair_value_uint32(pv_nvp, (uint32_t *)&type); } switch (type) { case TOPO_TYPE_BOOLEAN: tstr = "boolean"; break; case TOPO_TYPE_INT32: tstr = "int32"; break; case TOPO_TYPE_UINT32: tstr = "uint32"; break; case TOPO_TYPE_INT64: tstr = "int64"; break; case TOPO_TYPE_UINT64: tstr = "uint64"; break; case TOPO_TYPE_DOUBLE: tstr = "double"; break; case TOPO_TYPE_STRING: tstr = "string"; break; case TOPO_TYPE_FMRI: tstr = "fmri"; break; case TOPO_TYPE_INT32_ARRAY: tstr = "int32[]"; break; case TOPO_TYPE_UINT32_ARRAY: tstr = "uint32[]"; break; case TOPO_TYPE_INT64_ARRAY: tstr = "int64[]"; break; case TOPO_TYPE_UINT64_ARRAY: tstr = "uint64[]"; break; case TOPO_TYPE_STRING_ARRAY: tstr = "string[]"; break; case TOPO_TYPE_FMRI_ARRAY: tstr = "fmri[]"; break; default: tstr = "unknown type"; } (void) printf(" %-17s %-8s ", propn, tstr); /* * Get property value */ if (nvpair_name(pv_nvp) == NULL || (pv_nvp = nvlist_next_nvpair(nvl, pv_nvp)) == NULL) { (void) fprintf(stderr, "%s: malformed property value\n", g_pname); return; } switch (nvpair_type(pv_nvp)) { case DATA_TYPE_INT32: { int32_t val; (void) nvpair_value_int32(pv_nvp, &val); (void) printf(" %d", val); break; } case DATA_TYPE_UINT32: { uint32_t val, type; char val_str[49]; nvlist_t *fac, *rsrc = NULL; (void) nvpair_value_uint32(pv_nvp, &val); if (node == NULL || topo_node_flags(node) != TOPO_NODE_FACILITY) goto uint32_def; if (topo_node_resource(node, &rsrc, &err) != 0) goto uint32_def; if (nvlist_lookup_nvlist(rsrc, "facility", &fac) != 0) goto uint32_def; if (nvlist_lookup_string(fac, FM_FMRI_FACILITY_TYPE, &factype) != 0) goto uint32_def; nvlist_free(rsrc); rsrc = NULL; /* * Special case code to do friendlier printing of * facility node properties */ if ((strcmp(propn, TOPO_FACILITY_TYPE) == 0) && (strcmp(factype, TOPO_FAC_TYPE_SENSOR) == 0)) { topo_sensor_type_name(val, val_str, 48); (void) printf(" 0x%x (%s)", val, val_str); break; } else if ((strcmp(propn, TOPO_FACILITY_TYPE) == 0) && (strcmp(factype, TOPO_FAC_TYPE_INDICATOR) == 0)) { topo_led_type_name(val, val_str, 48); (void) printf(" 0x%x (%s)", val, val_str); break; } else if (strcmp(propn, TOPO_SENSOR_UNITS) == 0) { topo_sensor_units_name(val, val_str, 48); (void) printf(" 0x%x (%s)", val, val_str); break; } else if (strcmp(propn, TOPO_LED_MODE) == 0) { topo_led_state_name(val, val_str, 48); (void) printf(" 0x%x (%s)", val, val_str); break; } else if ((strcmp(propn, TOPO_SENSOR_STATE) == 0) && (strcmp(factype, TOPO_FAC_TYPE_SENSOR) == 0)) { if (topo_prop_get_uint32(node, TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE, &type, &err) != 0) { goto uint32_def; } topo_sensor_state_name(type, val, val_str, 48); (void) printf(" 0x%x (%s)", val, val_str); break; } uint32_def: (void) printf(" 0x%x", val); if (rsrc != NULL) nvlist_free(rsrc); break; } case DATA_TYPE_INT64: { int64_t val; (void) nvpair_value_int64(pv_nvp, &val); (void) printf(" %lld", (longlong_t)val); break; } case DATA_TYPE_UINT64: { uint64_t val; (void) nvpair_value_uint64(pv_nvp, &val); (void) printf(" 0x%llx", (u_longlong_t)val); break; } case DATA_TYPE_DOUBLE: { double val; (void) nvpair_value_double(pv_nvp, &val); (void) printf(" %lf", (double)val); break; } case DATA_TYPE_STRING: { char *val; (void) nvpair_value_string(pv_nvp, &val); if (!opt_V && strlen(val) > 48) { (void) snprintf(buf, 48, "%s...", val); (void) printf(" %s", buf); } else { (void) printf(" %s", val); } break; } case DATA_TYPE_NVLIST: { nvlist_t *val; char *fmri; (void) nvpair_value_nvlist(pv_nvp, &val); if (topo_fmri_nvl2str(thp, val, &fmri, &err) != 0) { if (opt_V) nvlist_print(stdout, nvl); break; } if (!opt_V && strlen(fmri) > 48) { (void) snprintf(buf, 48, "%s", fmri); (void) snprintf(&buf[45], 4, "%s", DOTS); (void) printf(" %s", buf); } else { (void) printf(" %s", fmri); } topo_hdl_strfree(thp, fmri); break; } case DATA_TYPE_INT32_ARRAY: { int32_t *val; (void) nvpair_value_int32_array(pv_nvp, &val, &nelem); (void) printf(" [ "); for (i = 0; i < nelem; i++) (void) printf("%d ", val[i]); (void) printf("]"); break; } case DATA_TYPE_UINT32_ARRAY: { uint32_t *val; (void) nvpair_value_uint32_array(pv_nvp, &val, &nelem); (void) printf(" [ "); for (i = 0; i < nelem; i++) (void) printf("%u ", val[i]); (void) printf("]"); break; } case DATA_TYPE_INT64_ARRAY: { int64_t *val; (void) nvpair_value_int64_array(pv_nvp, &val, &nelem); (void) printf(" [ "); for (i = 0; i < nelem; i++) (void) printf("%lld ", val[i]); (void) printf("]"); break; } case DATA_TYPE_UINT64_ARRAY: { uint64_t *val; (void) nvpair_value_uint64_array(pv_nvp, &val, &nelem); (void) printf(" [ "); for (i = 0; i < nelem; i++) (void) printf("%llu ", val[i]); (void) printf("]"); break; } case DATA_TYPE_STRING_ARRAY: { char **val; (void) nvpair_value_string_array(pv_nvp, &val, &nelem); (void) printf(" [ "); for (i = 0; i < nelem; i++) (void) printf("\"%s\" ", val[i]); (void) printf("]"); break; } default: (void) fprintf(stderr, " unknown data type (%d)", nvpair_type(pv_nvp)); break; } (void) printf("\n"); }
void print_fmri(topo_hdl_t *thp, char *uuid) { int ret, err; nvlist_t *nvl; char buf[32]; time_t tod = time(NULL); if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) { (void) fprintf(stderr, "%s: failed to convert %s to nvlist: " "%s\n", g_pname, g_fmri, topo_strerror(err)); return; } (void) printf("TIME UUID\n"); (void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod)); (void) printf("%-15s %-32s\n", buf, uuid); (void) printf("\n"); (void) printf("%s\n", (char *)g_fmri); if (opt_p && !(pcnt > 0 || opt_V || opt_all)) { char *aname = NULL, *fname = NULL, *lname = NULL; nvlist_t *asru = NULL; nvlist_t *fru = NULL; if (topo_fmri_asru(thp, nvl, &asru, &err) == 0) (void) topo_fmri_nvl2str(thp, asru, &aname, &err); if (topo_fmri_fru(thp, nvl, &fru, &err) == 0) (void) topo_fmri_nvl2str(thp, fru, &fname, &err); (void) topo_fmri_label(thp, nvl, &lname, &err); nvlist_free(fru); nvlist_free(asru); if (aname != NULL) { (void) printf("\tASRU: %s\n", aname); topo_hdl_strfree(thp, aname); } else { (void) printf("\tASRU: -\n"); } if (fname != NULL) { (void) printf("\tFRU: %s\n", fname); topo_hdl_strfree(thp, fname); } else { (void) printf("\tFRU: -\n"); } if (lname != NULL) { (void) printf("\tLabel: %s\n", lname); topo_hdl_strfree(thp, lname); } else { (void) printf("\tLabel: -\n"); } } if (opt_S) { if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) { (void) printf("\tPresent: -\n"); (void) printf("\tUnusable: -\n"); return; } if ((ret = topo_fmri_present(thp, nvl, &err)) < 0) (void) printf("\tPresent: -\n"); else (void) printf("\tPresent: %s\n", ret ? "true" : "false"); if ((ret = topo_fmri_unusable(thp, nvl, &err)) < 0) (void) printf("\tUnusable: -\n"); else (void) printf("\tUnusable: %s\n", ret ? "true" : "false"); nvlist_free(nvl); } if (pargs && pcnt > 0) print_fmri_props(thp, nvl); }
/*ARGSUSED*/ static int do_slot_mapping_cb(topo_hdl_t *thp, tnode_t *node, void *arg) { int err, ret; nvlist_t *rsrc = NULL; const char *match = arg; char *s, *fmri = NULL; char *didstr = NULL, *driver = NULL, *vidstr = NULL; boolean_t printed = B_FALSE; ret = TOPO_WALK_NEXT; if (topo_node_resource(node, &rsrc, &err) < 0) goto next; if (topo_fmri_nvl2str(thp, rsrc, &fmri, &err) < 0) goto next; if ((s = strstr(fmri, match)) == NULL) goto next; if (s[strlen(match)] != '\0') goto next; /* At this point we think we've found a match */ ret = TOPO_WALK_TERMINATE; if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DRIVER, &driver, &err) != 0) driver = NULL; if (topo_prop_get_string(node, TOPO_PGROUP_PCI, TOPO_PCI_VENDID, &vidstr, &err) != 0) goto next; if (topo_prop_get_string(node, TOPO_PGROUP_PCI, TOPO_PCI_DEVID, &didstr, &err) != 0) goto next; if (prt_php != NULL) { long vid, did; vid = strtol(vidstr, NULL, 16); did = strtol(didstr, NULL, 16); if (vid >= 0 && vid <= UINT16_MAX && did >= 0 && did <= UINT16_MAX) { pcidb_device_t *pdev; pdev = pcidb_lookup_device(prt_php, vid, did); if (pdev != NULL) { pcidb_vendor_t *pvend; pvend = pcidb_device_vendor(pdev); (void) printf(gettext(", %s %s (%s)"), pcidb_vendor_name(pvend), pcidb_device_name(pdev), driver != NULL ? driver : "<unknown>"); printed = B_TRUE; } } } if (printed == B_FALSE) { (void) printf(gettext(", pci%s,%s (%s)"), vidstr, didstr, driver != NULL ? driver : "<unknown>"); } next: topo_hdl_strfree(thp, didstr); topo_hdl_strfree(thp, driver); topo_hdl_strfree(thp, vidstr); topo_hdl_strfree(thp, fmri); nvlist_free(rsrc); return (ret); }