示例#1
0
static int
gather_pci_cap(LibHalContext *ctx, const char *udi,
               virNodeDevCapDataPtr d)
{
    char *sysfs_path;

    if (get_str_prop(ctx, udi, "pci.linux.sysfs_path", &sysfs_path) == 0) {
        char *p = strrchr(sysfs_path, '/');
        if (p) {
            ignore_value(virStrToLong_ui(p+1, &p, 16, &d->pci_dev.domain));
            ignore_value(virStrToLong_ui(p+1, &p, 16, &d->pci_dev.bus));
            ignore_value(virStrToLong_ui(p+1, &p, 16, &d->pci_dev.slot));
            ignore_value(virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function));
        }

        if (nodeDeviceSysfsGetPCIRelatedDevCaps(sysfs_path, d) < 0) {
            VIR_FREE(sysfs_path);
            return -1;
        }
        VIR_FREE(sysfs_path);
    }

    (void)get_int_prop(ctx, udi, "pci.vendor_id", (int *)&d->pci_dev.vendor);
    if (get_str_prop(ctx, udi, "pci.vendor", &d->pci_dev.vendor_name) != 0)
        (void)get_str_prop(ctx, udi, "info.vendor", &d->pci_dev.vendor_name);
    (void)get_int_prop(ctx, udi, "pci.product_id", (int *)&d->pci_dev.product);
    if (get_str_prop(ctx, udi, "pci.product", &d->pci_dev.product_name) != 0)
        (void)get_str_prop(ctx, udi, "info.product", &d->pci_dev.product_name);

    return 0;
}
static int gather_pci_cap(LibHalContext *ctx, const char *udi,
                          union _virNodeDevCapData *d)
{
    char *sysfs_path;

    if (get_str_prop(ctx, udi, "pci.linux.sysfs_path", &sysfs_path) == 0) {
        char *p = strrchr(sysfs_path, '/');
        if (p) {
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.domain);
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.bus);
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.slot);
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function);
        }

        if (!pciGetPhysicalFunction(sysfs_path, &d->pci_dev.physical_function))
            d->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION;

        if (!pciGetVirtualFunctions(sysfs_path, &d->pci_dev.virtual_functions,
            &d->pci_dev.num_virtual_functions) ||
            d->pci_dev.num_virtual_functions > 0)
            d->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;

        VIR_FREE(sysfs_path);
    }

    (void)get_int_prop(ctx, udi, "pci.vendor_id", (int *)&d->pci_dev.vendor);
    if (get_str_prop(ctx, udi, "pci.vendor", &d->pci_dev.vendor_name) != 0)
        (void)get_str_prop(ctx, udi, "info.vendor", &d->pci_dev.vendor_name);
    (void)get_int_prop(ctx, udi, "pci.product_id", (int *)&d->pci_dev.product);
    if (get_str_prop(ctx, udi, "pci.product", &d->pci_dev.product_name) != 0)
        (void)get_str_prop(ctx, udi, "info.product", &d->pci_dev.product_name);

    return 0;
}
示例#3
0
static int gather_pci_cap(LibHalContext *ctx, const char *udi,
                          union _virNodeDevCapData *d)
{
    char *sysfs_path;

    if (get_str_prop(ctx, udi, "pci.linux.sysfs_path", &sysfs_path) == 0) {
        char *p = strrchr(sysfs_path, '/');
        if (p) {
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.domain);
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.bus);
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.slot);
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function);
        }

        get_physical_function(sysfs_path, d);
        get_virtual_functions(sysfs_path, d);

        VIR_FREE(sysfs_path);
    }

    (void)get_int_prop(ctx, udi, "pci.vendor_id", (int *)&d->pci_dev.vendor);
    if (get_str_prop(ctx, udi, "pci.vendor", &d->pci_dev.vendor_name) != 0)
        (void)get_str_prop(ctx, udi, "info.vendor", &d->pci_dev.vendor_name);
    (void)get_int_prop(ctx, udi, "pci.product_id", (int *)&d->pci_dev.product);
    if (get_str_prop(ctx, udi, "pci.product", &d->pci_dev.product_name) != 0)
        (void)get_str_prop(ctx, udi, "info.product", &d->pci_dev.product_name);

    return 0;
}
示例#4
0
static int
gather_capabilities(LibHalContext *ctx, const char *udi,
                    virNodeDevCapsDefPtr *caps_p)
{
    char *bus_name = NULL;
    virNodeDevCapsDefPtr caps = NULL;
    char **hal_cap_names = NULL;
    int rv;
    size_t i;

    if (STREQ(udi, "/org/freedesktop/Hal/devices/computer")) {
        rv = gather_capability(ctx, udi, "system", &caps);
        if (rv != 0)
            goto failure;
    }

    if (get_str_prop(ctx, udi, "info.subsystem", &bus_name) == 0 ||
        get_str_prop(ctx, udi, "linux.subsystem", &bus_name) == 0) {
        rv = gather_capability(ctx, udi, bus_name, &caps);
        if (rv != 0)
            goto failure;
    }

    hal_cap_names = libhal_device_get_property_strlist(ctx, udi,
                                                       "info.capabilities",
                                                       NULL);
    if (hal_cap_names) {
        for (i = 0; hal_cap_names[i]; i++) {
            if (! (bus_name && STREQ(hal_cap_names[i], bus_name))) {
                rv = gather_capability(ctx, udi, hal_cap_names[i], &caps);
                if (rv != 0)
                    goto failure;
            }
        }
        for (i = 0; hal_cap_names[i]; i++)
            VIR_FREE(hal_cap_names[i]);
        VIR_FREE(hal_cap_names);
    }
    VIR_FREE(bus_name);

    *caps_p = caps;
    return 0;

 failure:
    VIR_FREE(bus_name);
    if (hal_cap_names) {
        for (i = 0; hal_cap_names[i]; i++)
            VIR_FREE(hal_cap_names[i]);
        VIR_FREE(hal_cap_names);
    }
    while (caps) {
        virNodeDevCapsDefPtr next = caps->next;
        virNodeDevCapsDefFree(caps);
        caps = next;
    }
    return rv;
}
示例#5
0
static int
gather_system_cap(LibHalContext *ctx, const char *udi,
                  union _virNodeDevCapData *d)
{
    char *uuidstr;

    (void)get_str_prop(ctx, udi, "system.product", &d->system.product_name);
    (void)get_str_prop(ctx, udi, "system.hardware.vendor",
                       &d->system.hardware.vendor_name);
    (void)get_str_prop(ctx, udi, "system.hardware.version",
                       &d->system.hardware.version);
    (void)get_str_prop(ctx, udi, "system.hardware.serial",
                       &d->system.hardware.serial);
    if (get_str_prop(ctx, udi, "system.hardware.uuid", &uuidstr) == 0) {
        ignore_value(virUUIDParse(uuidstr, d->system.hardware.uuid));
        VIR_FREE(uuidstr);
    }
    (void)get_str_prop(ctx, udi, "system.firmware.vendor",
                       &d->system.firmware.vendor_name);
    (void)get_str_prop(ctx, udi, "system.firmware.version",
                       &d->system.firmware.version);
    (void)get_str_prop(ctx, udi, "system.firmware.release_date",
                       &d->system.firmware.release_date);
    return 0;
}
示例#6
0
static int
gather_scsi_generic_cap(LibHalContext *ctx, const char *udi,
                        union _virNodeDevCapData *d)
{
    (void)get_str_prop(ctx, udi, "scsi_generic.device", &d->sg.path);
    return 0;
}
static int gather_net_cap(LibHalContext *ctx, const char *udi,
                          union _virNodeDevCapData *d)
{
    unsigned long long dummy;
    (void)get_str_prop(ctx, udi, "net.interface", &d->net.ifname);
    (void)get_str_prop(ctx, udi, "net.address", &d->net.address);
    if (get_uint64_prop(ctx, udi, "net.80203.mac_address",
                        &dummy) == 0)
        d->net.subtype = VIR_NODE_DEV_CAP_NET_80203;
    else if (get_uint64_prop(ctx, udi, "net.80211.mac_address",
                             &dummy) == 0)
        d->net.subtype = VIR_NODE_DEV_CAP_NET_80211;
    else
        d->net.subtype = VIR_NODE_DEV_CAP_NET_LAST;

    return 0;
}
static int gather_scsi_cap(LibHalContext *ctx, const char *udi,
                           union _virNodeDevCapData *d)
{
    (void)get_int_prop(ctx, udi, "scsi.host", (int *)&d->scsi.host);
    (void)get_int_prop(ctx, udi, "scsi.bus", (int *)&d->scsi.bus);
    (void)get_int_prop(ctx, udi, "scsi.target", (int *)&d->scsi.target);
    (void)get_int_prop(ctx, udi, "scsi.lun", (int *)&d->scsi.lun);
    (void)get_str_prop(ctx, udi, "scsi.type", &d->scsi.type);
    return 0;
}
static int gather_usb_device_cap(LibHalContext *ctx, const char *udi,
                          union _virNodeDevCapData *d)
{
    (void)get_int_prop(ctx, udi, "usb_device.bus_number",
                       (int *)&d->usb_dev.bus);
    (void)get_int_prop(ctx, udi, "usb_device.linux.device_number",
                       (int *)&d->usb_dev.device);
    (void)get_int_prop(ctx, udi, "usb_device.vendor_id",
                       (int *)&d->usb_dev.vendor);
    if (get_str_prop(ctx, udi, "usb_device.vendor",
                     &d->usb_dev.vendor_name) != 0)
        (void)get_str_prop(ctx, udi, "info.vendor", &d->usb_dev.vendor_name);
    (void)get_int_prop(ctx, udi, "usb_device.product_id",
                       (int *)&d->usb_dev.product);
    if (get_str_prop(ctx, udi, "usb_device.product",
                     &d->usb_dev.product_name) != 0)
        (void)get_str_prop(ctx, udi, "info.product", &d->usb_dev.product_name);
    return 0;
}
示例#10
0
static int
gather_storage_cap(LibHalContext *ctx, const char *udi,
                   union _virNodeDevCapData *d)
{
    int val;
    (void)get_str_prop(ctx, udi, "block.device", &d->storage.block);
    (void)get_str_prop(ctx, udi, "storage.bus", &d->storage.bus);
    (void)get_str_prop(ctx, udi, "storage.drive_type", &d->storage.drive_type);
    (void)get_str_prop(ctx, udi, "storage.model", &d->storage.model);
    (void)get_str_prop(ctx, udi, "storage.vendor", &d->storage.vendor);
    (void)get_str_prop(ctx, udi, "storage.serial", &d->storage.serial);
    if (get_bool_prop(ctx, udi, "storage.removable", &val) == 0 && val) {
        d->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE;
        if (get_bool_prop(ctx, udi, "storage.removable.media_available",
                          &val) == 0 && val) {
            d->storage.flags |=
                VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE;
            (void)get_uint64_prop(ctx, udi, "storage.removable.media_size",
                                  &d->storage.removable_media_size);
        }
    } else {
        (void)get_uint64_prop(ctx, udi, "storage.size", &d->storage.size);
    }
    if (get_bool_prop(ctx, udi, "storage.hotpluggable", &val) == 0 && val)
        d->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE;
    return 0;
}
static int gather_usb_cap(LibHalContext *ctx, const char *udi,
                          union _virNodeDevCapData *d)
{
    (void)get_int_prop(ctx, udi, "usb.interface.number",
                       (int *)&d->usb_if.number);
    (void)get_int_prop(ctx, udi, "usb.interface.class",
                       (int *)&d->usb_if._class);
    (void)get_int_prop(ctx, udi, "usb.interface.subclass",
                       (int *)&d->usb_if.subclass);
    (void)get_int_prop(ctx, udi, "usb.interface.protocol",
                       (int *)&d->usb_if.protocol);
    (void)get_str_prop(ctx, udi, "usb.interface.description",
                       &d->usb_if.description);
    return 0;
}
示例#12
0
STATIC phandle
DoFindNodeByType(char *type, phandle ph)
{
	phandle res;

	if (ph == 0) {
		return(0);
	}
	if (strcmp(get_str_prop(ph, "device_type", NOALLOC), type) == 0) {
		return(ph);
	}
	res = DoFindNodeByType(type, OFChild(ph));
	if (res != 0) {
		return(res);
	}
	return(DoFindNodeByType(type, OFPeer(ph)));
}
示例#13
0
static void
dev_create(const char *udi)
{
    LibHalContext *ctx;
    char *parent_key = NULL;
    virNodeDeviceObjPtr dev = NULL;
    virNodeDeviceDefPtr def = NULL;
    const char *name = hal_name(udi);
    int rv;
    char *privData;
    char *devicePath = NULL;

    if (VIR_STRDUP(privData, udi) < 0)
        return;

    nodeDeviceLock(driverState);
    ctx = DRV_STATE_HAL_CTX(driverState);

    if (VIR_ALLOC(def) < 0)
        goto failure;

    if (VIR_STRDUP(def->name, name) < 0)
        goto failure;

    if (get_str_prop(ctx, udi, "info.parent", &parent_key) == 0) {
        if (VIR_STRDUP(def->parent, hal_name(parent_key)) < 0) {
            VIR_FREE(parent_key);
            goto failure;
        }
        VIR_FREE(parent_key);
    }

    rv = gather_capabilities(ctx, udi, &def->caps);
    if (rv != 0) goto failure;

    if (def->caps == NULL)
        goto cleanup;

    /* Some devices don't have a path in sysfs, so ignore failure */
    (void)get_str_prop(ctx, udi, "linux.sysfs_path", &devicePath);

    dev = virNodeDeviceAssignDef(&driverState->devs,
                                 def);

    if (!dev) {
        VIR_FREE(devicePath);
        goto failure;
    }

    dev->privateData = privData;
    dev->privateFree = free_udi;
    dev->def->sysfs_path = devicePath;

    virNodeDeviceObjUnlock(dev);

    nodeDeviceUnlock(driverState);
    return;

 failure:
    VIR_DEBUG("FAILED TO ADD dev %s", name);
cleanup:
    VIR_FREE(privData);
    virNodeDeviceDefFree(def);
    nodeDeviceUnlock(driverState);
}
示例#14
0
static disk_t *
create_disk(char *deviceid, char *kernel_name, struct search_args *args)
{
	disk_t	*diskp;
	char	*type;
	char	*prod_id;
	char	*vendor_id;

	if (dm_debug) {
		(void) fprintf(stderr, "INFO: create_disk %s\n", kernel_name);
	}

	diskp = calloc(1, sizeof (disk_t));
	if (diskp == NULL) {
		return (NULL);
	}

	diskp->controllers = (controller_t **)
	    calloc(1, sizeof (controller_t *));
	if (diskp->controllers == NULL) {
		cache_free_disk(diskp);
		return (NULL);
	}
	diskp->controllers[0] = NULL;

	diskp->devid = NULL;
	if (deviceid != NULL) {
		if ((diskp->device_id = strdup(deviceid)) == NULL) {
			cache_free_disk(diskp);
			return (NULL);
		}
		(void) devid_str_decode(deviceid, &(diskp->devid), NULL);
	}

	if (kernel_name != NULL) {
		diskp->kernel_name = strdup(kernel_name);
		if (diskp->kernel_name == NULL) {
			cache_free_disk(diskp);
			return (NULL);
		}
	}

	diskp->paths = NULL;
	diskp->aliases = NULL;

	diskp->cd_rom = 0;
	diskp->rpm = 0;
	diskp->solid_state = -1;
	type = di_minor_nodetype(args->minor);

	prod_id = get_str_prop(PROD_ID_PROP, args->node);
	if (prod_id != NULL) {
		if ((diskp->product_id = strdup(prod_id)) == NULL) {
			cache_free_disk(diskp);
			return (NULL);
		}
	} else {
		prod_id = get_str_prop(PROD_ID_USB_PROP, args->node);
		if (prod_id != NULL) {
			if ((diskp->product_id = strdup(prod_id)) == NULL) {
				cache_free_disk(diskp);
				return (NULL);
			}
		}
	}

	vendor_id = get_str_prop(VENDOR_ID_PROP, args->node);
	if (vendor_id != NULL) {
		if ((diskp->vendor_id = strdup(vendor_id)) == NULL) {
			cache_free_disk(diskp);
			return (NULL);
		}
	} else {
		vendor_id = get_str_prop(VENDOR_ID_USB_PROP, args->node);
		if (vendor_id != NULL) {
			if ((diskp->vendor_id = strdup(vendor_id)) == NULL) {
				cache_free_disk(diskp);
				return (NULL);
			}
		}
	}

	/*
	 * DVD, CD-ROM, CD-RW, MO, etc. are all reported as CD-ROMS.
	 * We try to use uscsi later to determine the real type.
	 * The cd_rom flag tells us that the kernel categorized the drive
	 * as a CD-ROM.  We leave the drv_type as UNKNOWN for now.
	 * The combination of the cd_rom flag being set with the drv_type of
	 * unknown is what triggers the uscsi probe in drive.c.
	 */
	if (disk_is_cdrom(type)) {
		diskp->drv_type = DM_DT_UNKNOWN;
		diskp->cd_rom = 1;
		diskp->removable = 1;
	} else if (libdiskmgt_str_eq(type, DDI_NT_FD)) {
		diskp->drv_type = DM_DT_FLOPPY;
		diskp->removable = 1;
	} else {
		/* not a CD-ROM or Floppy */
		diskp->removable = get_prop(REMOVABLE_PROP, args->node);

		if (diskp->removable == -1) {
			diskp->removable = 0;
			diskp->drv_type = DM_DT_FIXED;
		}
	}

	diskp->next = args->disk_listp;
	args->disk_listp = diskp;

	return (diskp);
}
示例#15
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);
}
示例#16
0
static int
add_devpath(di_devlink_t devlink, void *arg)
{
	struct search_args *args;
	char		*devidstr;
	disk_t		*diskp;
	char		kernel_name[MAXPATHLEN];

	args =	(struct search_args *)arg;

	/*
	 * Get the diskp value from calling have_disk. Can either be found
	 * by kernel name or devid.
	 */

	diskp = NULL;
	devidstr = get_str_prop(DEVICE_ID_PROP, args->node);
	(void) snprintf(kernel_name, sizeof (kernel_name), "%s%d",
	    di_node_name(args->node), di_instance(args->node));

	(void) have_disk(args, devidstr, kernel_name, &diskp);

	/*
	 * The devlink_path is usually of the form /dev/rdsk/c0t0d0s0.
	 * For diskettes it is /dev/rdiskette*.
	 * On Intel we would also get each fdisk partition as well
	 * (e.g. /dev/rdsk/c0t0d0p0).
	 */
	if (diskp != NULL) {
		alias_t	*ap;
		char	*devlink_path;

		if (diskp->drv_type != DM_DT_FLOPPY) {
			/*
			 * Add other controllers for multipath disks.
			 * This will have no effect if the controller
			 * relationship is already set up.
			 */
			if (add_disk2controller(diskp, args) != 0) {
				args->dev_walk_status = ENOMEM;
			}
		}

		(void) snprintf(kernel_name, sizeof (kernel_name), "%s%d",
		    di_node_name(args->node), di_instance(args->node));
		devlink_path = (char *)di_devlink_path(devlink);

		if (dm_debug > 1) {
			(void) fprintf(stderr,
			    "INFO:     devpath %s\n", devlink_path);
		}

		if ((ap = find_alias(diskp, kernel_name)) == NULL) {
			if (new_alias(diskp, kernel_name, devlink_path,
			    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, devlink_path) != 0) {
				args->dev_walk_status = ENOMEM;
			}
		}
	}

	return (DI_WALK_CONTINUE);
}