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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Use is subject to license terms.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Sun NDI hotplug interfaces
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/note.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sysmacros.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/types.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/param.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/systm.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/kmem.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/cmn_err.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/debug.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/avintr.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/autoconf.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sunndi.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/ndi_impldefs.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/ddi.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/disp.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/stat.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/callb.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sysevent.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sysevent/eventdefs.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sysevent/dr.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/taskq.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/* Local functions prototype */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void ddihp_cn_run_event(void *arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int ddihp_cn_req_handler(ddi_hp_cn_handle_t *hdlp,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t target_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Global functions (called by hotplug controller or nexus drivers)
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Register the Hotplug Connection (CN)
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanndi_hp_register(dev_info_t *dip, ddi_hp_cn_info_t *info_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_handle_t *hdlp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int count;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_NEXDBG((CE_CONT, "ndi_hp_register: dip %p, info_p %p\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)dip, (void *)info_p));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(!servicing_interrupt());
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (servicing_interrupt())
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Validate the arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((dip == NULL) || (info_p == NULL))
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!NEXUS_HAS_HP_OP(dip)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_ENOTSUP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Lock before access */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_enter(dip, &count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan hdlp = ddihp_cn_name_to_handle(dip, info_p->cn_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (hdlp) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* This cn_name is already registered. */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_exit(dip, count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Create and initialize hotplug Connection handle
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan hdlp = (ddi_hp_cn_handle_t *)kmem_zalloc(
269473047d747f7815af570197e4ef7322d3632cEvan Yan (sizeof (ddi_hp_cn_handle_t)), KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Copy the Connection information */
269473047d747f7815af570197e4ef7322d3632cEvan Yan hdlp->cn_dip = dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan bcopy(info_p, &(hdlp->cn_info), sizeof (*info_p));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Copy cn_name */
269473047d747f7815af570197e4ef7322d3632cEvan Yan hdlp->cn_info.cn_name = ddi_strdup(info_p->cn_name, KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ddihp_cn_getstate(hdlp) != DDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_NEXDBG((CE_CONT, "ndi_hp_register: dip %p, hdlp %p"
269473047d747f7815af570197e4ef7322d3632cEvan Yan "ddi_cn_getstate failed\n", (void *)dip, (void *)hdlp));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto fail;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Append the handle to the list
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDIHP_LIST_APPEND(ddi_hp_cn_handle_t, (DEVI(dip)->devi_hp_hdlp),
269473047d747f7815af570197e4ef7322d3632cEvan Yan hdlp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_exit(dip, count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanfail:
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(hdlp->cn_info.cn_name, strlen(hdlp->cn_info.cn_name) + 1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(hdlp, sizeof (ddi_hp_cn_handle_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_exit(dip, count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Unregister a Hotplug Connection (CN)
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanndi_hp_unregister(dev_info_t *dip, char *cn_name)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_handle_t *hdlp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int count;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_NEXDBG((CE_CONT, "ndi_hp_unregister: dip %p, cn name %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)dip, cn_name));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(!servicing_interrupt());
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (servicing_interrupt())
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Validate the arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((dip == NULL) || (cn_name == NULL))
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_enter(dip, &count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan hdlp = ddihp_cn_name_to_handle(dip, cn_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (hdlp == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_exit(dip, count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (ddihp_cn_unregister(hdlp)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_SUCCESS:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = NDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_EINVAL:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = NDI_EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_EBUSY:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = NDI_BUSY;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = NDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_exit(dip, count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Notify the Hotplug Connection (CN) to change state.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Flag:
269473047d747f7815af570197e4ef7322d3632cEvan Yan * DDI_HP_REQ_SYNC Return after the change is finished.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * DDI_HP_REQ_ASYNC Return after the request is dispatched.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanndi_hp_state_change_req(dev_info_t *dip, char *cn_name,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t state, uint_t flag)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_async_event_entry_t *eventp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_NEXDBG((CE_CONT, "ndi_hp_state_change_req: dip %p "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "cn_name: %s, state %x, flag %x\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)dip, cn_name, state, flag));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Validate the arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (dip == NULL || cn_name == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!NEXUS_HAS_HP_OP(dip)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_ENOTSUP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If the request is to handle the event synchronously, then call
269473047d747f7815af570197e4ef7322d3632cEvan Yan * the event handler without queuing the event.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (flag & DDI_HP_REQ_SYNC) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_handle_t *hdlp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int count;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(!servicing_interrupt());
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (servicing_interrupt())
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_enter(dip, &count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan hdlp = ddihp_cn_name_to_handle(dip, cn_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (hdlp == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_exit(dip, count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_NEXDBG((CE_CONT, "ndi_hp_state_change_req: hdlp %p "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "calling ddihp_cn_req_handler() directly to handle "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "target_state %x\n", (void *)hdlp, state));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = ddihp_cn_req_handler(hdlp, state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_exit(dip, count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan eventp = kmem_zalloc(sizeof (ddi_hp_cn_async_event_entry_t),
269473047d747f7815af570197e4ef7322d3632cEvan Yan KM_NOSLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (eventp == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_NOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan eventp->cn_name = ddi_strdup(cn_name, KM_NOSLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (eventp->cn_name == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(eventp, sizeof (ddi_hp_cn_async_event_entry_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_NOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan eventp->dip = dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan eventp->target_state = state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Hold the parent's ref so that it won't disappear when the taskq is
269473047d747f7815af570197e4ef7322d3632cEvan Yan * scheduled to run.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_hold_devi(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!taskq_dispatch(system_taskq, ddihp_cn_run_event, eventp,
269473047d747f7815af570197e4ef7322d3632cEvan Yan TQ_NOSLEEP)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_rele_devi(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_NEXDBG((CE_CONT, "ndi_hp_state_change_req: "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "taskq_dispatch failed! dip %p "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "target_state %x\n", (void *)dip, state));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_NOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_CLAIMED);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Walk the link of Hotplug Connection handles of a dip:
269473047d747f7815af570197e4ef7322d3632cEvan Yan * DEVI(dip)->devi_hp_hdlp->[link of connections]
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanndi_hp_walk_cn(dev_info_t *dip, int (*f)(ddi_hp_cn_info_t *,
269473047d747f7815af570197e4ef7322d3632cEvan Yan void *), void *arg)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan int count;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_handle_t *head, *curr, *prev;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_NEXDBG((CE_CONT, "ndi_hp_walk_cn: dip %p arg %p\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)dip, arg));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(!servicing_interrupt());
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (servicing_interrupt())
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Validate the arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (dip == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_enter(dip, &count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan head = DEVI(dip)->devi_hp_hdlp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan curr = head;
269473047d747f7815af570197e4ef7322d3632cEvan Yan prev = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan while (curr != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_NEXDBG((CE_CONT, "ndi_hp_walk_cn: dip %p "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "current cn_name: %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)dip, curr->cn_info.cn_name));
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch ((*f)(&(curr->cn_info), arg)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_WALK_TERMINATE:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_exit(dip, count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_WALK_CONTINUE:
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (DEVI(dip)->devi_hp_hdlp != head) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The current node is head and it is removed
269473047d747f7815af570197e4ef7322d3632cEvan Yan * by last call to (*f)()
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan head = DEVI(dip)->devi_hp_hdlp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan curr = head;
269473047d747f7815af570197e4ef7322d3632cEvan Yan prev = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (prev && prev->next != curr) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The current node is a middle node or tail
269473047d747f7815af570197e4ef7322d3632cEvan Yan * node and it is removed by last call to
269473047d747f7815af570197e4ef7322d3632cEvan Yan * (*f)()
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan curr = prev->next;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* no removal accurred on curr node */
269473047d747f7815af570197e4ef7322d3632cEvan Yan prev = curr;
269473047d747f7815af570197e4ef7322d3632cEvan Yan curr = curr->next;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_exit(dip, count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Local functions (called within this file)
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Wrapper function for ddihp_cn_req_handler() called from taskq
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void
269473047d747f7815af570197e4ef7322d3632cEvan Yanddihp_cn_run_event(void *arg)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_async_event_entry_t *eventp =
269473047d747f7815af570197e4ef7322d3632cEvan Yan (ddi_hp_cn_async_event_entry_t *)arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_info_t *dip = eventp->dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_handle_t *hdlp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int count;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Lock before access */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_enter(dip, &count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan hdlp = ddihp_cn_name_to_handle(dip, eventp->cn_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (hdlp) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) ddihp_cn_req_handler(hdlp, eventp->target_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_run_event: no handle for "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "cn_name: %s dip %p. Request for target_state %x is"
269473047d747f7815af570197e4ef7322d3632cEvan Yan " dropped. \n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan eventp->cn_name, (void *)dip, eventp->target_state));
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_exit(dip, count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Release the devi's ref that is held from interrupt context. */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_rele_devi((dev_info_t *)DEVI(dip));
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(eventp->cn_name, strlen(eventp->cn_name) + 1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(eventp, sizeof (ddi_hp_cn_async_event_entry_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Handle state change request of a Hotplug Connection (CN)
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanddihp_cn_req_handler(ddi_hp_cn_handle_t *hdlp,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t target_state)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_info_t *dip = hdlp->cn_dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret = DDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_req_handler:"
269473047d747f7815af570197e4ef7322d3632cEvan Yan " hdlp %p, target_state %x\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)hdlp, target_state));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(DEVI_BUSY_OWNED(dip));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ddihp_cn_getstate(hdlp) != DDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_req_handler: dip %p, "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "hdlp %p ddi_cn_getstate failed\n", (void *)dip,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)hdlp));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_UNCLAIMED);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (hdlp->cn_info.cn_state != target_state) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t result_state = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDIHP_CN_OPS(hdlp, DDI_HPOP_CN_CHANGE_STATE,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)&target_state, (void *)&result_state, ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_req_handler: dip %p, "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "hdlp %p changed state to %x, ret=%x\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)dip, (void *)hdlp, result_state, ret));
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ret == DDI_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_CLAIMED);
269473047d747f7815af570197e4ef7322d3632cEvan Yan else
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NDI_UNCLAIMED);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}