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 <pthread.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <alloca.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <libnvpair.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <libhotplug.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <libhotplug_impl.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/types.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sunddi.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/ddi_hp.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/modctl.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include "hotplugd_impl.h"
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * All operations affecting kernel state are serialized.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic pthread_mutex_t hotplug_lock = PTHREAD_MUTEX_INITIALIZER;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Local functions.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
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 Yanstatic void free_properties(ddi_hp_property_t *);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * changestate()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Perform a state change operation.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * NOTE: all operations are serialized, using a global lock.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanchangestate(const char *path, const char *connection, int state, uint_t flags,
269473047d747f7815af570197e4ef7322d3632cEvan Yan int *old_statep, hp_node_t *resultsp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t root = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char **rsrcs = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan boolean_t use_rcm = B_FALSE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("changestate(path=%s, connection=%s, state=0x%x, flags=0x%x)\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan path, connection, state, flags);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan *resultsp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan *old_statep = -1;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pthread_mutex_lock(&hotplug_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get an information snapshot, without usage details */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = getinfo(path, connection, 0, &root)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pthread_mutex_unlock(&hotplug_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("changestate: getinfo() failed (%s)\n", strerror(rv));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Record current state (used in hotplugd_door.c for auditing) */
269473047d747f7815af570197e4ef7322d3632cEvan Yan *old_statep = hp_state(root);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check if RCM interactions are required */
269473047d747f7815af570197e4ef7322d3632cEvan Yan use_rcm = check_rcm_required(root, state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* If RCM is required, perform RCM offline */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (use_rcm) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("changestate: RCM offline is required.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get RCM resources */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = rcm_resources(root, &rsrcs)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("changestate: rcm_resources() failed.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pthread_mutex_unlock(&hotplug_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_fini(root);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Request RCM offline */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rsrcs != NULL) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan ((rv = rcm_offline(rsrcs, flags, root)) != 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("changestate: rcm_offline() failed.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_online(rsrcs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pthread_mutex_unlock(&hotplug_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan free_rcm_resources(rsrcs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan *resultsp = root;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* The information snapshot is no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_fini(root);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Stop now if QUERY flag was specified */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (flags & HPQUERY) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("changestate: operation was QUERY only.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_online(rsrcs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pthread_mutex_unlock(&hotplug_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan free_rcm_resources(rsrcs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Do state change in kernel */
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (modctl(MODHPOPS, MODHPOPS_CHANGE_STATE, path, connection, state))
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = errno;
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("changestate: modctl(MODHPOPS_CHANGE_STATE) = %d.\n", rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
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 */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (use_rcm && (rsrcs != NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* RCM online if failure, or RCM remove if successful */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv == 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_remove(rsrcs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan else
269473047d747f7815af570197e4ef7322d3632cEvan Yan rcm_online(rsrcs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* RCM resources no longer required */
269473047d747f7815af570197e4ef7322d3632cEvan Yan free_rcm_resources(rsrcs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pthread_mutex_unlock(&hotplug_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *resultsp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * private_options()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Implement set/get of bus private options.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanprivate_options(const char *path, const char *connection, hp_cmd_t cmd,
269473047d747f7815af570197e4ef7322d3632cEvan Yan const char *options, char **resultsp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_property_t prop;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_property_t results;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *values = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("private_options(path=%s, connection=%s, options='%s')\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan path, connection, options);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize property arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = pack_properties(options, &prop)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("private_options: failed to pack properties.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) memset(&results, 0, sizeof (ddi_hp_property_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan results.buf_size = HP_PRIVATE_BUF_SZ;
269473047d747f7815af570197e4ef7322d3632cEvan Yan results.nvlist_buf = (char *)calloc(1, HP_PRIVATE_BUF_SZ);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (results.nvlist_buf == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("private_options: failed to allocate buffer.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan free_properties(&prop);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Lock hotplug */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pthread_mutex_lock(&hotplug_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Perform the command */
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (cmd == HP_CMD_GETPRIVATE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (modctl(MODHPOPS, MODHPOPS_BUS_GET, path, connection,
269473047d747f7815af570197e4ef7322d3632cEvan Yan &prop, &results))
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = errno;
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("private_options: modctl(MODHPOPS_BUS_GET) = %d\n", rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (modctl(MODHPOPS, MODHPOPS_BUS_SET, path, connection,
269473047d747f7815af570197e4ef7322d3632cEvan Yan &prop, &results))
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = errno;
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("private_options: modctl(MODHPOPS_BUS_SET) = %d\n", rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Unlock hotplug */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pthread_mutex_unlock(&hotplug_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Parse results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan unpack_properties(&results, &values);
269473047d747f7815af570197e4ef7322d3632cEvan Yan *resultsp = values;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Cleanup */
269473047d747f7815af570197e4ef7322d3632cEvan Yan free_properties(&prop);
269473047d747f7815af570197e4ef7322d3632cEvan Yan free_properties(&results);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * check_rcm_required()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Given the root of a changestate operation and the target
269473047d747f7815af570197e4ef7322d3632cEvan Yan * state, determine if RCM interactions will be required.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic boolean_t
269473047d747f7815af570197e4ef7322d3632cEvan Yancheck_rcm_required(hp_node_t root, int target_state)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * RCM is required when transitioning an ENABLED
269473047d747f7815af570197e4ef7322d3632cEvan Yan * connector to a non-ENABLED state.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((root->hp_type == HP_NODE_CONNECTOR) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan HP_IS_ENABLED(root->hp_state) && !HP_IS_ENABLED(target_state))
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (B_TRUE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * RCM is required when transitioning an OPERATIONAL
269473047d747f7815af570197e4ef7322d3632cEvan Yan * port to a non-OPERATIONAL state.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((root->hp_type == HP_NODE_PORT) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan HP_IS_ONLINE(root->hp_state) && HP_IS_OFFLINE(target_state))
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (B_TRUE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* RCM is not required in other cases */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (B_FALSE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * pack_properties()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
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 Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpack_properties(const char *options, ddi_hp_property_t *prop)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *nvl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *buf, *tmp, *name, *value, *next;
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) memset(prop, 0, sizeof (ddi_hp_property_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Do nothing if options string is empty */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((len = strlen(options)) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("pack_properties: options string is empty.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOENT);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Avoid modifying the input string by using a copy on the stack */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((tmp = (char *)alloca(len + 1)) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Failed to allocate buffer for private options.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) strlcpy(tmp, options, len + 1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate the nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Failed to allocate private options nvlist.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add each option from the string */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (name = tmp; name != NULL; name = next) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Isolate current name/value, and locate the next */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((next = strchr(name, ',')) != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan *next = '\0';
269473047d747f7815af570197e4ef7322d3632cEvan Yan next++;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Split current name/value pair */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((value = strchr(name, '=')) != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan *value = '\0';
269473047d747f7815af570197e4ef7322d3632cEvan Yan value++;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan value = "";
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add the option to the nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_add_string(nvl, name, value) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Failed to add private option to nvlist.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EFAULT);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Pack the nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan len = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan buf = NULL;
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 nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EFAULT);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Save results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan prop->nvlist_buf = buf;
269473047d747f7815af570197e4ef7322d3632cEvan Yan prop->buf_size = len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* The nvlist is no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * unpack_properties()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
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 Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void
269473047d747f7815af570197e4ef7322d3632cEvan Yanunpack_properties(ddi_hp_property_t *prop, char **optionsp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *nvl = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvpair_t *nvp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan boolean_t first_flag;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *name, *value, *options;
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan *optionsp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
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 return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
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 return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Compute the size of the options string */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (len = 0, nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan name = nvpair_name(nvp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Skip the command, and anything not a string */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((strcmp(name, "cmd") == 0) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvpair_type(nvp) != DATA_TYPE_STRING))
269473047d747f7815af570197e4ef7322d3632cEvan Yan continue;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) nvpair_value_string(nvp, &value);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Account for '=' signs, commas, and terminating NULL */
269473047d747f7815af570197e4ef7322d3632cEvan Yan len += (strlen(name) + strlen(value) + 2);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
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 nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Copy name/value pairs into the options string */
269473047d747f7815af570197e4ef7322d3632cEvan Yan first_flag = B_TRUE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan name = nvpair_name(nvp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Skip the command, and anything not a string */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((strcmp(name, "cmd") == 0) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvpair_type(nvp) != DATA_TYPE_STRING))
269473047d747f7815af570197e4ef7322d3632cEvan Yan continue;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!first_flag)
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) strlcat(options, ",", len);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) strlcat(options, name, len);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) nvpair_value_string(nvp, &value);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strlen(value) > 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) strlcat(options, "=", len);
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) strlcat(options, value, len);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan first_flag = B_FALSE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* The unpacked nvlist is no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Save results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan *optionsp = options;
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * free_properties()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Destroy a structure containing a packed nvlist of bus
269473047d747f7815af570197e4ef7322d3632cEvan Yan * private properties.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void
269473047d747f7815af570197e4ef7322d3632cEvan Yanfree_properties(ddi_hp_property_t *prop)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (prop) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (prop->nvlist_buf)
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(prop->nvlist_buf);
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) memset(prop, 0, sizeof (ddi_hp_property_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}