예제 #1
0
/* di_walk_node callback for disk_list_gather */
static int
dev_walk_di_nodes(di_node_t node, void *arg)
{
	char			*devidstr = NULL;
	char			*s;
	int			*val;

	/*
	 * If it's not a scsi_vhci client and doesn't have a target_port
	 * property and doesn't have a target property then it's not a storage
	 * device and we're not interested.
	 */
	if (di_path_client_next_path(node, NULL) == NULL &&
	    di_prop_lookup_strings(DDI_DEV_T_ANY, node,
	    SCSI_ADDR_PROP_TARGET_PORT, &s) <= 0 &&
	    di_prop_lookup_ints(DDI_DEV_T_ANY, node,
	    SCSI_ADDR_PROP_TARGET, &val) <= 0) {
		return (DI_WALK_CONTINUE);
	}
	(void) di_prop_lookup_strings(DDI_DEV_T_ANY, node,
	    DEVID_PROP_NAME, &devidstr);

	/* create/find the devid scsi topology node */
	(void) dev_di_node_add(node, devidstr, arg);

	return (DI_WALK_CONTINUE);
}
예제 #2
0
/*
 * The following boot properties can be used to configure a network
 * interface in the case of a diskless boot.
 *	host-ip, subnet-mask, server-path, server-name, server-ip.
 *
 * XXX non-diskless case requires "network-interface"?
 */
static boolean_t
boot_properties_present()
{
	/* XXX should use sys/bootprops.h, but it's not delivered */
	const char *required_properties[] = {
		"host-ip",
		"subnet-mask",
		"server-path",
		"server-name",
		"server-ip",
		NULL,
	};
	const char **prop = required_properties;
	char *prop_value;
	di_node_t dn;

	if ((dn = di_init("/", DINFOPROP)) == DI_NODE_NIL) {
		(void) fprintf(stderr, "%s: di_init: %s\n", program,
		    strerror(errno));
		di_fini(dn);
		return (B_FALSE);
	}

	while (*prop != NULL) {
		if (di_prop_lookup_strings(DDI_DEV_T_ANY,
		    dn, *prop, &prop_value) != 1) {
			di_fini(dn);
			return (B_FALSE);
		}
		prop++;
	}
	di_fini(dn);

	return (B_TRUE);
}
예제 #3
0
static int
print_bootpath()
{
	char *bootprop = NULL;

	if (di_prop_lookup_strings(DDI_DEV_T_ANY, devinfo_root,
	    "bootpath", &bootprop) >= 0) {
		(void) printf("%s\n", bootprop);
		return (0);
	} else if (di_prop_lookup_strings(DDI_DEV_T_ANY, devinfo_root,
	    "boot-path", &bootprop) >= 0) {
		(void) printf("%s\n", bootprop);
		return (0);
	} else {
		(void) printf("ERROR: no bootpath/boot-path property found\n");
		return (ENOENT);
	}
}
예제 #4
0
static char *
get_str_prop(char *prop_name, di_node_t node)
{
	char *str;

	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, prop_name, &str) == 1) {
		return (str);
	}

	return (NULL);
}
예제 #5
0
static int
count_cb(di_node_t node, void *arg)
{
	struct cb_data *cb = (struct cb_data *)arg;
	char *prop_data;

	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zfd_zname",
	    &prop_data) != -1) {
		assert(prop_data != NULL);
		if (strcmp(prop_data, zone_name) == 0) {
			cb->found++;
			return (DI_WALK_CONTINUE);
		}
	}
	return (DI_WALK_CONTINUE);
}
예제 #6
0
static int
disk_callback_fabric(di_minor_t minor, di_node_t node)
{
	char disk[DISK_SUBPATH_MAX];
	int lun;
	int count;
	int *intp;
	uchar_t *str;
	uchar_t *wwn;
	uchar_t ascii_wwn[ASCIIWWNSIZE];

	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
	    "client-guid", (char **)&wwn) > 0) {
		if (strlcpy((char *)ascii_wwn, (char *)wwn,
		    sizeof (ascii_wwn)) >= sizeof (ascii_wwn)) {
			devfsadm_errprint("SUNW_disk_link: GUID too long:%d",
			    strlen((char *)wwn));
			return (DEVFSADM_CONTINUE);
		}
		lun = 0;
	} else if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
	    "port-wwn", &wwn) > 0) {
		if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
		    SCSI_ADDR_PROP_LUN, &intp) > 0) {
			lun = *intp;
		} else {
			lun = 0;
		}

		for (count = 0, str = ascii_wwn; count < 8; count++, str += 2) {
			(void) sprintf((caddr_t)str, "%02x", wwn[count]);
		}
		*str = '\0';
	} else {
		return (DEVFSADM_CONTINUE);
	}

	for (str = ascii_wwn; *str != '\0'; str++) {
		*str = DISK_LINK_TO_UPPER(*str);
	}

	(void) snprintf(disk, DISK_SUBPATH_MAX, "t%sd%d", ascii_wwn, lun);

	disk_common(minor, node, disk, RM_STALE);

	return (DEVFSADM_CONTINUE);
}
예제 #7
0
/*
 * For the zfs control node:
 *	/dev/zfs -> /devices/pseudo/zfs@0:zfs
 * For zvols:
 *	/dev/zvol/dsk/<pool>/<dataset> -> /devices/pseudo/zfs@0:1
 *	/dev/zvol/rdsk/<pool>/<dataset> -> /devices/pseudo/zfs@0:1,raw
 */
static int
zfs(di_minor_t minor, di_node_t node)
{
	dev_t	dev;
	int	err;
	char mn[MAXNAMELEN + 1];
	char blkname[MAXNAMELEN + 1];
	char rawname[MAXNAMELEN + 1];
	char path[PATH_MAX + 1];
	char *name;

	(void) strcpy(mn, di_minor_name(minor));

	if (strcmp(mn, ZFS_DRIVER) == 0) {
		(void) devfsadm_mklink(ZFS_DRIVER, node, minor, 0);
	} else {
		dev = di_minor_devt(minor);
		err = di_prop_lookup_strings(dev, node, ZVOL_PROP_NAME, &name);
		if (err < 0) {
			/* property not defined so can't do anything */
			return (DEVFSADM_CONTINUE);
		}
		(void) snprintf(blkname, sizeof (blkname), "%dc",
		    (int)minor(dev));
		(void) snprintf(rawname, sizeof (rawname), "%dc,raw",
		    (int)minor(dev));

		/*
		 * This is where the actual public name gets constructed.
		 * Change the snprintf format to change the public
		 * path that gets constructed.
		 */
		if (strcmp(mn, blkname) == 0) {
			(void) snprintf(path, sizeof (path), "%s/%s",
			    ZVOL_DEV_DIR, name);
		} else if (strcmp(mn, rawname) == 0) {
			(void) snprintf(path, sizeof (path), "%s/%s",
			    ZVOL_RDEV_DIR, name);
		} else {
			return (DEVFSADM_CONTINUE);
		}

		(void) devfsadm_mklink(path, node, minor, 0);
	}
	return (DEVFSADM_CONTINUE);
}
예제 #8
0
void
devinfo_set_default_properties (HalDevice *d, HalDevice *parent, di_node_t node, char *devfs_path)
{
	char	*driver_name, *s;
	const char *s1;
	char	udi[HAL_PATH_MAX];

	if (parent != NULL) {
		hal_device_property_set_string (d, "info.parent", hal_device_get_udi (parent));
	} else {
		hal_device_property_set_string (d, "info.parent", "/org/freedesktop/Hal/devices/local");
	}

	hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
				"/org/freedesktop/Hal/devices%s_%d",
				devfs_path,
				di_instance (node));
	hal_device_set_udi (d, udi);
	hal_device_property_set_string (d, "info.udi", udi);

	if (di_prop_lookup_strings (DDI_DEV_T_ANY, node, "model", &s) > 0) {
		hal_device_property_set_string (d, "info.product", s);
	} else {
		hal_device_property_set_string (d, "info.product", di_node_name (node));
	}

	hal_device_property_set_string (d, "solaris.devfs_path", devfs_path);

	if ((driver_name = di_driver_name (node)) != NULL) {
		hal_device_property_set_string (d, "info.solaris.driver",
						driver_name);
	}


	/* inherit parent's claim attributes */
	if (hal_device_property_get_bool (parent, "info.claimed")) {
		s1 = hal_device_property_get_string (parent, "info.claimed.service");
		if (s1 != NULL) {
			hal_device_property_set_bool (d, "info.claimed", TRUE);
			hal_device_property_set_string (d, "info.claimed.service", s1);
		}
	}
}
예제 #9
0
static void
print_mpx_capable(di_node_t curnode)
{
	char *prop;
	char *path;
	char *aliases = NULL;

	if (cap_N_option) {
		aliases = calloc(1, MAXPATHLEN + 1);
		if (aliases == NULL) {
			logmsg(MSG_ERROR,
			    gettext("Unable to allocate memory for a device "
			    "alias list\n"));
			return;
		}
	}

	for (; curnode != DI_NODE_NIL; curnode = di_drv_next_node(curnode)) {
		if (di_prop_lookup_strings(DDI_DEV_T_ANY, curnode,
		    "initiator-port", &prop) >= 0) {
			if ((path = di_devfs_path(curnode)) == NULL) {
				logmsg(MSG_INFO,
				    "Unable to find devfs path for device "
				    "%s: %s\n", &curnode, strerror(errno));
				continue;
			}
			if (cap_N_option) {
				char *nodename = di_node_name(curnode);
				/* nodename is never going to be null */
				if (strstr(aliases, nodename) == NULL)
					/* haven't seen this nodename before */
					(void) snprintf(aliases,
					    MAXPATHLEN + 1, "%s|%s",
					    ((aliases != NULL) ? aliases : ""),
					    nodename);
			} else
				(void) printf("%s\n", path);
		}
	}
	if (cap_N_option)
		(void) printf("%s\n", aliases);
}
예제 #10
0
static int
zcons_create(di_minor_t minor, di_node_t node)
{
	char	*minor_str;
	char	*zonename;
	char	path[MAXPATHLEN];

	minor_str = di_minor_name(minor);

	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zonename",
	    &zonename) == -1) {
		return (DEVFSADM_CONTINUE);
	}

	(void) snprintf(path, sizeof (path), "zcons/%s/%s", zonename,
	    minor_str);
	(void) devfsadm_mklink(path, node, minor, 0);

	return (DEVFSADM_CONTINUE);
}
예제 #11
0
/*
 * destroy_zfd_devs() and its helper destroy_cb() tears down any zfd instances
 * associated with this zone. If things went very wrong, we might have an
 * incorrect number of instances hanging around.  This routine hunts down and
 * tries to remove all of them. Of course, if the fd is open, the instance will
 * not detach, which is a potential issue.
 */
static int
destroy_cb(di_node_t node, void *arg)
{
	struct cb_data *cb = (struct cb_data *)arg;
	char *prop_data;
	char *tmp;
	char devpath[MAXPATHLEN];
	devctl_hdl_t hdl;

	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zfd_zname",
	    &prop_data) == -1)
		return (DI_WALK_CONTINUE);

	assert(prop_data != NULL);
	if (strcmp(prop_data, zone_name) != 0) {
		/* this is a zfd for a different zone */
		return (DI_WALK_CONTINUE);
	}

	cb->found++;
	tmp = di_devfs_path(node);
	(void) snprintf(devpath, sizeof (devpath), "/devices/%s", tmp);
	di_devfs_path_free(tmp);

	if ((hdl = devctl_device_acquire(devpath, 0)) == NULL) {
		zerror(cb->zlogp, B_TRUE, "WARNING: zfd %s found, "
		    "but it could not be controlled.", devpath);
		return (DI_WALK_CONTINUE);
	}
	if (devctl_device_remove(hdl) == 0) {
		cb->killed++;
	} else {
		zerror(cb->zlogp, B_TRUE, "WARNING: zfd %s found, "
		    "but it could not be removed.", devpath);
	}
	devctl_release(hdl);
	return (DI_WALK_CONTINUE);
}
예제 #12
0
HalDevice *
devinfo_add_node(HalDevice *parent, di_node_t node)
{
	HalDevice *d = NULL;
	char	*devfs_path;
	char	*device_type = NULL;
	DevinfoDevHandler *handler;
	int	i;

	devfs_path = di_devfs_path (node);

        (void) di_prop_lookup_strings (DDI_DEV_T_ANY, node, "device_type",
	    &device_type);

	for (i = 0; (d == NULL) && (devinfo_handlers[i] != NULL); i++) {
		handler = devinfo_handlers[i];
		d = handler->add (parent, node, devfs_path, device_type);
	}

	di_devfs_path_free(devfs_path);

	HAL_INFO (("add_node: %s", d ? hal_device_get_udi (d) : "none"));
	return (d);
}
예제 #13
0
/*
 * 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);
}
예제 #14
0
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);
}
예제 #15
0
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 int solarisWalkDeviceNode(di_node_t Node, void *pvArg)
{
    PUSBDEVICELIST pList = (PUSBDEVICELIST)pvArg;
    AssertPtrReturn(pList, DI_WALK_TERMINATE);

    /*
     * Check if it's a USB device in the first place.
     */
    bool fUSBDevice = false;
    char *pszCompatNames = NULL;
    int cCompatNames = di_compatible_names(Node, &pszCompatNames);
    for (int i = 0; i < cCompatNames; i++, pszCompatNames += strlen(pszCompatNames) + 1)
        if (!strncmp(pszCompatNames, "usb", 3))
        {
            fUSBDevice = true;
            break;
        }

    if (!fUSBDevice)
        return DI_WALK_CONTINUE;

    /*
     * Check if it's a device node or interface.
     */
    int *pInt = NULL;
    char *pStr = NULL;
    int rc = DI_WALK_CONTINUE;
    if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "interface", &pInt) < 0)
    {
        /* It's a device node. */
        char *pszDevicePath = di_devfs_path(Node);
        PUSBDEVICE pCur = (PUSBDEVICE)RTMemAllocZ(sizeof(*pCur));
        if (!pCur)
        {
            LogRel(("USBService: failed to allocate %d bytes for PUSBDEVICE.\n", sizeof(*pCur)));
            return DI_WALK_TERMINATE;
        }

        bool fValidDevice = false;
        do
        {
            AssertBreak(pszDevicePath);

            char *pszDriverName = di_driver_name(Node);

            /*
             * Skip hubs
             */
            if (   pszDriverName
                && !strcmp(pszDriverName, "hubd"))
            {
                break;
            }

            /*
             * Mandatory.
             * snv_85 and above have usb-dev-descriptor node properties, but older one's do not.
             * So if we cannot obtain the entire device descriptor, we try falling back to the
             * individual properties (those must not fail, if it does we drop the device).
             */
            uchar_t *pDevData = NULL;
            int cbProp = di_prop_lookup_bytes(DDI_DEV_T_ANY, Node, "usb-dev-descriptor", &pDevData);
            if (   cbProp > 0
                && pDevData)
            {
                usb_dev_descr_t *pDeviceDescriptor = (usb_dev_descr_t *)pDevData;
                pCur->bDeviceClass = pDeviceDescriptor->bDeviceClass;
                pCur->bDeviceSubClass = pDeviceDescriptor->bDeviceSubClass;
                pCur->bDeviceProtocol = pDeviceDescriptor->bDeviceProtocol;
                pCur->idVendor = pDeviceDescriptor->idVendor;
                pCur->idProduct = pDeviceDescriptor->idProduct;
                pCur->bcdDevice = pDeviceDescriptor->bcdDevice;
                pCur->bcdUSB = pDeviceDescriptor->bcdUSB;
                pCur->bNumConfigurations = pDeviceDescriptor->bNumConfigurations;
                pCur->fPartialDescriptor = false;
            }
            else
            {
                AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-vendor-id", &pInt) > 0);
                pCur->idVendor = (uint16_t)*pInt;

                AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-product-id", &pInt) > 0);
                pCur->idProduct = (uint16_t)*pInt;

                AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-revision-id", &pInt) > 0);
                pCur->bcdDevice = (uint16_t)*pInt;

                AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-release", &pInt) > 0);
                pCur->bcdUSB = (uint16_t)*pInt;

                pCur->fPartialDescriptor = true;
            }

            char *pszPortAddr = di_bus_addr(Node);
            if (pszPortAddr)
                pCur->bPort = RTStrToUInt8(pszPortAddr);     /* Bus & Port are mixed up (kernel driver/userland) */
            else
                pCur->bPort = 0;

            char pathBuf[PATH_MAX];
            RTStrPrintf(pathBuf, sizeof(pathBuf), "%s", pszDevicePath);
            RTPathStripFilename(pathBuf);

            char szBuf[PATH_MAX + 48];
            RTStrPrintf(szBuf, sizeof(szBuf), "%#x:%#x:%d:%s", pCur->idVendor, pCur->idProduct, pCur->bcdDevice, pathBuf);
            pCur->pszAddress = RTStrDup(szBuf);

            pCur->pszDevicePath = RTStrDup(pszDevicePath);
            AssertBreak(pCur->pszDevicePath);

            /*
             * Optional (some devices don't have all these)
             */
            if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "usb-product-name", &pStr) > 0)
                pCur->pszProduct = RTStrDup(pStr);

            if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "usb-vendor-name", &pStr) > 0)
                pCur->pszManufacturer = RTStrDup(pStr);

            if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "usb-serialno", &pStr) > 0)
                pCur->pszSerialNumber = RTStrDup(pStr);

            if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "low-speed", &pInt) >= 0)
                pCur->enmSpeed = USBDEVICESPEED_LOW;
            else if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "high-speed", &pInt) >= 0)
                pCur->enmSpeed = USBDEVICESPEED_HIGH;
            else
                pCur->enmSpeed = USBDEVICESPEED_FULL;

            /* Determine state of the USB device. */
            pCur->enmState = solarisDetermineUSBDeviceState(pCur, Node);

            /*
             * Valid device, add it to the list.
             */
            fValidDevice = true;
            pCur->pPrev = pList->pTail;
            if (pList->pTail)
                pList->pTail = pList->pTail->pNext = pCur;
            else
                pList->pTail = pList->pHead = pCur;

            rc = DI_WALK_CONTINUE;
        } while(0);

        di_devfs_path_free(pszDevicePath);
        if (!fValidDevice)
            solarisFreeUSBDevice(pCur);
    }
    return rc;
}
예제 #17
0
static int
disk_callback_sas(di_minor_t minor, di_node_t node)
{
	char disk[DISK_SUBPATH_MAX];
	int lun64_found = 0;
	scsi_lun64_t lun64, sl;
	scsi_lun_t lun;
	int64_t *lun64p;
	uint64_t wwn;
	int *intp;
	char *tgt_port;
	uchar_t addr_method;

	/* Get lun property */
	if (di_prop_lookup_int64(DDI_DEV_T_ANY, node,
	    SCSI_ADDR_PROP_LUN64, &lun64p) > 0) {
		if (*lun64p != SCSI_LUN64_ILLEGAL) {
			lun64_found = 1;
			lun64 = (uint64_t)*lun64p;
		}
	}
	if ((!lun64_found) && (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
	    SCSI_ADDR_PROP_LUN, &intp) > 0)) {
		lun64 = (uint64_t)*intp;
	}

	lun = scsi_lun64_to_lun(lun64);

	addr_method = (lun.sl_lun1_msb & SCSI_LUN_AM_MASK);

	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
	    SCSI_ADDR_PROP_TARGET_PORT, &tgt_port) > 0) {
		(void) scsi_wwnstr_to_wwn(tgt_port, &wwn);
		if ((addr_method == SCSI_LUN_AM_PDEV) &&
		    (lun.sl_lun2_msb == 0) && (lun.sl_lun2_lsb == 0) &&
		    (lun.sl_lun3_msb == 0) && (lun.sl_lun3_lsb == 0) &&
		    (lun.sl_lun4_msb == 0) && (lun.sl_lun4_lsb == 0)) {
			(void) snprintf(disk, DISK_SUBPATH_MAX,
			    "t%"PRIX64"d%"PRId64, wwn, lun64);
		} else if ((addr_method == SCSI_LUN_AM_FLAT) &&
		    (lun.sl_lun2_msb == 0) && (lun.sl_lun2_lsb == 0) &&
		    (lun.sl_lun3_msb == 0) && (lun.sl_lun3_lsb == 0) &&
		    (lun.sl_lun4_msb == 0) && (lun.sl_lun4_lsb == 0)) {
			sl = (lun.sl_lun1_msb << 8) | lun.sl_lun1_lsb;
			(void) snprintf(disk, DISK_SUBPATH_MAX,
			    "t%"PRIX64"d%"PRIX16, wwn, sl);
		} else {
			(void) snprintf(disk, DISK_SUBPATH_MAX,
			    "t%"PRIX64"d%"PRIX64, wwn, lun64);
		}
	} else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
	    SCSI_ADDR_PROP_SATA_PHY, &intp) > 0) {
		/* Use phy format naming, for SATA devices without wwn */
		if ((addr_method == SCSI_LUN_AM_PDEV) &&
		    (lun.sl_lun2_msb == 0) && (lun.sl_lun2_lsb == 0) &&
		    (lun.sl_lun3_msb == 0) && (lun.sl_lun3_lsb == 0) &&
		    (lun.sl_lun4_msb == 0) && (lun.sl_lun4_lsb == 0)) {
			(void) snprintf(disk, DISK_SUBPATH_MAX,
			    "t%dd%"PRId64, *intp, lun64);
		} else if ((addr_method == SCSI_LUN_AM_FLAT) &&
		    (lun.sl_lun2_msb == 0) && (lun.sl_lun2_lsb == 0) &&
		    (lun.sl_lun3_msb == 0) && (lun.sl_lun3_lsb == 0) &&
		    (lun.sl_lun4_msb == 0) && (lun.sl_lun4_lsb == 0)) {
			sl = (lun.sl_lun1_msb << 8) | lun.sl_lun1_lsb;
			(void) snprintf(disk, DISK_SUBPATH_MAX,
			    "t%dd%"PRIX16, *intp, sl);
		} else {
			(void) snprintf(disk, DISK_SUBPATH_MAX,
			    "t%dd%"PRIX64, *intp, lun64);
		}
	} else {
		return (DEVFSADM_CONTINUE);
	}

	disk_common(minor, node, disk, RM_STALE);

	return (DEVFSADM_CONTINUE);
}