xref: /illumos-gate/usr/src/uts/common/os/ddi_hp_ndi.c (revision 350b2114)
126947304SEvan Yan /*
226947304SEvan Yan  * CDDL HEADER START
326947304SEvan Yan  *
426947304SEvan Yan  * The contents of this file are subject to the terms of the
526947304SEvan Yan  * Common Development and Distribution License (the "License").
626947304SEvan Yan  * You may not use this file except in compliance with the License.
726947304SEvan Yan  *
826947304SEvan Yan  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
926947304SEvan Yan  * or http://www.opensolaris.org/os/licensing.
1026947304SEvan Yan  * See the License for the specific language governing permissions
1126947304SEvan Yan  * and limitations under the License.
1226947304SEvan Yan  *
1326947304SEvan Yan  * When distributing Covered Code, include this CDDL HEADER in each
1426947304SEvan Yan  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1526947304SEvan Yan  * If applicable, add the following below this CDDL HEADER, with the
1626947304SEvan Yan  * fields enclosed by brackets "[]" replaced with your own identifying
1726947304SEvan Yan  * information: Portions Copyright [yyyy] [name of copyright owner]
1826947304SEvan Yan  *
1926947304SEvan Yan  * CDDL HEADER END
2026947304SEvan Yan  */
2126947304SEvan Yan /*
2226947304SEvan Yan  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2326947304SEvan Yan  * Use is subject to license terms.
24ffb64830SJordan Paige Hendricks  *
25ffb64830SJordan Paige Hendricks  * Copyright 2019 Joyent, Inc.
263fe80ca4SDan Cross  * Copyright 2023 Oxide Computer Company
2726947304SEvan Yan  */
2826947304SEvan Yan 
2926947304SEvan Yan /*
3026947304SEvan Yan  * Sun NDI hotplug interfaces
3126947304SEvan Yan  */
3226947304SEvan Yan 
3326947304SEvan Yan #include <sys/note.h>
3426947304SEvan Yan #include <sys/sysmacros.h>
3526947304SEvan Yan #include <sys/types.h>
3626947304SEvan Yan #include <sys/param.h>
3726947304SEvan Yan #include <sys/systm.h>
3826947304SEvan Yan #include <sys/kmem.h>
3926947304SEvan Yan #include <sys/cmn_err.h>
4026947304SEvan Yan #include <sys/debug.h>
4126947304SEvan Yan #include <sys/avintr.h>
4226947304SEvan Yan #include <sys/autoconf.h>
4326947304SEvan Yan #include <sys/sunndi.h>
4426947304SEvan Yan #include <sys/ndi_impldefs.h>
4526947304SEvan Yan #include <sys/ddi.h>
4626947304SEvan Yan #include <sys/disp.h>
4726947304SEvan Yan #include <sys/stat.h>
4826947304SEvan Yan #include <sys/callb.h>
4926947304SEvan Yan #include <sys/sysevent.h>
5026947304SEvan Yan #include <sys/sysevent/eventdefs.h>
5126947304SEvan Yan #include <sys/sysevent/dr.h>
5226947304SEvan Yan #include <sys/taskq.h>
5326947304SEvan Yan 
5426947304SEvan Yan /* Local functions prototype */
5526947304SEvan Yan static void ddihp_cn_run_event(void *arg);
5626947304SEvan Yan static int ddihp_cn_req_handler(ddi_hp_cn_handle_t *hdlp,
5726947304SEvan Yan     ddi_hp_cn_state_t target_state);
5826947304SEvan Yan 
5926947304SEvan Yan /*
6026947304SEvan Yan  * Global functions (called by hotplug controller or nexus drivers)
6126947304SEvan Yan  */
6226947304SEvan Yan 
6326947304SEvan Yan /*
6426947304SEvan Yan  * Register the Hotplug Connection (CN)
6526947304SEvan Yan  */
6626947304SEvan Yan int
ndi_hp_register(dev_info_t * dip,ddi_hp_cn_info_t * info_p)6726947304SEvan Yan ndi_hp_register(dev_info_t *dip, ddi_hp_cn_info_t *info_p)
6826947304SEvan Yan {
6926947304SEvan Yan 	ddi_hp_cn_handle_t	*hdlp;
7026947304SEvan Yan 
7126947304SEvan Yan 	DDI_HP_NEXDBG((CE_CONT, "ndi_hp_register: dip %p, info_p %p\n",
7226947304SEvan Yan 	    (void *)dip, (void *)info_p));
7326947304SEvan Yan 
7426947304SEvan Yan 	ASSERT(!servicing_interrupt());
7526947304SEvan Yan 	if (servicing_interrupt())
7626947304SEvan Yan 		return (NDI_FAILURE);
7726947304SEvan Yan 
7826947304SEvan Yan 	/* Validate the arguments */
7926947304SEvan Yan 	if ((dip == NULL) || (info_p == NULL))
8026947304SEvan Yan 		return (NDI_EINVAL);
8126947304SEvan Yan 
8226947304SEvan Yan 	if (!NEXUS_HAS_HP_OP(dip)) {
8326947304SEvan Yan 		return (NDI_ENOTSUP);
8426947304SEvan Yan 	}
8526947304SEvan Yan 	/* Lock before access */
863fe80ca4SDan Cross 	ndi_devi_enter(dip);
8726947304SEvan Yan 
8826947304SEvan Yan 	hdlp = ddihp_cn_name_to_handle(dip, info_p->cn_name);
8926947304SEvan Yan 	if (hdlp) {
9026947304SEvan Yan 		/* This cn_name is already registered. */
913fe80ca4SDan Cross 		ndi_devi_exit(dip);
9226947304SEvan Yan 
9326947304SEvan Yan 		return (NDI_SUCCESS);
9426947304SEvan Yan 	}
9526947304SEvan Yan 	/*
9626947304SEvan Yan 	 * Create and initialize hotplug Connection handle
9726947304SEvan Yan 	 */
9826947304SEvan Yan 	hdlp = (ddi_hp_cn_handle_t *)kmem_zalloc(
9926947304SEvan Yan 	    (sizeof (ddi_hp_cn_handle_t)), KM_SLEEP);
10026947304SEvan Yan 
10126947304SEvan Yan 	/* Copy the Connection information */
10226947304SEvan Yan 	hdlp->cn_dip = dip;
10326947304SEvan Yan 	bcopy(info_p, &(hdlp->cn_info), sizeof (*info_p));
10426947304SEvan Yan 
10526947304SEvan Yan 	/* Copy cn_name */
10626947304SEvan Yan 	hdlp->cn_info.cn_name = ddi_strdup(info_p->cn_name, KM_SLEEP);
10726947304SEvan Yan 
10826947304SEvan Yan 	if (ddihp_cn_getstate(hdlp) != DDI_SUCCESS) {
10926947304SEvan Yan 		DDI_HP_NEXDBG((CE_CONT, "ndi_hp_register: dip %p, hdlp %p"
11026947304SEvan Yan 		    "ddi_cn_getstate failed\n", (void *)dip, (void *)hdlp));
11126947304SEvan Yan 
11226947304SEvan Yan 		goto fail;
11326947304SEvan Yan 	}
11426947304SEvan Yan 
11526947304SEvan Yan 	/*
11626947304SEvan Yan 	 * Append the handle to the list
11726947304SEvan Yan 	 */
11826947304SEvan Yan 	DDIHP_LIST_APPEND(ddi_hp_cn_handle_t, (DEVI(dip)->devi_hp_hdlp),
11926947304SEvan Yan 	    hdlp);
12026947304SEvan Yan 
1213fe80ca4SDan Cross 	ndi_devi_exit(dip);
12226947304SEvan Yan 
12326947304SEvan Yan 	return (NDI_SUCCESS);
12426947304SEvan Yan 
12526947304SEvan Yan fail:
12626947304SEvan Yan 	kmem_free(hdlp->cn_info.cn_name, strlen(hdlp->cn_info.cn_name) + 1);
12726947304SEvan Yan 	kmem_free(hdlp, sizeof (ddi_hp_cn_handle_t));
1283fe80ca4SDan Cross 	ndi_devi_exit(dip);
12926947304SEvan Yan 
13026947304SEvan Yan 	return (NDI_FAILURE);
13126947304SEvan Yan }
13226947304SEvan Yan 
13326947304SEvan Yan /*
13426947304SEvan Yan  * Unregister a Hotplug Connection (CN)
13526947304SEvan Yan  */
13626947304SEvan Yan int
ndi_hp_unregister(dev_info_t * dip,char * cn_name)13726947304SEvan Yan ndi_hp_unregister(dev_info_t *dip, char *cn_name)
13826947304SEvan Yan {
13926947304SEvan Yan 	ddi_hp_cn_handle_t	*hdlp;
14026947304SEvan Yan 	int			ret;
14126947304SEvan Yan 
14226947304SEvan Yan 	DDI_HP_NEXDBG((CE_CONT, "ndi_hp_unregister: dip %p, cn name %s\n",
14326947304SEvan Yan 	    (void *)dip, cn_name));
14426947304SEvan Yan 
14526947304SEvan Yan 	ASSERT(!servicing_interrupt());
14626947304SEvan Yan 	if (servicing_interrupt())
14726947304SEvan Yan 		return (NDI_FAILURE);
14826947304SEvan Yan 
14926947304SEvan Yan 	/* Validate the arguments */
15026947304SEvan Yan 	if ((dip == NULL) || (cn_name == NULL))
15126947304SEvan Yan 		return (NDI_EINVAL);
15226947304SEvan Yan 
1533fe80ca4SDan Cross 	ndi_devi_enter(dip);
15426947304SEvan Yan 
15526947304SEvan Yan 	hdlp = ddihp_cn_name_to_handle(dip, cn_name);
15626947304SEvan Yan 	if (hdlp == NULL) {
1573fe80ca4SDan Cross 		ndi_devi_exit(dip);
15826947304SEvan Yan 		return (NDI_EINVAL);
15926947304SEvan Yan 	}
16026947304SEvan Yan 
16126947304SEvan Yan 	switch (ddihp_cn_unregister(hdlp)) {
16226947304SEvan Yan 	case DDI_SUCCESS:
16326947304SEvan Yan 		ret = NDI_SUCCESS;
16426947304SEvan Yan 		break;
16526947304SEvan Yan 	case DDI_EINVAL:
16626947304SEvan Yan 		ret = NDI_EINVAL;
16726947304SEvan Yan 		break;
16826947304SEvan Yan 	case DDI_EBUSY:
16926947304SEvan Yan 		ret = NDI_BUSY;
17026947304SEvan Yan 		break;
17126947304SEvan Yan 	default:
17226947304SEvan Yan 		ret = NDI_FAILURE;
17326947304SEvan Yan 		break;
17426947304SEvan Yan 	}
17526947304SEvan Yan 
1763fe80ca4SDan Cross 	ndi_devi_exit(dip);
17726947304SEvan Yan 
17826947304SEvan Yan 	return (ret);
17926947304SEvan Yan }
18026947304SEvan Yan 
18126947304SEvan Yan /*
18226947304SEvan Yan  * Notify the Hotplug Connection (CN) to change state.
18326947304SEvan Yan  * Flag:
18426947304SEvan Yan  *	DDI_HP_REQ_SYNC	    Return after the change is finished.
18526947304SEvan Yan  *	DDI_HP_REQ_ASYNC    Return after the request is dispatched.
18626947304SEvan Yan  */
18726947304SEvan Yan int
ndi_hp_state_change_req(dev_info_t * dip,char * cn_name,ddi_hp_cn_state_t state,uint_t flag)18826947304SEvan Yan ndi_hp_state_change_req(dev_info_t *dip, char *cn_name,
18926947304SEvan Yan     ddi_hp_cn_state_t state, uint_t flag)
19026947304SEvan Yan {
19126947304SEvan Yan 	ddi_hp_cn_async_event_entry_t	*eventp;
19226947304SEvan Yan 
19326947304SEvan Yan 	DDI_HP_NEXDBG((CE_CONT, "ndi_hp_state_change_req: dip %p "
19426947304SEvan Yan 	    "cn_name: %s, state %x, flag %x\n",
19526947304SEvan Yan 	    (void *)dip, cn_name, state, flag));
19626947304SEvan Yan 
19726947304SEvan Yan 	/* Validate the arguments */
19826947304SEvan Yan 	if (dip == NULL || cn_name == NULL)
19926947304SEvan Yan 		return (NDI_EINVAL);
20026947304SEvan Yan 
20126947304SEvan Yan 	if (!NEXUS_HAS_HP_OP(dip)) {
20226947304SEvan Yan 		return (NDI_ENOTSUP);
20326947304SEvan Yan 	}
20426947304SEvan Yan 	/*
20526947304SEvan Yan 	 * If the request is to handle the event synchronously, then call
20626947304SEvan Yan 	 * the event handler without queuing the event.
20726947304SEvan Yan 	 */
20826947304SEvan Yan 	if (flag & DDI_HP_REQ_SYNC) {
20926947304SEvan Yan 		ddi_hp_cn_handle_t	*hdlp;
21026947304SEvan Yan 		int			ret;
21126947304SEvan Yan 
21226947304SEvan Yan 		ASSERT(!servicing_interrupt());
21326947304SEvan Yan 		if (servicing_interrupt())
21426947304SEvan Yan 			return (NDI_FAILURE);
21526947304SEvan Yan 
2163fe80ca4SDan Cross 		ndi_devi_enter(dip);
21726947304SEvan Yan 
21826947304SEvan Yan 		hdlp = ddihp_cn_name_to_handle(dip, cn_name);
21926947304SEvan Yan 		if (hdlp == NULL) {
2203fe80ca4SDan Cross 			ndi_devi_exit(dip);
22126947304SEvan Yan 
22226947304SEvan Yan 			return (NDI_EINVAL);
22326947304SEvan Yan 		}
22426947304SEvan Yan 
22526947304SEvan Yan 		DDI_HP_NEXDBG((CE_CONT, "ndi_hp_state_change_req: hdlp %p "
22626947304SEvan Yan 		    "calling ddihp_cn_req_handler() directly to handle "
22726947304SEvan Yan 		    "target_state %x\n", (void *)hdlp, state));
22826947304SEvan Yan 
22926947304SEvan Yan 		ret = ddihp_cn_req_handler(hdlp, state);
23026947304SEvan Yan 
2313fe80ca4SDan Cross 		ndi_devi_exit(dip);
23226947304SEvan Yan 
23326947304SEvan Yan 		return (ret);
23426947304SEvan Yan 	}
23526947304SEvan Yan 
23626947304SEvan Yan 	eventp = kmem_zalloc(sizeof (ddi_hp_cn_async_event_entry_t),
23726947304SEvan Yan 	    KM_NOSLEEP);
23826947304SEvan Yan 	if (eventp == NULL)
23926947304SEvan Yan 		return (NDI_NOMEM);
24026947304SEvan Yan 
24126947304SEvan Yan 	eventp->cn_name = ddi_strdup(cn_name, KM_NOSLEEP);
24226947304SEvan Yan 	if (eventp->cn_name == NULL) {
24326947304SEvan Yan 		kmem_free(eventp, sizeof (ddi_hp_cn_async_event_entry_t));
24426947304SEvan Yan 		return (NDI_NOMEM);
24526947304SEvan Yan 	}
24626947304SEvan Yan 	eventp->dip = dip;
24726947304SEvan Yan 	eventp->target_state = state;
24826947304SEvan Yan 
24926947304SEvan Yan 	/*
25026947304SEvan Yan 	 * Hold the parent's ref so that it won't disappear when the taskq is
25126947304SEvan Yan 	 * scheduled to run.
25226947304SEvan Yan 	 */
25326947304SEvan Yan 	ndi_hold_devi(dip);
25426947304SEvan Yan 
255fc8ae2ecSToomas Soome 	if (taskq_dispatch(system_taskq, ddihp_cn_run_event, eventp,
256fc8ae2ecSToomas Soome 	    TQ_NOSLEEP) == TASKQID_INVALID) {
25726947304SEvan Yan 		ndi_rele_devi(dip);
25826947304SEvan Yan 		DDI_HP_NEXDBG((CE_CONT, "ndi_hp_state_change_req: "
25926947304SEvan Yan 		    "taskq_dispatch failed! dip %p "
26026947304SEvan Yan 		    "target_state %x\n", (void *)dip, state));
26126947304SEvan Yan 		return (NDI_NOMEM);
26226947304SEvan Yan 	}
26326947304SEvan Yan 
26426947304SEvan Yan 	return (NDI_CLAIMED);
26526947304SEvan Yan }
26626947304SEvan Yan 
26726947304SEvan Yan /*
26826947304SEvan Yan  * Walk the link of Hotplug Connection handles of a dip:
26926947304SEvan Yan  *	DEVI(dip)->devi_hp_hdlp->[link of connections]
27026947304SEvan Yan  */
27126947304SEvan Yan void
ndi_hp_walk_cn(dev_info_t * dip,int (* f)(ddi_hp_cn_info_t *,void *),void * arg)27226947304SEvan Yan ndi_hp_walk_cn(dev_info_t *dip, int (*f)(ddi_hp_cn_info_t *,
27326947304SEvan Yan     void *), void *arg)
27426947304SEvan Yan {
27526947304SEvan Yan 	ddi_hp_cn_handle_t	*head, *curr, *prev;
27626947304SEvan Yan 
27726947304SEvan Yan 	DDI_HP_NEXDBG((CE_CONT, "ndi_hp_walk_cn: dip %p arg %p\n",
27826947304SEvan Yan 	    (void *)dip, arg));
27926947304SEvan Yan 
28026947304SEvan Yan 	ASSERT(!servicing_interrupt());
28126947304SEvan Yan 	if (servicing_interrupt())
28226947304SEvan Yan 		return;
28326947304SEvan Yan 
28426947304SEvan Yan 	/* Validate the arguments */
28526947304SEvan Yan 	if (dip == NULL)
28626947304SEvan Yan 		return;
28726947304SEvan Yan 
2883fe80ca4SDan Cross 	ndi_devi_enter(dip);
28926947304SEvan Yan 
29026947304SEvan Yan 	head = DEVI(dip)->devi_hp_hdlp;
29126947304SEvan Yan 	curr = head;
29226947304SEvan Yan 	prev = NULL;
29326947304SEvan Yan 	while (curr != NULL) {
29426947304SEvan Yan 		DDI_HP_NEXDBG((CE_CONT, "ndi_hp_walk_cn: dip %p "
29526947304SEvan Yan 		    "current cn_name: %s\n",
29626947304SEvan Yan 		    (void *)dip, curr->cn_info.cn_name));
29726947304SEvan Yan 		switch ((*f)(&(curr->cn_info), arg)) {
29826947304SEvan Yan 		case DDI_WALK_TERMINATE:
2993fe80ca4SDan Cross 			ndi_devi_exit(dip);
30026947304SEvan Yan 
30126947304SEvan Yan 			return;
30226947304SEvan Yan 		case DDI_WALK_CONTINUE:
30326947304SEvan Yan 		default:
30426947304SEvan Yan 			if (DEVI(dip)->devi_hp_hdlp != head) {
30526947304SEvan Yan 				/*
30626947304SEvan Yan 				 * The current node is head and it is removed
30726947304SEvan Yan 				 * by last call to (*f)()
30826947304SEvan Yan 				 */
30926947304SEvan Yan 				head = DEVI(dip)->devi_hp_hdlp;
31026947304SEvan Yan 				curr = head;
31126947304SEvan Yan 				prev = NULL;
31226947304SEvan Yan 			} else if (prev && prev->next != curr) {
31326947304SEvan Yan 				/*
31426947304SEvan Yan 				 * The current node is a middle node or tail
31526947304SEvan Yan 				 * node and it is removed by last call to
31626947304SEvan Yan 				 * (*f)()
31726947304SEvan Yan 				 */
31826947304SEvan Yan 				curr = prev->next;
31926947304SEvan Yan 			} else {
32026947304SEvan Yan 				/* no removal accurred on curr node */
32126947304SEvan Yan 				prev = curr;
32226947304SEvan Yan 				curr = curr->next;
32326947304SEvan Yan 			}
32426947304SEvan Yan 		}
32526947304SEvan Yan 	}
3263fe80ca4SDan Cross 	ndi_devi_exit(dip);
32726947304SEvan Yan }
32826947304SEvan Yan 
32926947304SEvan Yan /*
33026947304SEvan Yan  * Local functions (called within this file)
33126947304SEvan Yan  */
33226947304SEvan Yan 
33326947304SEvan Yan /*
33426947304SEvan Yan  * Wrapper function for ddihp_cn_req_handler() called from taskq
33526947304SEvan Yan  */
33626947304SEvan Yan static void
ddihp_cn_run_event(void * arg)33726947304SEvan Yan ddihp_cn_run_event(void *arg)
33826947304SEvan Yan {
33926947304SEvan Yan 	ddi_hp_cn_async_event_entry_t	*eventp =
34026947304SEvan Yan 	    (ddi_hp_cn_async_event_entry_t *)arg;
34126947304SEvan Yan 	dev_info_t			*dip = eventp->dip;
342*350b2114SRobert Mustacchi 	dev_info_t			*pdip;
34326947304SEvan Yan 	ddi_hp_cn_handle_t		*hdlp;
34426947304SEvan Yan 
345*350b2114SRobert Mustacchi 	/*
346*350b2114SRobert Mustacchi 	 * See notes in ddihp_modctl().  This is another essentially identical
347*350b2114SRobert Mustacchi 	 * path we get to internally rather than from userland, but the same
348*350b2114SRobert Mustacchi 	 * problem applies here.
349*350b2114SRobert Mustacchi 	 */
350*350b2114SRobert Mustacchi 	pdip = ddi_get_parent(dip);
351*350b2114SRobert Mustacchi 	if (pdip != NULL)
352*350b2114SRobert Mustacchi 		ndi_devi_enter(pdip);
353*350b2114SRobert Mustacchi 
35426947304SEvan Yan 	/* Lock before access */
3553fe80ca4SDan Cross 	ndi_devi_enter(dip);
35626947304SEvan Yan 
35726947304SEvan Yan 	hdlp = ddihp_cn_name_to_handle(dip, eventp->cn_name);
35826947304SEvan Yan 	if (hdlp) {
35926947304SEvan Yan 		(void) ddihp_cn_req_handler(hdlp, eventp->target_state);
36026947304SEvan Yan 	} else {
36126947304SEvan Yan 		DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_run_event: no handle for "
36226947304SEvan Yan 		    "cn_name: %s dip %p. Request for target_state %x is"
36326947304SEvan Yan 		    " dropped. \n",
36426947304SEvan Yan 		    eventp->cn_name, (void *)dip, eventp->target_state));
36526947304SEvan Yan 	}
36626947304SEvan Yan 
3673fe80ca4SDan Cross 	ndi_devi_exit(dip);
368*350b2114SRobert Mustacchi 	if (pdip != NULL)
369*350b2114SRobert Mustacchi 		ndi_devi_exit(pdip);
37026947304SEvan Yan 
37126947304SEvan Yan 	/* Release the devi's ref that is held from interrupt context. */
37226947304SEvan Yan 	ndi_rele_devi((dev_info_t *)DEVI(dip));
37326947304SEvan Yan 	kmem_free(eventp->cn_name, strlen(eventp->cn_name) + 1);
37426947304SEvan Yan 	kmem_free(eventp, sizeof (ddi_hp_cn_async_event_entry_t));
37526947304SEvan Yan }
37626947304SEvan Yan 
37726947304SEvan Yan /*
37826947304SEvan Yan  * Handle state change request of a Hotplug Connection (CN)
37926947304SEvan Yan  */
38026947304SEvan Yan static int
ddihp_cn_req_handler(ddi_hp_cn_handle_t * hdlp,ddi_hp_cn_state_t target_state)38126947304SEvan Yan ddihp_cn_req_handler(ddi_hp_cn_handle_t *hdlp,
38226947304SEvan Yan     ddi_hp_cn_state_t target_state)
38326947304SEvan Yan {
38426947304SEvan Yan 	dev_info_t	*dip = hdlp->cn_dip;
38526947304SEvan Yan 	int		ret = DDI_SUCCESS;
38626947304SEvan Yan 
38726947304SEvan Yan 	DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_req_handler:"
38826947304SEvan Yan 	    " hdlp %p, target_state %x\n",
38926947304SEvan Yan 	    (void *)hdlp, target_state));
39026947304SEvan Yan 
39126947304SEvan Yan 	ASSERT(DEVI_BUSY_OWNED(dip));
39226947304SEvan Yan 
393ffb64830SJordan Paige Hendricks 	/*
394ffb64830SJordan Paige Hendricks 	 * We do not want to fetch the state first, as calling ddihp_cn_getstate
395ffb64830SJordan Paige Hendricks 	 * will update the cn_state member of the connection handle. The
396ffb64830SJordan Paige Hendricks 	 * connector's hotplug operations rely on this value to know how
397ffb64830SJordan Paige Hendricks 	 * target_state compares to the last known state of the device and make
398ffb64830SJordan Paige Hendricks 	 * decisions about whether to clean up, post sysevents about the state
399ffb64830SJordan Paige Hendricks 	 * change, and so on.
400ffb64830SJordan Paige Hendricks 	 *
401ffb64830SJordan Paige Hendricks 	 * Instead, just carry out the request to change the state. The
402ffb64830SJordan Paige Hendricks 	 * connector's hotplug operations will update the state in the
403ffb64830SJordan Paige Hendricks 	 * connection handle after they complete their necessary state change
404ffb64830SJordan Paige Hendricks 	 * actions.
405ffb64830SJordan Paige Hendricks 	 */
40626947304SEvan Yan 	if (hdlp->cn_info.cn_state != target_state) {
40726947304SEvan Yan 		ddi_hp_cn_state_t result_state = 0;
40826947304SEvan Yan 
40926947304SEvan Yan 		DDIHP_CN_OPS(hdlp, DDI_HPOP_CN_CHANGE_STATE,
41026947304SEvan Yan 		    (void *)&target_state, (void *)&result_state, ret);
41126947304SEvan Yan 
41226947304SEvan Yan 		DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_req_handler: dip %p, "
41326947304SEvan Yan 		    "hdlp %p changed state to %x, ret=%x\n",
41426947304SEvan Yan 		    (void *)dip, (void *)hdlp, result_state, ret));
41526947304SEvan Yan 	}
41626947304SEvan Yan 
41726947304SEvan Yan 	if (ret == DDI_SUCCESS)
41826947304SEvan Yan 		return (NDI_CLAIMED);
41926947304SEvan Yan 	else
42026947304SEvan Yan 		return (NDI_UNCLAIMED);
42126947304SEvan Yan }
422