hotplugd_rcm.c revision 269473047d747f7815af570197e4ef7322d3632c
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <librcm.h>
#include <libhotplug.h>
#include <libhotplug_impl.h>
#include "hotplugd_impl.h"
/*
* Define structures for a path-to-usage lookup table.
*/
typedef struct info_entry {
char *rsrc;
char *usage;
struct info_entry *next;
} info_entry_t;
typedef struct {
char *path;
} info_table_t;
/*
* Define callback argument used when getting resources.
*/
typedef struct {
int error;
int n_rsrcs;
char **rsrcs;
char path[MAXPATHLEN];
char connection[MAXPATHLEN];
char dev_path[MAXPATHLEN];
/*
* Define callback argument used when merging info.
*/
typedef struct {
int error;
char path[MAXPATHLEN];
char connection[MAXPATHLEN];
/*
* Local functions.
*/
size_t *table_lenp);
static int compare_info(const void *a, const void *b);
/*
* copy_usage()
*
* Given an information snapshot, get the corresponding
* RCM usage information and merge it into the snapshot.
*/
int
{
int rv;
/* Get resource names */
return (rv);
}
/* Do nothing if no resources */
return (0);
/* Get RCM usage information */
return (rv);
}
/* Done with resource names */
/* If there is RCM usage information, merge it in */
return (rv);
}
return (0);
}
/*
* rcm_resources()
*
* Given the root of a hotplug information snapshot,
* construct a list of RCM compatible resource names.
*/
int
{
/* Initialize results */
/* Traverse snapshot to get resources */
/* Check for errors */
}
/* Success */
return (0);
}
/*
* free_rcm_resources()
*
* Free a table of RCM resource names.
*/
void
free_rcm_resources(char **rsrcs)
{
int i;
}
}
/*
* rcm_offline()
*
* Implement an RCM offline request.
*
* NOTE: errors from RCM will be merged into the snapshot.
*/
int
{
int rv = 0;
dprintf("rcm_offline()\n");
/* Set flags */
/* Allocate RCM handle */
return (EFAULT);
}
/* Request RCM offline */
&info) != RCM_SUCCESS)
/* RCM handle is no longer needed */
(void) rcm_free_handle(handle);
/*
* Check if RCM returned any information tuples. If so,
* then also check if the RCM operation failed, and possibly
* merge the RCM info into the caller's hotplug snapshot.
*/
if (rv != 0)
}
return (rv);
}
/*
* rcm_online()
*
* Implement an RCM online notification.
*/
void
rcm_online(char **rsrcs)
{
dprintf("rcm_online()\n");
return;
}
(void) rcm_free_handle(handle);
}
/*
* rcm_remove()
*
* Implement an RCM remove notification.
*/
void
rcm_remove(char **rsrcs)
{
dprintf("rcm_remove()\n");
return;
}
(void) rcm_free_handle(handle);
}
/*
* get_rcm_usage()
*
* Lookup usage information for a set of resources from RCM.
*/
static int
{
int rv = 0;
/* No-op if no RCM resources */
return (0);
/* Allocate RCM handle */
return (EFAULT);
}
/* Get usage information from RCM */
&info) != RCM_SUCCESS) {
log_err("Failed to get RCM information (%s)\n",
}
/* RCM handle is no longer needed */
(void) rcm_free_handle(handle);
return (rv);
}
/*
* merge_rcm_info()
*
* Merge RCM information into a hotplug information snapshot.
* First a lookup table is built to map lists of RCM usage to
* pathnames. Then during a full traversal of the snapshot,
* the lookup table is used for each node to find matching
* RCM info tuples for each path in the snapshot.
*/
static int
{
int rv;
/* Build a lookup table, mapping paths to usage information */
return (rv);
}
/* Stop if no valid entries were inserted in table */
log_err("Unable to gather RCM usage.\n");
return (0);
}
/* Initialize callback argument */
/* Perform a merge traversal */
/* Done with the table */
/* Check for errors */
return (rv);
}
return (0);
}
/*
* resource_callback()
*
* A callback function for hp_traverse() that builds an RCM
* compatible list of resource path names. The array has
* been pre-allocated based on results from the related
* callback resource_count_callback().
*/
static int
{
char **new_rsrcs;
int type;
/* Get node type */
/* Prune OFFLINE ports */
return (HP_WALK_PRUNECHILD);
/* Skip past non-devices */
if (type != HP_NODE_DEVICE)
return (HP_WALK_CONTINUE);
/* Lookup resource path */
log_err("Cannot get RCM resource path.\n");
return (HP_WALK_TERMINATE);
}
/* Insert "/devices" to path name */
/*
* Grow resource array to accomodate new /devices path.
* NOTE: include an extra NULL pointer at end of array.
*/
else
} else {
log_err("Cannot allocate RCM resource array.\n");
return (HP_WALK_TERMINATE);
}
/* Initialize new entries */
/* Check for errors */
log_err("Cannot allocate RCM resource path.\n");
return (HP_WALK_TERMINATE);
}
/* Increment resource count */
/* Do not visit children */
return (HP_WALK_PRUNECHILD);
}
/*
* merge_callback()
*
* A callback function for hp_traverse() that merges RCM information
* tuples into an existing hotplug information snapshot. The RCM
* information will be turned into HP_NODE_USAGE nodes.
*/
static int
{
int rv;
/* Only process device nodes (other nodes cannot have usage) */
return (HP_WALK_CONTINUE);
/* Get path of current node, using buffer provided in 'arg' */
return (HP_WALK_TERMINATE);
}
/* Check the lookup table for associated usage */
return (HP_WALK_CONTINUE);
/* Usage information was found. Append HP_NODE_USAGE nodes. */
/* Allocate a new usage node */
log_err("Cannot allocate hotplug usage node.\n");
return (HP_WALK_TERMINATE);
}
/* Initialize the usage node's contents */
log_err("Cannot allocate hotplug usage node name.\n");
return (HP_WALK_TERMINATE);
}
log_err("Cannot allocate hotplug usage node info.\n");
return (HP_WALK_TERMINATE);
}
/* Link the usage node as a child of the device node */
}
return (HP_WALK_CONTINUE);
}
/*
* build_table()
*
* Build a lookup table that will be used to map paths to their
* corresponding RCM information tuples.
*/
static int
{
const char *rsrc;
const char *usage;
char path[MAXPATHLEN];
/* Initialize results */
*table_lenp = 0;
/* Count the RCM info tuples to determine the table's size */
table_len = 0;
table_len++;
/* If the table would be empty, then do nothing */
if (table_len == 0)
return (ENOENT);
/* Allocate the lookup table */
return (ENOMEM);
/*
* Fill in the lookup table. Fill one slot in the table
* for each device path that has a set of associated RCM
* information tuples. In some cases multiple tuples will
* be joined together within the same slot.
*/
table_len = 0;
/*
* Extract RCM resource name and usage description.
*
* NOTE: skip invalid tuples to return as much as possible.
*/
log_err("RCM returned invalid resource or usage.\n");
continue;
}
/*
* Try to convert the RCM resource name to a hotplug path.
* If conversion succeeds and this path differs from the
* current slot in the table, then initialize the next
* slot in the table.
*/
log_err("Cannot build info table slot.\n");
return (ENOMEM);
}
table_len++;
}
/* Append current usage to entry list in the current slot */
/* Allocate new entry */
log_err("Cannot allocate info table entry.\n");
return (ENOMEM);
}
/* Link entry into current slot list */
/* Initialize entry values */
log_err("Cannot build info table entry.\n");
return (ENOMEM);
}
}
}
/* Check if valid entries were inserted in table */
if (table_len == 0) {
return (0);
}
/* Sort the lookup table by hotplug path */
/* Done */
*table_lenp = table_len;
return (0);
}
/*
* free_table()
*
* Destroy a lookup table.
*/
static void
{
int index;
}
}
}
}
/*
* rsrc2path()
*
* Convert from an RCM resource name to a hotplug device path.
*/
static int
{
char *s;
char tmp[MAXPATHLEN];
/* Only convert /dev and /devices paths */
/* Follow symbolic links for /dev paths */
log_err("Cannot resolve RCM resource (%s)\n",
return (-1);
}
/* Remove the leading "/devices" part */
/* Remove any trailing minor node part */
*s = '\0';
/* Successfully converted */
return (0);
}
/* Not converted */
return (-1);
}
/*
* compare_info()
*
* Compare two slots in the lookup table that maps paths to usage.
*
* NOTE: for use with qsort() and bsearch().
*/
static int
compare_info(const void *a, const void *b)
{
}