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/*
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 <unistd.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <errno.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <string.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <librcm.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 structures for a path-to-usage lookup table.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yantypedef struct info_entry {
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *rsrc;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *usage;
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct info_entry *next;
269473047d747f7815af570197e4ef7322d3632cEvan Yan} info_entry_t;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yantypedef struct {
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *path;
269473047d747f7815af570197e4ef7322d3632cEvan Yan info_entry_t *entries;
269473047d747f7815af570197e4ef7322d3632cEvan Yan} info_table_t;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Define callback argument used when getting resources.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yantypedef struct {
269473047d747f7815af570197e4ef7322d3632cEvan Yan int error;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int n_rsrcs;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char **rsrcs;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char path[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan char connection[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan char dev_path[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan} resource_cb_arg_t;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Define callback argument used when merging info.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yantypedef struct {
269473047d747f7815af570197e4ef7322d3632cEvan Yan int error;
269473047d747f7815af570197e4ef7322d3632cEvan Yan info_table_t *table;
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t table_len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char path[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan char connection[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan} merge_cb_arg_t;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Local functions.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int merge_rcm_info(hp_node_t root, rcm_info_t *info);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int get_rcm_usage(char **rsrcs, rcm_info_t **info_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int build_table(rcm_info_t *info, info_table_t **tablep,
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t *table_lenp);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void free_table(info_table_t *table, size_t table_len);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int resource_callback(hp_node_t node, void *argp);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int merge_callback(hp_node_t node, void *argp);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int rsrc2path(const char *rsrc, char *path);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int compare_info(const void *a, const void *b);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * copy_usage()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Given an information snapshot, get the corresponding
269473047d747f7815af570197e4ef7322d3632cEvan Yan * RCM usage information and merge it into the snapshot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yancopy_usage(hp_node_t root)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_info_t *info = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char **rsrcs = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get resource names */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = rcm_resources(root, &rsrcs)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot get RCM resources (%s)\n", strerror(rv));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Do nothing if no resources */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rsrcs == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get RCM usage information */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = get_rcm_usage(rsrcs, &info)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot get RCM information (%s)\n", strerror(rv));
269473047d747f7815af570197e4ef7322d3632cEvan Yan free_rcm_resources(rsrcs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Done with resource names */
269473047d747f7815af570197e4ef7322d3632cEvan Yan free_rcm_resources(rsrcs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* If there is RCM usage information, merge it in */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (info != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = merge_rcm_info(root, info);
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_free_info(info);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * rcm_resources()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Given the root of a hotplug information snapshot,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * construct a list of RCM compatible resource names.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanrcm_resources(hp_node_t root, char ***rsrcsp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan resource_cb_arg_t arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan *rsrcsp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Traverse snapshot to get resources */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) memset(&arg, 0, sizeof (resource_cb_arg_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) hp_traverse(root, &arg, resource_callback);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check for errors */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (arg.error != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan free_rcm_resources(arg.rsrcs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (arg.error);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Success */
269473047d747f7815af570197e4ef7322d3632cEvan Yan *rsrcsp = arg.rsrcs;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * free_rcm_resources()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Free a table of RCM resource names.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanfree_rcm_resources(char **rsrcs)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan int i;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rsrcs != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (i = 0; rsrcs[i] != NULL; i++)
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(rsrcs[i]);
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(rsrcs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * rcm_offline()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Implement an RCM offline request.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * NOTE: errors from RCM will be merged into the snapshot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanrcm_offline(char **rsrcs, uint_t flags, hp_node_t root)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_handle_t *handle;
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_info_t *info = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint_t rcm_flags = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("rcm_offline()\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Set flags */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (flags & HPFORCE)
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_flags |= RCM_FORCE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (flags & HPQUERY)
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_flags |= RCM_QUERY;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate RCM handle */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rcm_alloc_handle(NULL, 0, NULL, &handle) != RCM_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot allocate RCM handle (%s)\n", strerror(errno));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EFAULT);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Request RCM offline */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rcm_request_offline_list(handle, rsrcs, rcm_flags,
269473047d747f7815af570197e4ef7322d3632cEvan Yan &info) != RCM_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = EBUSY;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* RCM handle is no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) rcm_free_handle(handle);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Check if RCM returned any information tuples. If so,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * then also check if the RCM operation failed, and possibly
269473047d747f7815af570197e4ef7322d3632cEvan Yan * merge the RCM info into the caller's hotplug snapshot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (info != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) merge_rcm_info(root, info);
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_free_info(info);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * rcm_online()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Implement an RCM online notification.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanrcm_online(char **rsrcs)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_handle_t *handle;
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_info_t *info = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("rcm_online()\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rcm_alloc_handle(NULL, 0, NULL, &handle) != RCM_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot allocate RCM handle (%s)\n", strerror(errno));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) rcm_notify_online_list(handle, rsrcs, 0, &info);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) rcm_free_handle(handle);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (info != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_free_info(info);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * rcm_remove()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Implement an RCM remove notification.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanrcm_remove(char **rsrcs)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_handle_t *handle;
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_info_t *info = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("rcm_remove()\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rcm_alloc_handle(NULL, 0, NULL, &handle) != RCM_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot allocate RCM handle (%s)\n", strerror(errno));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) rcm_notify_remove_list(handle, rsrcs, 0, &info);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) rcm_free_handle(handle);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (info != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_free_info(info);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * get_rcm_usage()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Lookup usage information for a set of resources from RCM.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanget_rcm_usage(char **rsrcs, rcm_info_t **info_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_handle_t *handle;
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_info_t *info = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* No-op if no RCM resources */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rsrcs == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate RCM handle */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rcm_alloc_handle(NULL, RCM_NOPID, NULL, &handle) != RCM_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot allocate RCM handle (%s)\n", strerror(errno));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EFAULT);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get usage information from RCM */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rcm_get_info_list(handle, rsrcs,
269473047d747f7815af570197e4ef7322d3632cEvan Yan RCM_INCLUDE_DEPENDENT | RCM_INCLUDE_SUBTREE,
269473047d747f7815af570197e4ef7322d3632cEvan Yan &info) != RCM_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Failed to get RCM information (%s)\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan strerror(errno));
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = EFAULT;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* RCM handle is no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) rcm_free_handle(handle);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *info_p = info;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * merge_rcm_info()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Merge RCM information into a hotplug information snapshot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * First a lookup table is built to map lists of RCM usage to
269473047d747f7815af570197e4ef7322d3632cEvan Yan * pathnames. Then during a full traversal of the snapshot,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * the lookup table is used for each node to find matching
269473047d747f7815af570197e4ef7322d3632cEvan Yan * RCM info tuples for each path in the snapshot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanmerge_rcm_info(hp_node_t root, rcm_info_t *info)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan merge_cb_arg_t arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan info_table_t *table;
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t table_len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Build a lookup table, mapping paths to usage information */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = build_table(info, &table, &table_len)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot build RCM lookup table (%s)\n", strerror(rv));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Stop if no valid entries were inserted in table */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((table == NULL) || (table_len == 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Unable to gather RCM usage.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize callback argument */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) memset(&arg, 0, sizeof (merge_cb_arg_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg.table = table;
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg.table_len = table_len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Perform a merge traversal */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) hp_traverse(root, (void *)&arg, merge_callback);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Done with the table */
269473047d747f7815af570197e4ef7322d3632cEvan Yan free_table(table, table_len);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check for errors */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (arg.error != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot merge RCM information (%s)\n", strerror(rv));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * resource_callback()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * A callback function for hp_traverse() that builds an RCM
269473047d747f7815af570197e4ef7322d3632cEvan Yan * compatible list of resource path names. The array has
269473047d747f7815af570197e4ef7322d3632cEvan Yan * been pre-allocated based on results from the related
269473047d747f7815af570197e4ef7322d3632cEvan Yan * callback resource_count_callback().
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanresource_callback(hp_node_t node, void *argp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan resource_cb_arg_t *arg = (resource_cb_arg_t *)argp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char **new_rsrcs;
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t new_size;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int type;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get node type */
269473047d747f7815af570197e4ef7322d3632cEvan Yan type = hp_type(node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Prune OFFLINE ports */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((type == HP_NODE_PORT) && HP_IS_OFFLINE(hp_state(node)))
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (HP_WALK_PRUNECHILD);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Skip past non-devices */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (type != HP_NODE_DEVICE)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (HP_WALK_CONTINUE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Lookup resource path */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (hp_path(node, arg->path, arg->connection) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot get RCM resource path.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg->error = EFAULT;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (HP_WALK_TERMINATE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Insert "/devices" to path name */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) snprintf(arg->dev_path, MAXPATHLEN, "/devices%s", arg->path);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Grow resource array to accomodate new /devices path.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * NOTE: include an extra NULL pointer at end of array.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan new_size = (arg->n_rsrcs + 2) * sizeof (char *);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (arg->rsrcs == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan new_rsrcs = (char **)malloc(new_size);
269473047d747f7815af570197e4ef7322d3632cEvan Yan else
269473047d747f7815af570197e4ef7322d3632cEvan Yan new_rsrcs = (char **)realloc(arg->rsrcs, new_size);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (new_rsrcs != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg->rsrcs = new_rsrcs;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot allocate RCM resource array.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg->error = ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (HP_WALK_TERMINATE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize new entries */
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg->rsrcs[arg->n_rsrcs] = strdup(arg->dev_path);
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg->rsrcs[arg->n_rsrcs + 1] = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check for errors */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (arg->rsrcs[arg->n_rsrcs] == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot allocate RCM resource path.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg->error = ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (HP_WALK_TERMINATE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Increment resource count */
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg->n_rsrcs += 1;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Do not visit children */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (HP_WALK_PRUNECHILD);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * merge_callback()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * A callback function for hp_traverse() that merges RCM information
269473047d747f7815af570197e4ef7322d3632cEvan Yan * tuples into an existing hotplug information snapshot. The RCM
269473047d747f7815af570197e4ef7322d3632cEvan Yan * information will be turned into HP_NODE_USAGE nodes.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanmerge_callback(hp_node_t node, void *argp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan merge_cb_arg_t *arg = (merge_cb_arg_t *)argp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t usage;
269473047d747f7815af570197e4ef7322d3632cEvan Yan info_table_t lookup;
269473047d747f7815af570197e4ef7322d3632cEvan Yan info_table_t *slot;
269473047d747f7815af570197e4ef7322d3632cEvan Yan info_entry_t *entry;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Only process device nodes (other nodes cannot have usage) */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (hp_type(node) != HP_NODE_DEVICE)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (HP_WALK_CONTINUE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get path of current node, using buffer provided in 'arg' */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = hp_path(node, arg->path, arg->connection)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot lookup hotplug path (%s)\n", strerror(rv));
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg->error = rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (HP_WALK_TERMINATE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check the lookup table for associated usage */
269473047d747f7815af570197e4ef7322d3632cEvan Yan lookup.path = arg->path;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((slot = bsearch(&lookup, arg->table, arg->table_len,
269473047d747f7815af570197e4ef7322d3632cEvan Yan sizeof (info_table_t), compare_info)) == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (HP_WALK_CONTINUE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Usage information was found. Append HP_NODE_USAGE nodes. */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (entry = slot->entries; entry != NULL; entry = entry->next) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate a new usage node */
269473047d747f7815af570197e4ef7322d3632cEvan Yan usage = (hp_node_t)calloc(1, sizeof (struct hp_node));
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (usage == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot allocate hotplug usage node.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg->error = ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (HP_WALK_TERMINATE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize the usage node's contents */
269473047d747f7815af570197e4ef7322d3632cEvan Yan usage->hp_type = HP_NODE_USAGE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((usage->hp_name = strdup(entry->rsrc)) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot allocate hotplug usage node name.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(usage);
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg->error = ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (HP_WALK_TERMINATE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((usage->hp_usage = strdup(entry->usage)) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot allocate hotplug usage node info.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(usage->hp_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(usage);
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg->error = ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (HP_WALK_TERMINATE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Link the usage node as a child of the device node */
269473047d747f7815af570197e4ef7322d3632cEvan Yan usage->hp_parent = node;
269473047d747f7815af570197e4ef7322d3632cEvan Yan usage->hp_sibling = node->hp_child;
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_child = usage;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (HP_WALK_CONTINUE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * build_table()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Build a lookup table that will be used to map paths to their
269473047d747f7815af570197e4ef7322d3632cEvan Yan * corresponding RCM information tuples.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanbuild_table(rcm_info_t *info, info_table_t **tablep, size_t *table_lenp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_info_tuple_t *tuple;
269473047d747f7815af570197e4ef7322d3632cEvan Yan info_entry_t *entry;
269473047d747f7815af570197e4ef7322d3632cEvan Yan info_table_t *slot;
269473047d747f7815af570197e4ef7322d3632cEvan Yan info_table_t *table;
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t table_len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan const char *rsrc;
269473047d747f7815af570197e4ef7322d3632cEvan Yan const char *usage;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char path[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan *tablep = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan *table_lenp = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Count the RCM info tuples to determine the table's size */
269473047d747f7815af570197e4ef7322d3632cEvan Yan table_len = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (tuple = NULL; (tuple = rcm_info_next(info, tuple)) != NULL; )
269473047d747f7815af570197e4ef7322d3632cEvan Yan table_len++;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* If the table would be empty, then do nothing */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (table_len == 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOENT);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate the lookup table */
269473047d747f7815af570197e4ef7322d3632cEvan Yan table = (info_table_t *)calloc(table_len, sizeof (info_table_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (table == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Fill in the lookup table. Fill one slot in the table
269473047d747f7815af570197e4ef7322d3632cEvan Yan * for each device path that has a set of associated RCM
269473047d747f7815af570197e4ef7322d3632cEvan Yan * information tuples. In some cases multiple tuples will
269473047d747f7815af570197e4ef7322d3632cEvan Yan * be joined together within the same slot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan table_len = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (tuple = NULL; (tuple = rcm_info_next(info, tuple)) != NULL; ) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Extract RCM resource name and usage description.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * NOTE: skip invalid tuples to return as much as possible.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (((rsrc = rcm_info_rsrc(tuple)) == NULL) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan ((usage = rcm_info_info(tuple)) == NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("RCM returned invalid resource or usage.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan continue;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Try to convert the RCM resource name to a hotplug path.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If conversion succeeds and this path differs from the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * current slot in the table, then initialize the next
269473047d747f7815af570197e4ef7322d3632cEvan Yan * slot in the table.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rsrc2path(rsrc, path) == 0) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan ((slot == NULL) || (strcmp(slot->path, path) != 0))) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot = &table[table_len];
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((slot->path = strdup(path)) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot build info table slot.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan free_table(table, table_len);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan table_len++;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Append current usage to entry list in the current slot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate new entry */
269473047d747f7815af570197e4ef7322d3632cEvan Yan entry = (info_entry_t *)malloc(sizeof (info_entry_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (entry == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot allocate info table entry.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan free_table(table, table_len);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Link entry into current slot list */
269473047d747f7815af570197e4ef7322d3632cEvan Yan entry->next = slot->entries;
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot->entries = entry;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize entry values */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (((entry->rsrc = strdup(rsrc)) == NULL) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan ((entry->usage = strdup(usage)) == NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot build info table entry.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan free_table(table, table_len);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check if valid entries were inserted in table */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (table_len == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(table);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Sort the lookup table by hotplug path */
269473047d747f7815af570197e4ef7322d3632cEvan Yan qsort(table, table_len, sizeof (info_table_t), compare_info);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Done */
269473047d747f7815af570197e4ef7322d3632cEvan Yan *tablep = table;
269473047d747f7815af570197e4ef7322d3632cEvan Yan *table_lenp = table_len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * free_table()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Destroy a lookup table.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void
269473047d747f7815af570197e4ef7322d3632cEvan Yanfree_table(info_table_t *table, size_t table_len)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan info_entry_t *entry;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int index;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (table != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (index = 0; index < table_len; index++) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (table[index].path != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(table[index].path);
269473047d747f7815af570197e4ef7322d3632cEvan Yan while (table[index].entries != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan entry = table[index].entries;
269473047d747f7815af570197e4ef7322d3632cEvan Yan table[index].entries = entry->next;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (entry->rsrc != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(entry->rsrc);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (entry->usage != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(entry->usage);
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(entry);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(table);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * rsrc2path()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Convert from an RCM resource name to a hotplug device path.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanrsrc2path(const char *rsrc, char *path)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *s;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char tmp[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Only convert /dev and /devices paths */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strncmp(rsrc, "/dev", 4) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Follow symbolic links for /dev paths */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (realpath(rsrc, tmp) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot resolve RCM resource (%s)\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan strerror(errno));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (-1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Remove the leading "/devices" part */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) strlcpy(path, &tmp[strlen(S_DEVICES)], MAXPATHLEN);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Remove any trailing minor node part */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((s = strrchr(path, ':')) != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan *s = '\0';
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Successfully converted */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Not converted */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (-1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * compare_info()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Compare two slots in the lookup table that maps paths to usage.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * NOTE: for use with qsort() and bsearch().
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yancompare_info(const void *a, const void *b)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan info_table_t *slot_a = (info_table_t *)a;
269473047d747f7815af570197e4ef7322d3632cEvan Yan info_table_t *slot_b = (info_table_t *)b;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (strcmp(slot_a->path, slot_b->path));
269473047d747f7815af570197e4ef7322d3632cEvan Yan}