/* * Print vendor ID and device ID for PCI devices */ int print_pciid(di_node_t node, di_prom_handle_t ph) { di_node_t pnode = di_parent_node(node); char *s = NULL; int *i, type = di_nodeid(node); if (LOOKUP_PROP(strings, ph, type, DDI_DEV_T_ANY, pnode, "device_type", &s) <= 0) return (0); if (!ISPCI(s)) return (0); /* not a pci device */ (void) printf(" (%s", s); if (LOOKUP_PROP(ints, ph, type, DDI_DEV_T_ANY, node, "vendor-id", &i) > 0) (void) printf("%x", i[0]); if (LOOKUP_PROP(ints, ph, type, DDI_DEV_T_ANY, node, "device-id", &i) > 0) (void) printf(",%x", i[0]); (void) printf(")"); return (1); }
static boolean_t is_root_complex(di_prom_handle_t ph, di_node_t di) { int len; char *type; len = di_prom_prop_lookup_strings(ph, di, "device_type", &type); if ((len == 0) || (type == NULL)) return (B_FALSE); if (strcmp(type, PCIEX) != 0) return (B_FALSE); /* * A root complex node is directly under the root node. So, if * 'di' is not the root node, and its parent has no parent, * then 'di' represents a root complex node. */ return ((di_parent_node(di) != DI_NODE_NIL) && (di_parent_node(di_parent_node(di)) == DI_NODE_NIL)); }
static di_node_t get_parent_bus(di_node_t node, struct search_args *args) { di_node_t pnode; pnode = di_parent_node(node); if (pnode == DI_NODE_NIL) { return (NULL); } if (bus_type(pnode, di_minor_next(pnode, NULL), args->ph) != NULL) { return (pnode); } return (get_parent_bus(pnode, args)); }
/* * Print vendor ID and device ID for PCI devices */ int print_pciid(di_node_t node, di_prom_handle_t ph, pcidb_hdl_t *pci) { pcidb_vendor_t *vend; pcidb_device_t *dev; di_node_t pnode = di_parent_node(node); char *s = NULL; int *i, type = di_nodeid(node); if (LOOKUP_PROP(strings, ph, type, DDI_DEV_T_ANY, pnode, "device_type", &s) <= 0) return (0); if (!ISPCI(s)) return (0); /* not a pci device */ (void) printf(" (%s", s); if (LOOKUP_PROP(ints, ph, type, DDI_DEV_T_ANY, node, "vendor-id", &i) > 0) (void) printf("%x", i[0]); if (pci != NULL) vend = pcidb_lookup_vendor(pci, i[0]); if (LOOKUP_PROP(ints, ph, type, DDI_DEV_T_ANY, node, "device-id", &i) > 0) (void) printf(",%x", i[0]); if (pci != NULL) dev = pcidb_lookup_device_by_vendor(vend, i[0]); (void) printf(") ["); if (vend != NULL) (void) printf("%s ", pcidb_vendor_name(vend)); else (void) printf("unknown vendor, "); if (dev != NULL) (void) printf("%s", pcidb_device_name(dev)); else (void) printf("unknown device"); (void) printf("]"); return (1); }
void devinfo_add_subtree(HalDevice *parent, di_node_t node, gboolean is_root) { HalDevice *d; di_node_t root_node, child_node; HAL_INFO (("add_subtree: %s", di_node_name (node))); root_node = node; do { d = devinfo_add_node (parent, node); if ((d != NULL) && (child_node = di_child_node (node)) != DI_NODE_NIL) { devinfo_add_subtree (d, child_node, FALSE); } node = di_sibling_node (node); } while ((node != DI_NODE_NIL) && (!is_root || di_parent_node (node) == root_node)); }
static struct priv_data * match_priv_data(di_node_t node) { int i; size_t len; char *drv_name, *tmp; di_node_t parent; struct priv_data *pdp; if ((parent = di_parent_node(node)) == DI_NODE_NIL) return (NULL); if ((drv_name = di_driver_name(parent)) == NULL) return (NULL); pdp = prt_priv_data; len = strlen(drv_name); for (i = 0; i < nprt_priv_data; ++i, ++pdp) { tmp = pdp->drv_name; while (tmp && (*tmp != '\0')) { if (strncmp(tmp, drv_name, len) == 0) { #ifdef DEBUG dprintf("matched parent private data" " at Node <%s> parent driver <%s>\n", di_node_name(node), drv_name); #endif /* DEBUG */ return (pdp); } /* * skip a white space */ if (tmp = strchr(tmp, ' ')) tmp++; } } return (NULL); }
static int sunos_add_devices(di_devlink_t link, void *arg) { struct devlink_cbarg *largs = (struct devlink_cbarg *)arg; struct node_args *nargs; di_node_t myself, pnode; uint64_t session_id = 0; uint16_t bdf = 0; struct libusb_device *dev; sunos_dev_priv_t *devpriv; const char *path, *newpath; int n, i; int *addr_prop; uint8_t bus_number = 0; nargs = (struct node_args *)largs->nargs; myself = largs->myself; if (nargs->last_ugenpath) { /* the same node's links */ return (DI_WALK_CONTINUE); } /* * Construct session ID. * session ID = ...parent hub addr|hub addr|dev addr. */ pnode = myself; i = 0; while (pnode != DI_NODE_NIL) { if (di_prop_exists(DDI_DEV_T_ANY, pnode, "root-hub") == 1) { /* walk to root */ uint32_t *regbuf = NULL; uint32_t reg; n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode, "reg", (int **)®buf); reg = regbuf[0]; bdf = (PCI_REG_BUS_G(reg) << 8) | (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg); session_id |= (bdf << i * 8); /* same as 'unit-address' property */ bus_number = (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg); usbi_dbg("device bus address=%s:%x", di_bus_addr(pnode), bus_number); break; } /* usb_addr */ n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode, "assigned-address", &addr_prop); if ((n != 1) || (addr_prop[0] == 0)) { usbi_dbg("cannot get valid usb_addr"); return (DI_WALK_CONTINUE); } session_id |= ((addr_prop[0] & 0xff) << i * 8); if (++i > 7) break; pnode = di_parent_node(pnode); } path = di_devlink_path(link); dev = usbi_get_device_by_session_id(nargs->ctx, session_id); if (dev == NULL) { dev = usbi_alloc_device(nargs->ctx, session_id); if (dev == NULL) { usbi_dbg("can't alloc device"); return (DI_WALK_TERMINATE); } devpriv = (sunos_dev_priv_t *)dev->os_priv; if ((newpath = strrchr(path, '/')) == NULL) { libusb_unref_device(dev); return (DI_WALK_TERMINATE); } devpriv->ugenpath = strndup(path, strlen(path) - strlen(newpath)); dev->bus_number = bus_number; if (sunos_fill_in_dev_info(myself, dev) != LIBUSB_SUCCESS) { libusb_unref_device(dev); return (DI_WALK_TERMINATE); } if (usbi_sanitize_device(dev) < 0) { libusb_unref_device(dev); usbi_dbg("sanatize failed: "); return (DI_WALK_TERMINATE); } } else { usbi_dbg("Dev %s exists", path); } devpriv = (sunos_dev_priv_t *)dev->os_priv; if (nargs->last_ugenpath == NULL) { /* first device */ nargs->last_ugenpath = devpriv->ugenpath; if (discovered_devs_append(*(nargs->discdevs), dev) == NULL) { usbi_dbg("cannot append device"); } /* * we alloc and hence ref this dev. We don't need to ref it * hereafter. Front end or app should take care of their ref. */ libusb_unref_device(dev); } usbi_dbg("Device %s %s id=0x%llx, devcount:%d, bdf=%x", devpriv->ugenpath, path, (uint64_t)session_id, (*nargs->discdevs)->len, bdf); return (DI_WALK_CONTINUE); }
/* * Operates on a single di_node_t, collecting all the device properties * that we need. devnvl is allocated by the caller, and we add our nvpairs * to it if they don't already exist. * * We are _only_ interested in devices which have a devid. We pull in * devices even when they're excluded via stmsboot -D (driver), because * we don't want to miss out on any devid data that might be handy later. */ static int popcheck_devnvl(di_node_t thisnode, nvlist_t *devnvl, char *strdevid) { char *path = NULL; char *curpath = NULL; char *devfspath = NULL; char *prop = NULL; int scsivhciparent = 0; int rv = 0; boolean_t mpxenp = B_FALSE; errno = 0; devfspath = di_devfs_path(thisnode); if (devfspath == NULL) { logmsg(MSG_ERROR, gettext("Unable to determine devfs path for node: %s\n"), strerror(errno)); return (-1); } /* Add a convenient devfspath to devid inverse map */ if (nvlist_add_string(mapnvl, devfspath, strdevid) != 0) { logmsg(MSG_ERROR, gettext("Unable to add device path %s with devid " "%s to mapnvl\n"), devfspath, strdevid); return (-1); } if (di_prop_lookup_strings(DDI_DEV_T_ANY, di_parent_node(thisnode), "mpxio-disable", &prop) >= 0) { if (strncmp(prop, "yes", 3) == 0) { if (!mpxprop) mpxprop++; } } if (strncmp(di_driver_name(di_parent_node(thisnode)), "scsi_vhci", 9) == 0) { scsivhciparent = 1; if (!mpxenabled) mpxenabled++; rv = nvlist_lookup_boolean_value(devnvl, NVL_MPXEN, &mpxenp); if (rv || (mpxenp == B_FALSE)) { rv = nvlist_add_boolean_value(devnvl, NVL_MPXEN, B_TRUE); if (rv) { logmsg(MSG_ERROR, gettext("Unable to add property %s " "(set to B_TRUE) for device %s: " "%s (%d)\n"), NVL_MPXEN, devfspath, strerror(rv), rv); return (-1); } logmsg(MSG_INFO, "NVL_MPXEN :: (B_FALSE->B_TRUE)\n"); } } else { /* turn _off_ the flag if it was enabled */ rv = nvlist_add_boolean_value(devnvl, NVL_MPXEN, B_FALSE); if (rv) { logmsg(MSG_ERROR, gettext("Unable to add property %s " "(set to B_FALSE) for device %s: %s (%d)\n"), NVL_MPXEN, devfspath, strerror(rv), rv); return (-1); } logmsg(MSG_INFO, "NVL_MPXEN :: (B_TRUE-> B_FALSE)\n"); } rv = nvlist_add_string(devnvl, NVL_PHYSPATH, devfspath); if (rv) { logmsg(MSG_ERROR, gettext("Unable to add physical device path (%s) " "property to nvl\n")); return (-1); } if ((curpath = calloc(1, MAXPATHLEN)) == NULL) { logmsg(MSG_ERROR, gettext("Unable to allocate space for current path\n")); return (-1); } curpath = find_link(thisnode); if (curpath == NULL) { if (readonlyroot) { return (0); } logmsg(MSG_ERROR, gettext("Unable to determine device path for node %s\n"), devfspath); return (-1); } rv = nvlist_lookup_string(devnvl, NVL_MPXPATH, &path); if (scsivhciparent) { (void) nvlist_add_string(devnvl, NVL_MPXPATH, curpath); } else { (void) nvlist_add_string(devnvl, NVL_PATH, curpath); path = curpath; } /* * This next block provides the path to devid inverse mapping * that other functions require */ if (path != NULL) { if (nvlist_add_string(mapnvl, path, strdevid) != 0) { logmsg(MSG_ERROR, gettext("Unable to add device %s with devid " "%s to mapnvl\n"), path, strdevid); return (-1); } logmsg(MSG_INFO, "popcheck_devnvl: added path %s :: %s\n", path, strdevid); } if (nvlist_add_string(mapnvl, curpath, strdevid) != 0) { logmsg(MSG_ERROR, gettext("Unable to add device %s with devid " "%s to mapnvl: %s\n"), curpath, strdevid, strerror(errno)); return (-1); } logmsg(MSG_INFO, "popcheck_devnvl: added curpath %s :: %s\n", curpath, strdevid); return (0); }
static int add_disk2controller(disk_t *diskp, struct search_args *args) { di_node_t pnode; controller_t *cp; di_minor_t minor; di_node_t node; int i; node = args->node; pnode = di_parent_node(node); if (pnode == DI_NODE_NIL) { return (0); } minor = di_minor_next(pnode, NULL); if (minor == NULL) { return (0); } if ((cp = add_controller(args, pnode, minor)) == NULL) { return (ENOMEM); } /* check if the disk <-> ctrl assoc is already there */ for (i = 0; diskp->controllers[i]; i++) { if (cp == diskp->controllers[i]) { return (0); } } /* this is a new controller for this disk */ /* add the disk to the controller */ if (add_ptr2array(diskp, (void ***)&cp->disks) != 0) { return (ENOMEM); } /* add the controller to the disk */ if (add_ptr2array(cp, (void ***)&diskp->controllers) != 0) { return (ENOMEM); } /* * Set up paths for mpxio controlled drives. */ if (libdiskmgt_str_eq(di_node_name(pnode), "scsi_vhci")) { /* note: mpxio di_path stuff is all consolidation private */ di_path_t pi = DI_PATH_NIL; while ( (pi = di_path_client_next_path(node, pi)) != DI_PATH_NIL) { int cnt; uchar_t *bytes; char str[MAXPATHLEN]; char *wwn; di_node_t phci_node = di_path_phci_node(pi); /* get the node wwn */ cnt = di_path_prop_lookup_bytes(pi, WWN_PROP, &bytes); wwn = NULL; if (cnt > 0) { int i; str[0] = 0; for (i = 0; i < cnt; i++) { /* * A byte is only 2 hex chars + null. */ char bstr[8]; (void) snprintf(bstr, sizeof (bstr), "%.2x", bytes[i]); (void) strlcat(str, bstr, sizeof (str)); } wwn = str; } if (new_path(cp, diskp, phci_node, di_path_state(pi), wwn) == NULL) { return (ENOMEM); } } } return (0); }
static controller_t * add_controller(struct search_args *args, di_node_t node, di_minor_t minor) { char *devpath; controller_t *cp; char kstat_name[MAXPATHLEN]; char *c_type = DM_CTYPE_UNKNOWN; devpath = di_devfs_path(node); if ((cp = find_controller(args, devpath)) != NULL) { di_devfs_path_free((void *) devpath); return (cp); } /* Special handling for fp attachment node. */ if (strcmp(di_node_name(node), "fp") == 0) { di_node_t pnode; pnode = di_parent_node(node); if (pnode != DI_NODE_NIL) { di_devfs_path_free((void *) devpath); devpath = di_devfs_path(pnode); if ((cp = find_controller(args, devpath)) != NULL) { di_devfs_path_free((void *) devpath); return (cp); } /* not in the list, create it */ node = pnode; c_type = DM_CTYPE_FIBRE; } } if (dm_debug) { (void) fprintf(stderr, "INFO: add_controller %s\n", devpath); } cp = (controller_t *)calloc(1, sizeof (controller_t)); if (cp == NULL) { return (NULL); } cp->name = strdup(devpath); di_devfs_path_free((void *) devpath); if (cp->name == NULL) { cache_free_controller(cp); return (NULL); } if (strcmp(c_type, DM_CTYPE_UNKNOWN) == 0) { c_type = ctype(node, minor); } cp->ctype = c_type; (void) snprintf(kstat_name, sizeof (kstat_name), "%s%d", di_node_name(node), di_instance(node)); if ((cp->kstat_name = strdup(kstat_name)) == NULL) { cache_free_controller(cp); return (NULL); } if (libdiskmgt_str_eq(cp->ctype, "scsi")) { cp->scsi_options = get_prop(SCSI_OPTIONS_PROP, node); } if (libdiskmgt_str_eq(di_node_name(node), "scsi_vhci")) { cp->multiplex = 1; } else { cp->multiplex = 0; } cp->freq = get_prom_int("clock-frequency", node, args->ph); cp->disks = (disk_t **)calloc(1, sizeof (disk_t *)); if (cp->disks == NULL) { cache_free_controller(cp); return (NULL); } cp->disks[0] = NULL; cp->next = args->controller_listp; args->controller_listp = cp; cp->bus = add_bus(args, di_parent_node(node), di_minor_next(di_parent_node(node), NULL), cp); return (cp); }
static bus_t * add_bus(struct search_args *args, di_node_t node, di_minor_t minor, controller_t *cp) { char *btype; char *devpath; bus_t *bp; char kstat_name[MAXPATHLEN]; di_node_t pnode; if (node == DI_NODE_NIL) { return (NULL); } if ((btype = bus_type(node, minor, args->ph)) == NULL) { return (add_bus(args, di_parent_node(node), di_minor_next(di_parent_node(node), NULL), cp)); } devpath = di_devfs_path(node); if ((bp = find_bus(args, devpath)) != NULL) { di_devfs_path_free((void *) devpath); if (cp != NULL) { if (add_ptr2array(cp, (void ***)&bp->controllers) != 0) { args->dev_walk_status = ENOMEM; return (NULL); } } return (bp); } /* Special handling for root node. */ if (strcmp(devpath, "/") == 0) { di_devfs_path_free((void *) devpath); return (NULL); } if (dm_debug) { (void) fprintf(stderr, "INFO: add_bus %s\n", devpath); } bp = (bus_t *)calloc(1, sizeof (bus_t)); if (bp == NULL) { return (NULL); } bp->name = strdup(devpath); di_devfs_path_free((void *) devpath); if (bp->name == NULL) { args->dev_walk_status = ENOMEM; cache_free_bus(bp); return (NULL); } bp->btype = strdup(btype); if (bp->btype == NULL) { args->dev_walk_status = ENOMEM; cache_free_bus(bp); return (NULL); } (void) snprintf(kstat_name, sizeof (kstat_name), "%s%d", di_node_name(node), di_instance(node)); if ((bp->kstat_name = strdup(kstat_name)) == NULL) { args->dev_walk_status = ENOMEM; cache_free_bus(bp); return (NULL); } /* if parent node is a bus, get its name */ if ((pnode = get_parent_bus(node, args)) != NULL) { devpath = di_devfs_path(pnode); bp->pname = strdup(devpath); di_devfs_path_free((void *) devpath); if (bp->pname == NULL) { args->dev_walk_status = ENOMEM; cache_free_bus(bp); return (NULL); } } else { bp->pname = NULL; } bp->freq = get_prom_int("clock-frequency", node, args->ph); bp->controllers = (controller_t **)calloc(1, sizeof (controller_t *)); if (bp->controllers == NULL) { args->dev_walk_status = ENOMEM; cache_free_bus(bp); return (NULL); } bp->controllers[0] = NULL; if (cp != NULL) { if (add_ptr2array(cp, (void ***)&bp->controllers) != 0) { args->dev_walk_status = ENOMEM; return (NULL); } } bp->next = args->bus_listp; args->bus_listp = bp; return (bp); }
static path_t * new_path(controller_t *cp, disk_t *dp, di_node_t node, di_path_state_t st, char *wwn) { char *devpath; path_t *pp; di_minor_t minor; /* Special handling for fp attachment node. */ if (strcmp(di_node_name(node), "fp") == 0) { di_node_t pnode; pnode = di_parent_node(node); if (pnode != DI_NODE_NIL) { node = pnode; } } devpath = di_devfs_path(node); /* check if the path is already there */ pp = NULL; if (cp->paths != NULL) { int i; for (i = 0; cp->paths[i]; i++) { if (libdiskmgt_str_eq(devpath, cp->paths[i]->name)) { pp = cp->paths[i]; break; } } } if (pp != NULL) { /* the path exists, add this disk to it */ di_devfs_path_free((void *) devpath); if (!add_disk2path(dp, pp, st, wwn)) { return (NULL); } return (pp); } /* create a new path */ pp = calloc(1, sizeof (path_t)); if (pp == NULL) { di_devfs_path_free((void *) devpath); return (NULL); } pp->name = strdup(devpath); di_devfs_path_free((void *) devpath); if (pp->name == NULL) { cache_free_path(pp); return (NULL); } /* add the disk to the path */ if (!add_disk2path(dp, pp, st, wwn)) { return (NULL); } /* add the path to the controller */ if (add_ptr2array(pp, (void ***)&cp->paths) != 0) { cache_free_path(pp); return (NULL); } /* add the controller to the path */ pp->controller = cp; minor = di_minor_next(node, NULL); if (minor != NULL) { pp->ctype = ctype(node, minor); } else { pp->ctype = DM_CTYPE_UNKNOWN; } return (pp); }
static int new_alias(disk_t *diskp, char *kernel_name, char *devlink_path, struct search_args *args) { alias_t *aliasp; char alias[MAXPATHLEN]; di_node_t pnode; aliasp = malloc(sizeof (alias_t)); if (aliasp == NULL) { return (ENOMEM); } aliasp->alias = NULL; aliasp->kstat_name = NULL; aliasp->wwn = NULL; aliasp->devpaths = NULL; aliasp->orig_paths = NULL; get_disk_name_from_path(devlink_path, alias, sizeof (alias)); aliasp->alias = strdup(alias); if (aliasp->alias == NULL) { cache_free_alias(aliasp); return (ENOMEM); } if (kernel_name != NULL) { aliasp->kstat_name = strdup(kernel_name); if (aliasp->kstat_name == NULL) { cache_free_alias(aliasp); return (ENOMEM); } } else { aliasp->kstat_name = NULL; } aliasp->lun = get_prop(DM_LUN, args->node); aliasp->target = get_prop(DM_TARGET, args->node); aliasp->wwn = get_byte_prop(WWN_PROP, args->node); pnode = di_parent_node(args->node); if (pnode != DI_NODE_NIL) { char prop_name[MAXPROPLEN]; (void) snprintf(prop_name, sizeof (prop_name), "target%d-sync-speed", aliasp->target); diskp->sync_speed = get_prop(prop_name, pnode); (void) snprintf(prop_name, sizeof (prop_name), "target%d-wide", aliasp->target); diskp->wide = get_prop(prop_name, pnode); } if (new_devpath(aliasp, devlink_path) != 0) { cache_free_alias(aliasp); return (ENOMEM); } aliasp->next = diskp->aliases; diskp->aliases = aliasp; return (0); }