static int sunos_walk_minor_node_link(di_node_t node, void *args) { di_minor_t minor = DI_MINOR_NIL; char *minor_path; struct devlink_cbarg arg; struct node_args *nargs = (struct node_args *)args; di_devlink_handle_t devlink_hdl = nargs->dlink_hdl; /* walk each minor to find ugen devices */ while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { minor_path = di_devfs_minor_path(minor); arg.nargs = args; arg.myself = node; arg.minor = minor; (void) di_devlink_walk(devlink_hdl, "^usb/[0-9a-f]+[.][0-9a-f]+", minor_path, DI_PRIMARY_LINK, (void *)&arg, sunos_add_devices); di_devfs_path_free(minor_path); } /* switch to a different node */ nargs->last_ugenpath = NULL; return (DI_WALK_CONTINUE); }
char * get_devlink(di_devlink_handle_t devlink_hdl, char *re, char *path) { char *devlink_path = NULL; (void) di_devlink_walk(devlink_hdl, re, path, DI_PRIMARY_LINK, &devlink_path, walk_devlinks); return (devlink_path); }
char *getDeviceFileName(MP_UINT64 objectSequenceNumber) { char *deviceFileName = NULL; di_node_t root_node = DI_NODE_NIL; di_node_t cur_node = DI_NODE_NIL; int instNum; int majorNum; MP_UINT64 osn; char *pathName = NULL; char *minorName = "c,raw"; char *devLink = NULL; char fullName[512]; walk_devlink_t warg; di_devlink_handle_t dlHandle = NULL; int diStatus = 0; log(LOG_INFO, "getDeviceFileName()", " - enter"); log(LOG_INFO, "getDeviceFileName()", " - objectSequenceNumber: %llx", objectSequenceNumber); root_node = di_init("/", DINFOCACHE); if (DI_NODE_NIL == root_node) { log(LOG_INFO, "MP_GetMultipathLusPlugin()", " - $ERROR, di_init() failed"); return (NULL); } cur_node = di_drv_first_node("scsi_vhci", root_node); if (DI_NODE_NIL == cur_node) { log(LOG_INFO, "getDeviceFileName()", " - $ERROR, di_drv_first_node() failed"); di_fini(root_node); return (NULL); } cur_node = di_child_node(cur_node); while (DI_NODE_NIL != cur_node) { instNum = di_instance(cur_node); majorNum = di_driver_major(cur_node); osn = 0; osn = MP_STORE_INST_TO_ID(instNum, osn); osn = MP_STORE_MAJOR_TO_ID(majorNum, osn); if (osn == objectSequenceNumber) { log(LOG_INFO, "getDeviceFileName()", " - found node."); break; } cur_node = di_sibling_node(cur_node); } if (DI_NODE_NIL != cur_node) { dlHandle = di_devlink_init(NULL, 0); if (NULL == dlHandle) { log(LOG_INFO, "getDeviceFileName()", " - $ERROR, di_devlink_init() failed."); di_fini(root_node); return (NULL); } pathName = di_devfs_path(cur_node); (void) snprintf(fullName, 511, "%s:%s", pathName, minorName); log(LOG_INFO, "getDeviceFileName()", " - fullName: {%s]", fullName); (void) memset(&warg, 0, sizeof (walk_devlink_t)); devLink = NULL; warg.linkpp = &devLink; diStatus = di_devlink_walk(dlHandle, NULL, fullName, DI_PRIMARY_LINK, (void *)&warg, get_devlink); if (diStatus != 0) { log(LOG_INFO, "getDeviceFileName()", "diStatus: %d", diStatus); if (diStatus < 0) { diStatus = errno; } log(LOG_INFO, "getDeviceFileName()", "diStatus: %d", diStatus); log(LOG_INFO, "getDeviceFileName()", "strerror(diStatus): %s", strerror(diStatus)); } if (NULL != devLink) { deviceFileName = (char *)calloc(1, strlen(devLink) + 1); (void) strncpy(deviceFileName, devLink, strlen(devLink)); } else { log(LOG_INFO, "getDeviceFileName()", " - $ERROR, devLink is NULL."); deviceFileName = (char *)calloc(1, 256); (void) strncpy(deviceFileName, pathName, 255); } di_devfs_path_free(pathName); (void) di_devlink_fini(&dlHandle); } di_fini(root_node); free(devLink); log(LOG_INFO, "getDeviceFileName()", " - exit"); return (deviceFileName); }
static int dev_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp) { topo_mod_t *mod = cbp->dcb_mod; dev_di_node_t *dnode; di_path_t pnode; char *path; int mlen; char *minorpath; char *extn = ":a"; char *s; int64_t *nblocksp; uint64_t nblocks; int *dblksizep; uint_t dblksize; char lentry[MAXPATHLEN]; int pathcount; int *inq_dtype, itype; int i; if (devid) { /* * Check for list duplicate using devid search. * Note if there is no devid, then we can end up with duplicates * in the list, but this doesn't do any harm. */ for (dnode = topo_list_next(cbp->dcb_list); dnode != NULL; dnode = topo_list_next(dnode)) { if (dnode->ddn_devid && devid_str_compare(dnode->ddn_devid, devid) == 0) { topo_mod_dprintf(mod, "dev_di_node_add: " "already there %s\n", devid); return (0); } } } if ((dnode = topo_mod_zalloc(mod, sizeof (dev_di_node_t))) == NULL) return (-1); if (devid) { /* Establish the devid. */ dnode->ddn_devid = topo_mod_strdup(mod, devid); if (dnode->ddn_devid == NULL) goto error; } /* Establish the devinfo dpath */ if ((path = di_devfs_path(node)) == NULL) { (void) topo_mod_seterrno(mod, errno); goto error; } dnode->ddn_dpath = topo_mod_strdup(mod, path); di_devfs_path_free(path); if (dnode->ddn_dpath == NULL) goto error; /* * Establish the physical ppath and target ports. If the device is * non-mpxio then dpath and ppath are the same, and the target port is a * property of the device node. * * If dpath is a client node under scsi_vhci, then iterate over all * paths and get their physical paths and target port properrties. * di_path_client_next_path call below will * return non-NULL, and ppath is set to the physical path to the first * pathinfo node. * * NOTE: It is possible to get a generic.vs.non-generic path * for di_devfs_path.vs.di_path_devfs_path like: * xml: /pci@7b,0/pci1022,7458@11/pci1000,3060@2/sd@2,0 * pnode: /pci@7b,0/pci1022,7458@11/pci1000,3060@2/disk@2,0 * To resolve this issue disk_declare_path() needs to use the * special di_devfs_path_match() interface. */ pathcount = 0; pnode = NULL; while ((pnode = di_path_client_next_path(node, pnode)) != NULL) { pathcount++; } if (pathcount == 0) { if ((dnode->ddn_ppath = topo_mod_zalloc(mod, sizeof (char *))) == NULL) goto error; dnode->ddn_ppath_count = 1; if ((dnode->ddn_ppath[0] = topo_mod_strdup(mod, dnode->ddn_dpath)) == NULL) goto error; if ((dnode->ddn_target_port = topo_mod_zalloc(mod, sizeof (char *))) == NULL) goto error; if ((dnode->ddn_attached_port = topo_mod_zalloc(mod, sizeof (char *))) == NULL) goto error; if ((dnode->ddn_bridge_port = topo_mod_zalloc(mod, sizeof (char *))) == NULL) goto error; /* There should be only one target port for a devinfo node. */ if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node, SCSI_ADDR_PROP_TARGET_PORT, &s)) == 1) { if ((dnode->ddn_target_port[0] = topo_mod_strdup(mod, scsi_wwnstr_skip_ua_prefix(s))) == NULL) goto error; } if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node, SCSI_ADDR_PROP_ATTACHED_PORT, &s)) == 1) { /* There should be one attached port if any. */ if ((dnode->ddn_attached_port[0] = topo_mod_strdup(mod, scsi_wwnstr_skip_ua_prefix(s))) == NULL) goto error; } if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node, SCSI_ADDR_PROP_BRIDGE_PORT, &s)) == 1) { /* There should be one bridge port if any. */ if ((dnode->ddn_bridge_port[0] = topo_mod_strdup(mod, scsi_wwnstr_skip_ua_prefix(s))) == NULL) goto error; } } else { /* processing a scsi_vhci device. */ if ((dnode->ddn_ppath = topo_mod_zalloc(mod, pathcount * sizeof (char *))) == NULL) goto error; dnode->ddn_ppath_count = pathcount; if ((dnode->ddn_target_port = topo_mod_zalloc(mod, pathcount * sizeof (char *))) == NULL) goto error; if ((dnode->ddn_attached_port = topo_mod_zalloc(mod, pathcount * sizeof (char *))) == NULL) goto error; if ((dnode->ddn_bridge_port = topo_mod_zalloc(mod, pathcount * sizeof (char *))) == NULL) goto error; pnode = NULL; pathcount = 0; while ((pnode = di_path_client_next_path(node, pnode)) != NULL) { if ((path = di_path_devfs_path(pnode)) == NULL) { (void) topo_mod_seterrno(mod, errno); goto error; } dnode->ddn_ppath[pathcount] = topo_mod_strdup(mod, path); di_devfs_path_free(path); if (dnode->ddn_ppath[pathcount] == NULL) goto error; if ((di_path_prop_lookup_strings(pnode, SCSI_ADDR_PROP_TARGET_PORT, &s)) == 1) { if ((dnode->ddn_target_port[pathcount] = topo_mod_strdup(mod, scsi_wwnstr_skip_ua_prefix(s))) == NULL) goto error; } if ((di_path_prop_lookup_strings(pnode, SCSI_ADDR_PROP_ATTACHED_PORT, &s)) == 1) { if ((dnode->ddn_attached_port[pathcount] = topo_mod_strdup(mod, scsi_wwnstr_skip_ua_prefix(s))) == NULL) goto error; } if ((di_path_prop_lookup_strings(pnode, SCSI_ADDR_PROP_BRIDGE_PORT, &s)) == 1) { if ((dnode->ddn_bridge_port[pathcount] = topo_mod_strdup(mod, scsi_wwnstr_skip_ua_prefix(s))) == NULL) goto error; } pathcount++; } } /* * Find the public /dev name for a disk by adding a minor name and using * di_devlink interface for reverse translation (use devinfo path). */ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type", &inq_dtype) > 0) { dnode->ddn_dtype = *inq_dtype; itype = (*inq_dtype) & DTYPE_MASK; if (itype == DTYPE_DIRECT) { mlen = strlen(dnode->ddn_dpath) + strlen(extn) + 1; if ((minorpath = topo_mod_alloc(mod, mlen)) == NULL) goto error; (void) snprintf(minorpath, mlen, "%s%s", dnode->ddn_dpath, extn); cbp->dcb_dnode = dnode; (void) di_devlink_walk(cbp->dcb_devhdl, "^dsk/", minorpath, DI_PRIMARY_LINK, cbp, disk_devlink_callback); topo_mod_free(mod, minorpath, mlen); if (dnode->ddn_lpath == NULL) { topo_mod_dprintf(mod, "dev_di_node_add: " "failed to determine logical path"); } } } else { dnode->ddn_dtype = DTYPE_UNKNOWN; } /* cache various bits of optional information about the device. */ if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, INQUIRY_VENDOR_ID, &s) > 0) { if ((dnode->ddn_mfg = disk_trim_whitespace(mod, s)) == NULL) goto error; } if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, INQUIRY_PRODUCT_ID, &s) > 0) { if ((dnode->ddn_model = disk_trim_whitespace(mod, s)) == NULL) goto error; } if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, INQUIRY_REVISION_ID, &s) > 0) { if ((dnode->ddn_firm = disk_trim_whitespace(mod, s)) == NULL) goto error; } if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, INQUIRY_SERIAL_NO, &s) > 0) { if ((dnode->ddn_serial = disk_trim_whitespace(mod, s)) == NULL) goto error; } if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, "device-nblocks", &nblocksp) > 0) { nblocks = (uint64_t)*nblocksp; /* * To save kernel memory, the driver may not define * "device-dblksize" when its value is default DEV_BSIZE. */ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-dblksize", &dblksizep) > 0) dblksize = (uint_t)*dblksizep; else dblksize = DEV_BSIZE; /* default value */ (void) snprintf(lentry, sizeof (lentry), "%" PRIu64, nblocks * dblksize); if ((dnode->ddn_cap = topo_mod_strdup(mod, lentry)) == NULL) goto error; } topo_mod_dprintf(mod, "dev_di_node_add: " "adding %s\n", devid ? dnode->ddn_devid : "NULL devid"); topo_mod_dprintf(mod, " " " %s\n", dnode->ddn_dpath); for (i = 0; i < dnode->ddn_ppath_count; i++) { topo_mod_dprintf(mod, " " " %s\n", dnode->ddn_ppath[i]); } topo_list_append(cbp->dcb_list, dnode); return (0); error: dev_di_node_free(mod, dnode); return (-1); }
static char * find_link(di_node_t cnode) { di_minor_t devminor = DI_MINOR_NIL; di_devlink_handle_t hdl; char *devfspath = NULL; char *minorpath = NULL; char *linkname = NULL; char *cbresult = NULL; devfspath = di_devfs_path(cnode); if (cnode == DI_NODE_NIL) { logmsg(MSG_ERROR, gettext("find_ctrl must be called with non-null " "di_node_t\n")); return (NULL); } logmsg(MSG_INFO, "find_link: devfspath %s\n", devfspath); if (((cbresult = calloc(1, MAXPATHLEN)) == NULL) || ((minorpath = calloc(1, MAXPATHLEN)) == NULL) || ((linkname = calloc(1, MAXPATHLEN)) == NULL)) { logmsg(MSG_ERROR, "unable to allocate space for dev link\n"); return (NULL); } devminor = di_minor_next(cnode, devminor); hdl = di_devlink_init(di_devfs_minor_path(devminor), DI_MAKE_LINK); if (hdl == NULL) { logmsg((readonlyroot ? MSG_INFO : MSG_ERROR), gettext("unable to take devlink snapshot: %s\n"), strerror(errno)); return (NULL); } linkname = "^dsk/"; (void) snprintf(minorpath, MAXPATHLEN, "%s:c", devfspath); errno = 0; if (di_devlink_walk(hdl, linkname, minorpath, DI_PRIMARY_LINK, (void *)cbresult, link_cb) < 0) { logmsg(MSG_ERROR, gettext("Unable to walk devlink snapshot for %s: %s\n"), minorpath, strerror(errno)); return (NULL); } if (di_devlink_fini(&hdl) < 0) { logmsg(MSG_ERROR, gettext("Unable to close devlink snapshot: %s\n"), strerror(errno)); } if (strstr(cbresult, "dsk/") == NULL) return (devfspath); bzero(minorpath, MAXPATHLEN); /* strip off the trailing "s2" */ bcopy(cbresult, minorpath, strlen(cbresult) - 1); /* Now strip off the /dev/dsk/ prefix for output flexibility */ linkname = strrchr(minorpath, '/'); return (++linkname); }
static int add_devs(di_node_t node, di_minor_t minor, void *arg) { struct search_args *args; int result = DI_WALK_CONTINUE; args = (struct search_args *)arg; if (dm_debug > 1) { /* This is all just debugging code */ char *devpath; char dev_name[MAXPATHLEN]; devpath = di_devfs_path(node); (void) snprintf(dev_name, sizeof (dev_name), "%s:%s", devpath, di_minor_name(minor)); di_devfs_path_free((void *) devpath); (void) fprintf(stderr, "INFO: dev: %s, node: %s%d, minor: 0x%x, type: %s\n", dev_name, di_node_name(node), di_instance(node), di_minor_spectype(minor), (di_minor_nodetype(minor) != NULL ? di_minor_nodetype(minor) : "NULL")); } if (bus_type(node, minor, args->ph) != NULL) { if (add_bus(args, node, minor, NULL) == NULL) { args->dev_walk_status = ENOMEM; result = DI_WALK_TERMINATE; } } else if (is_ctrl(node, minor)) { if (add_controller(args, node, minor) == NULL) { args->dev_walk_status = ENOMEM; result = DI_WALK_TERMINATE; } } else if (di_minor_spectype(minor) == S_IFCHR && (is_drive(minor) || is_zvol(node, minor))) { char *devidstr; char kernel_name[MAXPATHLEN]; disk_t *diskp; (void) snprintf(kernel_name, sizeof (kernel_name), "%s%d", di_node_name(node), di_instance(node)); devidstr = get_str_prop(DEVICE_ID_PROP, node); args->node = node; args->minor = minor; /* * Check if we already got this disk and * this is another slice. */ if (!have_disk(args, devidstr, kernel_name, &diskp)) { args->dev_walk_status = 0; /* * This is a newly found disk, create the * disk structure. */ diskp = create_disk(devidstr, kernel_name, args); if (diskp == NULL) { args->dev_walk_status = ENOMEM; } if (diskp->drv_type != DM_DT_FLOPPY) { /* add the controller relationship */ if (args->dev_walk_status == 0) { if (add_disk2controller(diskp, args) != 0) { args->dev_walk_status = ENOMEM; } } } } if (is_zvol(node, minor)) { char zvdsk[MAXNAMELEN]; char *str; alias_t *ap; if (di_prop_lookup_strings(di_minor_devt(minor), node, "name", &str) == -1) return (DI_WALK_CONTINUE); (void) snprintf(zvdsk, MAXNAMELEN, "/dev/zvol/rdsk/%s", str); if ((ap = find_alias(diskp, kernel_name)) == NULL) { if (new_alias(diskp, kernel_name, zvdsk, args) != 0) { args->dev_walk_status = ENOMEM; } } else { /* * It is possible that we have already added * this devpath. * Do not add it again. new_devpath will * return a 0 if found, and not add the path. */ if (new_devpath(ap, zvdsk) != 0) { args->dev_walk_status = ENOMEM; } } } /* Add the devpaths for the drive. */ if (args->dev_walk_status == 0) { char *devpath; char slice_path[MAXPATHLEN]; char *pattern; /* * We will come through here once for each of * the raw slice device names. */ devpath = di_devfs_path(node); (void) snprintf(slice_path, sizeof (slice_path), "%s:%s", devpath, di_minor_name(minor)); di_devfs_path_free((void *) devpath); if (libdiskmgt_str_eq(di_minor_nodetype(minor), DDI_NT_FD)) { pattern = DEVLINK_FLOPPY_REGEX; } else { pattern = DEVLINK_REGEX; } /* Walk the /dev tree to get the devlinks. */ (void) di_devlink_walk(args->handle, pattern, slice_path, DI_PRIMARY_LINK, arg, add_devpath); } if (args->dev_walk_status != 0) { result = DI_WALK_TERMINATE; } } return (result); }
/* * Convert the specified devid/minor_name into a devid_nmlist_t array * with names that resolve into /devices or /dev depending on search_path. * * The man page indicates that: * * This function traverses the file tree, starting at search_path. * * This is not true, we reverse engineer the paths relative to * the specified search path to avoid attaching all devices. */ int devid_deviceid_to_nmlist( char *search_path, ddi_devid_t devid, char *minor_name, devid_nmlist_t **retlist) { char *cp; int dev; char *paths = NULL; char *path; int lens; #ifndef __APPLE__ di_devlink_handle_t dlh = NULL; #endif int ret = -1; #ifndef __APPLE__ struct devlink_cbinfo cbi; #endif struct nmlist *nlh = NULL; struct nmlist *nl; devid_nmlist_t *rl; int nret; int nagain = 0; int err = 0; *retlist = NULL; /* verify valid search path starts with "/devices" or "/dev" */ if ((strcmp(search_path, "/devices") == 0) || (strncmp(search_path, "/devices/", 9) == 0)) dev = 0; else if ((strcmp(search_path, "/dev") == 0) || (strncmp(search_path, "/dev/", 5) == 0)) dev = 1; else { errno = EINVAL; return (-1); } #ifndef __APPLE__ /* translate devid/minor_name to /devices paths */ again: if (modctl(MODDEVID2PATHS, devid, minor_name, 0, &lens, NULL) != 0) goto out; if ((paths = (char *)malloc(lens)) == NULL) goto out; if (modctl(MODDEVID2PATHS, devid, minor_name, 0, &lens, paths) != 0) { if ((errno == EAGAIN) && (nagain++ < DEVICEID_NMLIST_NRETRY)) { free(paths); paths = NULL; goto again; } goto out; } /* * initialize for /devices path to /dev path translation. To reduce * overhead we reuse the last snapshot if DEVICEID_NMLIST_SLINK is set. */ if (dev) { dlh = devid_deviceid_to_nmlist_dlh; if (dlh && !(devid_deviceid_to_nmlist_flg & DEVICEID_NMLIST_SLINK)) { (void) di_devlink_fini(&dlh); dlh = devid_deviceid_to_nmlist_dlh = NULL; } if ((dlh == NULL) && ((dlh = di_devlink_init(NULL, 0)) == NULL)) goto out; } /* * iterate over all the devtspectype resolutions of the devid and * convert them into the appropriate path form and add items to return * to the nmlist list; */ for (path = paths; *path; path += strlen(path) + 1) { if (dev) { /* add /dev entries */ cbi.cbi_nlhp = &nlh; cbi.cbi_search_path = search_path; cbi.cbi_error = 0; (void) di_devlink_walk(dlh, NULL, path, devid_deviceid_to_nmlist_link, (void *)&cbi, devlink_callback); if (cbi.cbi_error) goto out; } else { /* add /devices entry */ cp = malloc(strlen("/devices") + strlen(path) + 1); (void) strcpy(cp, "/devices"); (void) strcat(cp, path); if (strncmp(cp, search_path, strlen(search_path)) == 0) { if (nmlist_add(&nlh, cp) == NULL) { free(cp); goto out; } } free(cp); } } /* convert from nmlist to retlist array */ for (nl = nlh, nret = 0; nl; nl = nl->nl_next) nret++; if (nret == 0) { err = ENODEV; goto out; } if ((*retlist = calloc(nret + 1, sizeof (devid_nmlist_t))) == NULL) { err = ENOMEM; goto out; } for (nl = nlh, rl = *retlist; nl; nl = nl->nl_next, rl++) { rl->devname = nl->nl_devname; rl->dev = nl->nl_dev; } rl->devname = NULL; rl->dev = NODEV; ret = 0; out: while ((nl = nlh) != NULL) { /* free the nmlist */ nlh = nl->nl_next; free(nl); } if (paths) free(paths); if (dlh) { if ((ret == 0) && (devid_deviceid_to_nmlist_flg & DEVICEID_NMLIST_SLINK)) devid_deviceid_to_nmlist_dlh = dlh; else (void) di_devlink_fini(&dlh); } if (ret && *retlist) free(*retlist); if (ret && err != 0) errno = err; #endif return (ret); }