/*
* 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 <pthread.h>
#include <alloca.h>
#include <libnvpair.h>
#include <libhotplug.h>
#include <libhotplug_impl.h>
#include "hotplugd_impl.h"
/*
* All operations affecting kernel state are serialized.
*/
/*
* Local functions.
*/
static int pack_properties(const char *, ddi_hp_property_t *);
static void unpack_properties(ddi_hp_property_t *, char **);
static void free_properties(ddi_hp_property_t *);
/*
* changestate()
*
* Perform a state change operation.
*
* NOTE: all operations are serialized, using a global lock.
*/
int
{
int rv;
dprintf("changestate(path=%s, connection=%s, state=0x%x, flags=0x%x)\n",
/* Initialize results */
*old_statep = -1;
(void) pthread_mutex_lock(&hotplug_lock);
/* Get an information snapshot, without usage details */
(void) pthread_mutex_unlock(&hotplug_lock);
return (rv);
}
/* Record current state (used in hotplugd_door.c for auditing) */
/* Check if RCM interactions are required */
/* If RCM is required, perform RCM offline */
if (use_rcm) {
dprintf("changestate: RCM offline is required.\n");
/* Get RCM resources */
dprintf("changestate: rcm_resources() failed.\n");
(void) pthread_mutex_unlock(&hotplug_lock);
return (rv);
}
/* Request RCM offline */
dprintf("changestate: rcm_offline() failed.\n");
(void) pthread_mutex_unlock(&hotplug_lock);
return (rv);
}
}
/* The information snapshot is no longer needed */
/* Stop now if QUERY flag was specified */
dprintf("changestate: operation was QUERY only.\n");
(void) pthread_mutex_unlock(&hotplug_lock);
return (0);
}
/* Do state change in kernel */
rv = 0;
/*
* If RCM is required, then perform an RCM online or RCM remove
* operation. Which depends upon if modctl succeeded or failed.
*/
/* RCM online if failure, or RCM remove if successful */
if (rv == 0)
else
/* RCM resources no longer required */
}
(void) pthread_mutex_unlock(&hotplug_lock);
return (rv);
}
/*
* private_options()
*
*/
int
{
int rv;
dprintf("private_options(path=%s, connection=%s, options='%s')\n",
/* Initialize property arguments */
dprintf("private_options: failed to pack properties.\n");
return (rv);
}
/* Initialize results */
dprintf("private_options: failed to allocate buffer.\n");
return (ENOMEM);
}
/* Lock hotplug */
(void) pthread_mutex_lock(&hotplug_lock);
/* Perform the command */
rv = 0;
if (cmd == HP_CMD_GETPRIVATE) {
} else {
}
/* Unlock hotplug */
(void) pthread_mutex_unlock(&hotplug_lock);
/* Parse results */
if (rv == 0) {
}
/* Cleanup */
return (rv);
}
/*
* check_rcm_required()
*
* Given the root of a changestate operation and the target
* state, determine if RCM interactions will be required.
*/
static boolean_t
{
/*
* RCM is required when transitioning an ENABLED
* connector to a non-ENABLED state.
*/
return (B_TRUE);
/*
* RCM is required when transitioning an OPERATIONAL
* port to a non-OPERATIONAL state.
*/
return (B_TRUE);
/* RCM is not required in other cases */
return (B_FALSE);
}
/*
* pack_properties()
*
* construct the structure containing a packed nvlist that
* contains the specified options.
*/
static int
{
/* Initialize results */
/* Do nothing if options string is empty */
dprintf("pack_properties: options string is empty.\n");
return (ENOENT);
}
/* Avoid modifying the input string by using a copy on the stack */
log_err("Failed to allocate buffer for private options.\n");
return (ENOMEM);
}
/* Allocate the nvlist */
log_err("Failed to allocate private options nvlist.\n");
return (ENOMEM);
}
/* Add each option from the string */
*next = '\0';
next++;
}
*value = '\0';
value++;
} else {
value = "";
}
/* Add the option to the nvlist */
log_err("Failed to add private option to nvlist.\n");
return (EFAULT);
}
}
/* Pack the nvlist */
len = 0;
log_err("Failed to pack private options nvlist.\n");
return (EFAULT);
}
/* Save results */
/* The nvlist is no longer needed */
return (0);
}
/*
* unpack_properties()
*
* Given a structure possibly containing a packed nvlist of
* bus private options, unpack the nvlist and expand its
* contents into an options string.
*/
static void
{
/* Initialize results */
/* Do nothing if properties do not exist */
dprintf("unpack_properties: no properties exist.\n");
return;
}
/* Unpack the nvlist */
log_err("Failed to unpack private options nvlist.\n");
return;
}
/* Compute the size of the options string */
/* Skip the command, and anything not a string */
continue;
/* Account for '=' signs, commas, and terminating NULL */
}
/* Allocate the resulting options string */
log_err("Failed to allocate private options string.\n");
return;
}
first_flag = B_TRUE;
/* Skip the command, and anything not a string */
continue;
if (!first_flag)
}
}
/* The unpacked nvlist is no longer needed */
/* Save results */
}
/*
* free_properties()
*
* Destroy a structure containing a packed nvlist of bus
* private properties.
*/
static void
{
if (prop) {
if (prop->nvlist_buf)
}
}