269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * CDDL HEADER START
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The contents of this file are subject to the terms of the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Common Development and Distribution License (the "License").
269473047d747f7815af570197e4ef7322d3632cEvan Yan * You may not use this file except in compliance with the License.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
269473047d747f7815af570197e4ef7322d3632cEvan Yan * or http://www.opensolaris.org/os/licensing.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * See the License for the specific language governing permissions
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and limitations under the License.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * When distributing Covered Code, include this CDDL HEADER in each
269473047d747f7815af570197e4ef7322d3632cEvan Yan * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If applicable, add the following below this CDDL HEADER, with the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * fields enclosed by brackets "[]" replaced with your own identifying
269473047d747f7815af570197e4ef7322d3632cEvan Yan * information: Portions Copyright [yyyy] [name of copyright owner]
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * CDDL HEADER END
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Use is subject to license terms.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <stdio.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <stdlib.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <string.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <errno.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <libdevinfo.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <libhotplug.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <libhotplug_impl.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sunddi.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/ddi_hp.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include "hotplugd_impl.h"
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Define a list of hotplug nodes.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * (Only used within this module.)
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yantypedef struct {
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t head;
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t prev;
269473047d747f7815af570197e4ef7322d3632cEvan Yan} hp_node_list_t;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Local functions.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int copy_devinfo(const char *, const char *, uint_t,
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t *);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int copy_devices(hp_node_t, di_node_t, uint_t, hp_node_t *);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int copy_hotplug(hp_node_t, di_node_t, const char *, uint_t,
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t *);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic char *base_path(const char *);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int search_cb(di_node_t, void *);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int check_search(di_node_t, uint_t);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic hp_node_t new_device_node(hp_node_t, di_node_t);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic hp_node_t new_hotplug_node(hp_node_t, di_hp_t);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void node_list_add(hp_node_list_t *, hp_node_t);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * getinfo()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Build a hotplug information snapshot. The path, connection,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and flags indicate what information should be included.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yangetinfo(const char *path, const char *connection, uint_t flags, hp_node_t *retp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t root = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t child;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *basepath;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((path == NULL) || (retp == NULL))
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("getinfo: path=%s, connection=%s, flags=0x%x\n", path,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (connection == NULL) ? "NULL" : connection, flags);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate the base path */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((basepath = base_path(path)) == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Copy in device and hotplug nodes from libdevinfo */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = copy_devinfo(basepath, connection, flags, &root)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_fini(root);
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(basepath);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check if there were no connections */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (root == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("getinfo: no hotplug connections.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(basepath);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOENT);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Special case: exclude root nexus from snapshot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strcmp(basepath, "/") == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan child = root->hp_child;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (root->hp_name != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(root->hp_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(root);
269473047d747f7815af570197e4ef7322d3632cEvan Yan root = child;
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (child = root; child; child = child->hp_sibling)
269473047d747f7815af570197e4ef7322d3632cEvan Yan child->hp_parent = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Store a pointer to the base path in each root node */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (child = root; child != NULL; child = child->hp_sibling)
269473047d747f7815af570197e4ef7322d3632cEvan Yan child->hp_basepath = basepath;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Copy in usage information from RCM */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (flags & HPINFOUSAGE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = copy_usage(root)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) hp_fini(root);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *retp = root;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * copy_devinfo()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Copy information about device and hotplug nodes from libdevinfo.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * When path is set to "/", the results need to be limited only to
269473047d747f7815af570197e4ef7322d3632cEvan Yan * branches that contain hotplug information. An initial search
269473047d747f7815af570197e4ef7322d3632cEvan Yan * is performed to mark which branches contain hotplug nodes.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yancopy_devinfo(const char *path, const char *connection, uint_t flags,
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t *rootp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t hp_root = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan di_node_t di_root;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get libdevinfo snapshot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((di_root = di_init(path, DINFOSUBTREE | DINFOHP)) == DI_NODE_NIL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (errno);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Do initial search pass, if required */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strcmp(path, "/") == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan flags |= HPINFOSEARCH;
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) di_walk_node(di_root, DI_WALK_CLDFIRST, NULL, search_cb);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If a connection is specified, just copy immediate hotplug info.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Else, copy the device tree normally.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (connection != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = copy_hotplug(NULL, di_root, connection, flags, &hp_root);
269473047d747f7815af570197e4ef7322d3632cEvan Yan else
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = copy_devices(NULL, di_root, flags, &hp_root);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Destroy devinfo snapshot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan di_fini(di_root);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *rootp = (rv == 0) ? hp_root : NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * copy_devices()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Copy a full branch of device nodes. Used by copy_devinfo() and
269473047d747f7815af570197e4ef7322d3632cEvan Yan * copy_hotplug().
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yancopy_devices(hp_node_t parent, di_node_t dev, uint_t flags, hp_node_t *rootp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_list_t children;
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t self, branch;
269473047d747f7815af570197e4ef7322d3632cEvan Yan di_node_t child;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan *rootp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Enforce search semantics */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (check_search(dev, flags) == 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate new node for current device */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((self = new_device_node(parent, dev)) == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If the device has hotplug nodes, then use copy_hotplug()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * instead to build the branch associated with current device.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (di_hp_next(dev, DI_HP_NIL) != DI_HP_NIL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = copy_hotplug(self, dev, NULL, flags,
269473047d747f7815af570197e4ef7322d3632cEvan Yan &self->hp_child)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(self);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan *rootp = self;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The device does not have hotplug nodes. Use normal
269473047d747f7815af570197e4ef7322d3632cEvan Yan * approach of iterating through its child device nodes.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) memset(&children, 0, sizeof (hp_node_list_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (child = di_child_node(dev); child != DI_NODE_NIL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan child = di_sibling_node(child)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan branch = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = copy_devices(self, child, flags, &branch)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) hp_fini(children.head);
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(self);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (branch != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan node_list_add(&children, branch);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan self->hp_child = children.head;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Done */
269473047d747f7815af570197e4ef7322d3632cEvan Yan *rootp = self;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * copy_hotplug()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Copy a full branch of hotplug nodes. Used by copy_devinfo()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and copy_devices().
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If a connection is specified, the results are limited only
269473047d747f7815af570197e4ef7322d3632cEvan Yan * to the branch associated with that specific connection.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yancopy_hotplug(hp_node_t parent, di_node_t dev, const char *connection,
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint_t flags, hp_node_t *retp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_list_t connections, ports;
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t node, port_node;
269473047d747f7815af570197e4ef7322d3632cEvan Yan di_node_t child_dev;
269473047d747f7815af570197e4ef7322d3632cEvan Yan di_hp_t hp, port_hp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint_t child_flags;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv, physnum;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Stop implementing the HPINFOSEARCH flag */
269473047d747f7815af570197e4ef7322d3632cEvan Yan child_flags = flags & ~(HPINFOSEARCH);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Clear lists of discovered ports and connections */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) memset(&ports, 0, sizeof (hp_node_list_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) memset(&connections, 0, sizeof (hp_node_list_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Scan virtual ports.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If a connection is specified and it matches a virtual port,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * this will build the branch associated with that connection.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Else, this will only build branches for virtual ports that
269473047d747f7815af570197e4ef7322d3632cEvan Yan * are not associated with a physical connector.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (hp = DI_HP_NIL; (hp = di_hp_next(dev, hp)) != DI_HP_NIL; ) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Ignore connectors */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (di_hp_type(hp) != DDI_HP_CN_TYPE_VIRTUAL_PORT)
269473047d747f7815af570197e4ef7322d3632cEvan Yan continue;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Ignore ports associated with connectors, unless
269473047d747f7815af570197e4ef7322d3632cEvan Yan * a specific connection is being sought.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((connection == NULL) && (di_hp_depends_on(hp) != -1))
269473047d747f7815af570197e4ef7322d3632cEvan Yan continue;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* If a connection is specified, ignore non-matching ports */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((connection != NULL) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (strcmp(di_hp_name(hp), connection) != 0))
269473047d747f7815af570197e4ef7322d3632cEvan Yan continue;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Create a new port node */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node = new_hotplug_node(parent, hp)) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto fail;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add port node to connection list */
269473047d747f7815af570197e4ef7322d3632cEvan Yan node_list_add(&connections, node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add branch of child devices to port node */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((child_dev = di_hp_child(hp)) != DI_NODE_NIL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = copy_devices(node, child_dev, child_flags,
269473047d747f7815af570197e4ef7322d3632cEvan Yan &node->hp_child)) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto fail;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Scan physical connectors.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If a connection is specified, the results will be limited
269473047d747f7815af570197e4ef7322d3632cEvan Yan * only to the branch associated with that connection.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (hp = DI_HP_NIL; (hp = di_hp_next(dev, hp)) != DI_HP_NIL; ) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Ignore ports */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT)
269473047d747f7815af570197e4ef7322d3632cEvan Yan continue;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* If a connection is specified, ignore non-matching ports */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((connection != NULL) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (strcmp(di_hp_name(hp), connection) != 0))
269473047d747f7815af570197e4ef7322d3632cEvan Yan continue;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Create a new connector node */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node = new_hotplug_node(parent, hp)) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto fail;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add connector node to connection list */
269473047d747f7815af570197e4ef7322d3632cEvan Yan node_list_add(&connections, node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add branches of associated port nodes */
269473047d747f7815af570197e4ef7322d3632cEvan Yan physnum = di_hp_connection(hp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan port_hp = DI_HP_NIL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan while ((port_hp = di_hp_next(dev, port_hp)) != DI_HP_NIL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Ignore irrelevant connections */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (di_hp_depends_on(port_hp) != physnum)
269473047d747f7815af570197e4ef7322d3632cEvan Yan continue;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add new port node to port list */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((port_node = new_hotplug_node(node,
269473047d747f7815af570197e4ef7322d3632cEvan Yan port_hp)) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto fail;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan node_list_add(&ports, port_node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add branch of child devices */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((child_dev = di_hp_child(port_hp)) != DI_NODE_NIL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = copy_devices(port_node, child_dev,
269473047d747f7815af570197e4ef7322d3632cEvan Yan child_flags, &port_node->hp_child)) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto fail;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_child = ports.head;
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) memset(&ports, 0, sizeof (hp_node_list_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (connections.head == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENXIO);
269473047d747f7815af570197e4ef7322d3632cEvan Yan *retp = connections.head;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanfail:
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) hp_fini(ports.head);
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) hp_fini(connections.head);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * base_path()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Normalize the base path of a hotplug information snapshot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The caller must free the string that is allocated.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic char *
269473047d747f7815af570197e4ef7322d3632cEvan Yanbase_path(const char *path)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *base_path;
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t devices_len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan devices_len = strlen(S_DEVICES);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strncmp(path, S_DEVICES, devices_len) == 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan base_path = strdup(&path[devices_len]);
269473047d747f7815af570197e4ef7322d3632cEvan Yan else
269473047d747f7815af570197e4ef7322d3632cEvan Yan base_path = strdup(path);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (base_path);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * search_cb()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Callback function used by di_walk_node() to search for branches
269473047d747f7815af570197e4ef7322d3632cEvan Yan * of the libdevinfo snapshot that contain hotplug nodes.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*ARGSUSED*/
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yansearch_cb(di_node_t node, void *arg)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan di_node_t parent;
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint_t flags;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) di_node_private_set(node, (void *)(uintptr_t)0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (di_hp_next(node, DI_HP_NIL) == DI_HP_NIL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DI_WALK_CONTINUE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (parent = node; parent != DI_NODE_NIL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan parent = di_parent_node(parent)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan flags = (uint_t)(uintptr_t)di_node_private_get(parent);
269473047d747f7815af570197e4ef7322d3632cEvan Yan flags |= HPINFOSEARCH;
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) di_node_private_set(parent, (void *)(uintptr_t)flags);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DI_WALK_CONTINUE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * check_search()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Check if a device node was marked by an initial search pass.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yancheck_search(di_node_t dev, uint_t flags)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint_t dev_flags;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (flags & HPINFOSEARCH) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_flags = (uint_t)(uintptr_t)di_node_private_get(dev);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((dev_flags & HPINFOSEARCH) == 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * node_list_add()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Utility function to append one node to a list of hotplug nodes.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void
269473047d747f7815af570197e4ef7322d3632cEvan Yannode_list_add(hp_node_list_t *listp, hp_node_t node)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (listp->prev != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan listp->prev->hp_sibling = node;
269473047d747f7815af570197e4ef7322d3632cEvan Yan else
269473047d747f7815af570197e4ef7322d3632cEvan Yan listp->head = node;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan listp->prev = node;
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * new_device_node()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Build a new hotplug node based on a specified devinfo node.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic hp_node_t
269473047d747f7815af570197e4ef7322d3632cEvan Yannew_device_node(hp_node_t parent, di_node_t dev)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t node;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *node_name, *bus_addr;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char name[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan node = (hp_node_t)calloc(1, sizeof (struct hp_node));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_parent = parent;
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_type = HP_NODE_DEVICE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan node_name = di_node_name(dev);
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_addr = di_bus_addr(dev);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (bus_addr && (strlen(bus_addr) > 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (snprintf(name, sizeof (name), "%s@%s", node_name,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_addr) >= sizeof (name)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Path too long for device node.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_name = strdup(name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_name = strdup(node_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * new_hotplug_node()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Build a new hotplug node based on a specified devinfo hotplug node.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic hp_node_t
269473047d747f7815af570197e4ef7322d3632cEvan Yannew_hotplug_node(hp_node_t parent, di_hp_t hp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t node;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *s;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan node = (hp_node_t)calloc(1, sizeof (struct hp_node));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_parent = parent;
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_state = di_hp_state(hp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_last_change = di_hp_last_change(hp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((s = di_hp_name(hp)) != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_name = strdup(s);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((s = di_hp_description(hp)) != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_description = strdup(s);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT)
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_type = HP_NODE_PORT;
269473047d747f7815af570197e4ef7322d3632cEvan Yan else
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_type = HP_NODE_CONNECTOR;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}