Exemplo n.º 1
0
/*
 * 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);
}
Exemplo n.º 2
0
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));
}
Exemplo n.º 3
0
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));
}
Exemplo n.º 4
0
/*
 * 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);
}
Exemplo n.º 5
0
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));
}
Exemplo n.º 6
0
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);
}
Exemplo n.º 7
0
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 **)&regbuf);
			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);
}
Exemplo n.º 8
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);
}
Exemplo n.º 9
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);
}
Exemplo n.º 10
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);
}
Exemplo n.º 11
0
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);
}
Exemplo n.º 12
0
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);
}
Exemplo n.º 13
0
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);
}