269473047d747f7815af570197e4ef7322d3632cEvan Yan * CDDL HEADER START
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 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
269473047d747f7815af570197e4ef7322d3632cEvan Yan * See the License for the specific language governing permissions
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and limitations under the License.
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 * CDDL HEADER END
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Use is subject to license terms.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * All operations affecting kernel state are serialized.
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic pthread_mutex_t hotplug_lock = PTHREAD_MUTEX_INITIALIZER;
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Local functions.
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic boolean_t check_rcm_required(hp_node_t, int);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pack_properties(const char *, ddi_hp_property_t *);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void unpack_properties(ddi_hp_property_t *, char **);
269473047d747f7815af570197e4ef7322d3632cEvan Yan * changestate()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Perform a state change operation.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * NOTE: all operations are serialized, using a global lock.
269473047d747f7815af570197e4ef7322d3632cEvan Yanchangestate(const char *path, const char *connection, int state, uint_t flags,
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("changestate(path=%s, connection=%s, state=0x%x, flags=0x%x)\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get an information snapshot, without usage details */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = getinfo(path, connection, 0, &root)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("changestate: getinfo() failed (%s)\n", strerror(rv));
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Record current state (used in hotplugd_door.c for auditing) */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check if RCM interactions are required */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* If RCM is required, perform RCM offline */
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("changestate: RCM offline is required.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get RCM resources */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Request RCM offline */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* The information snapshot is no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Stop now if QUERY flag was specified */
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("changestate: operation was QUERY only.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Do state change in kernel */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (modctl(MODHPOPS, MODHPOPS_CHANGE_STATE, path, connection, state))
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("changestate: modctl(MODHPOPS_CHANGE_STATE) = %d.\n", rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If RCM is required, then perform an RCM online or RCM remove
269473047d747f7815af570197e4ef7322d3632cEvan Yan * operation. Which depends upon if modctl succeeded or failed.
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* RCM online if failure, or RCM remove if successful */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* RCM resources no longer required */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * private_options()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Implement set/get of bus private options.
269473047d747f7815af570197e4ef7322d3632cEvan Yanprivate_options(const char *path, const char *connection, hp_cmd_t cmd,
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("private_options(path=%s, connection=%s, options='%s')\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize property arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("private_options: failed to pack properties.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) memset(&results, 0, sizeof (ddi_hp_property_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan results.nvlist_buf = (char *)calloc(1, HP_PRIVATE_BUF_SZ);
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("private_options: failed to allocate buffer.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Lock hotplug */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Perform the command */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (modctl(MODHPOPS, MODHPOPS_BUS_GET, path, connection,
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("private_options: modctl(MODHPOPS_BUS_GET) = %d\n", rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (modctl(MODHPOPS, MODHPOPS_BUS_SET, path, connection,
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("private_options: modctl(MODHPOPS_BUS_SET) = %d\n", rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Unlock hotplug */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Parse results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Cleanup */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * check_rcm_required()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Given the root of a changestate operation and the target
269473047d747f7815af570197e4ef7322d3632cEvan Yan * state, determine if RCM interactions will be required.
269473047d747f7815af570197e4ef7322d3632cEvan Yancheck_rcm_required(hp_node_t root, int target_state)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * RCM is required when transitioning an ENABLED
269473047d747f7815af570197e4ef7322d3632cEvan Yan * connector to a non-ENABLED state.
269473047d747f7815af570197e4ef7322d3632cEvan Yan HP_IS_ENABLED(root->hp_state) && !HP_IS_ENABLED(target_state))
269473047d747f7815af570197e4ef7322d3632cEvan Yan * RCM is required when transitioning an OPERATIONAL
269473047d747f7815af570197e4ef7322d3632cEvan Yan * port to a non-OPERATIONAL state.
269473047d747f7815af570197e4ef7322d3632cEvan Yan HP_IS_ONLINE(root->hp_state) && HP_IS_OFFLINE(target_state))
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* RCM is not required in other cases */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * pack_properties()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Given a specified set/get command and an options string,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * construct the structure containing a packed nvlist that
269473047d747f7815af570197e4ef7322d3632cEvan Yan * contains the specified options.
269473047d747f7815af570197e4ef7322d3632cEvan Yanpack_properties(const char *options, ddi_hp_property_t *prop)
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) memset(prop, 0, sizeof (ddi_hp_property_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Do nothing if options string is empty */
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("pack_properties: options string is empty.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Avoid modifying the input string by using a copy on the stack */
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Failed to allocate buffer for private options.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate the nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Failed to allocate private options nvlist.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add each option from the string */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Isolate current name/value, and locate the next */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Split current name/value pair */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add the option to the nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Failed to add private option to nvlist.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Pack the nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Failed to pack private options nvlist.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Save results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* The nvlist is no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan * unpack_properties()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Given a structure possibly containing a packed nvlist of
269473047d747f7815af570197e4ef7322d3632cEvan Yan * bus private options, unpack the nvlist and expand its
269473047d747f7815af570197e4ef7322d3632cEvan Yan * contents into an options string.
269473047d747f7815af570197e4ef7322d3632cEvan Yanunpack_properties(ddi_hp_property_t *prop, char **optionsp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Do nothing if properties do not exist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((prop->nvlist_buf == NULL) || (prop->buf_size == 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("unpack_properties: no properties exist.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Unpack the nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_unpack(prop->nvlist_buf, prop->buf_size, &nvl, 0) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Failed to unpack private options nvlist.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Compute the size of the options string */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (len = 0, nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Skip the command, and anything not a string */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Account for '=' signs, commas, and terminating NULL */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate the resulting options string */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((options = (char *)calloc(len, sizeof (char))) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Failed to allocate private options string.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Copy name/value pairs into the options string */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Skip the command, and anything not a string */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* The unpacked nvlist is no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Save results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * free_properties()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Destroy a structure containing a packed nvlist of bus
269473047d747f7815af570197e4ef7322d3632cEvan Yan * private properties.
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) memset(prop, 0, sizeof (ddi_hp_property_t));