xref: /onnv-gate/usr/src/uts/common/os/ddi_hp_ndi.c (revision 10923:df470fd79c3c)
1*10923SEvan.Yan@Sun.COM /*
2*10923SEvan.Yan@Sun.COM  * CDDL HEADER START
3*10923SEvan.Yan@Sun.COM  *
4*10923SEvan.Yan@Sun.COM  * The contents of this file are subject to the terms of the
5*10923SEvan.Yan@Sun.COM  * Common Development and Distribution License (the "License").
6*10923SEvan.Yan@Sun.COM  * You may not use this file except in compliance with the License.
7*10923SEvan.Yan@Sun.COM  *
8*10923SEvan.Yan@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*10923SEvan.Yan@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*10923SEvan.Yan@Sun.COM  * See the License for the specific language governing permissions
11*10923SEvan.Yan@Sun.COM  * and limitations under the License.
12*10923SEvan.Yan@Sun.COM  *
13*10923SEvan.Yan@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*10923SEvan.Yan@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*10923SEvan.Yan@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*10923SEvan.Yan@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*10923SEvan.Yan@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*10923SEvan.Yan@Sun.COM  *
19*10923SEvan.Yan@Sun.COM  * CDDL HEADER END
20*10923SEvan.Yan@Sun.COM  */
21*10923SEvan.Yan@Sun.COM /*
22*10923SEvan.Yan@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*10923SEvan.Yan@Sun.COM  * Use is subject to license terms.
24*10923SEvan.Yan@Sun.COM  */
25*10923SEvan.Yan@Sun.COM 
26*10923SEvan.Yan@Sun.COM /*
27*10923SEvan.Yan@Sun.COM  * Sun NDI hotplug interfaces
28*10923SEvan.Yan@Sun.COM  */
29*10923SEvan.Yan@Sun.COM 
30*10923SEvan.Yan@Sun.COM #include <sys/note.h>
31*10923SEvan.Yan@Sun.COM #include <sys/sysmacros.h>
32*10923SEvan.Yan@Sun.COM #include <sys/types.h>
33*10923SEvan.Yan@Sun.COM #include <sys/param.h>
34*10923SEvan.Yan@Sun.COM #include <sys/systm.h>
35*10923SEvan.Yan@Sun.COM #include <sys/kmem.h>
36*10923SEvan.Yan@Sun.COM #include <sys/cmn_err.h>
37*10923SEvan.Yan@Sun.COM #include <sys/debug.h>
38*10923SEvan.Yan@Sun.COM #include <sys/avintr.h>
39*10923SEvan.Yan@Sun.COM #include <sys/autoconf.h>
40*10923SEvan.Yan@Sun.COM #include <sys/sunndi.h>
41*10923SEvan.Yan@Sun.COM #include <sys/ndi_impldefs.h>
42*10923SEvan.Yan@Sun.COM #include <sys/ddi.h>
43*10923SEvan.Yan@Sun.COM #include <sys/disp.h>
44*10923SEvan.Yan@Sun.COM #include <sys/stat.h>
45*10923SEvan.Yan@Sun.COM #include <sys/callb.h>
46*10923SEvan.Yan@Sun.COM #include <sys/sysevent.h>
47*10923SEvan.Yan@Sun.COM #include <sys/sysevent/eventdefs.h>
48*10923SEvan.Yan@Sun.COM #include <sys/sysevent/dr.h>
49*10923SEvan.Yan@Sun.COM #include <sys/taskq.h>
50*10923SEvan.Yan@Sun.COM 
51*10923SEvan.Yan@Sun.COM /* Local functions prototype */
52*10923SEvan.Yan@Sun.COM static void ddihp_cn_run_event(void *arg);
53*10923SEvan.Yan@Sun.COM static int ddihp_cn_req_handler(ddi_hp_cn_handle_t *hdlp,
54*10923SEvan.Yan@Sun.COM     ddi_hp_cn_state_t target_state);
55*10923SEvan.Yan@Sun.COM 
56*10923SEvan.Yan@Sun.COM /*
57*10923SEvan.Yan@Sun.COM  * Global functions (called by hotplug controller or nexus drivers)
58*10923SEvan.Yan@Sun.COM  */
59*10923SEvan.Yan@Sun.COM 
60*10923SEvan.Yan@Sun.COM /*
61*10923SEvan.Yan@Sun.COM  * Register the Hotplug Connection (CN)
62*10923SEvan.Yan@Sun.COM  */
63*10923SEvan.Yan@Sun.COM int
ndi_hp_register(dev_info_t * dip,ddi_hp_cn_info_t * info_p)64*10923SEvan.Yan@Sun.COM ndi_hp_register(dev_info_t *dip, ddi_hp_cn_info_t *info_p)
65*10923SEvan.Yan@Sun.COM {
66*10923SEvan.Yan@Sun.COM 	ddi_hp_cn_handle_t	*hdlp;
67*10923SEvan.Yan@Sun.COM 	int			count;
68*10923SEvan.Yan@Sun.COM 
69*10923SEvan.Yan@Sun.COM 	DDI_HP_NEXDBG((CE_CONT, "ndi_hp_register: dip %p, info_p %p\n",
70*10923SEvan.Yan@Sun.COM 	    (void *)dip, (void *)info_p));
71*10923SEvan.Yan@Sun.COM 
72*10923SEvan.Yan@Sun.COM 	ASSERT(!servicing_interrupt());
73*10923SEvan.Yan@Sun.COM 	if (servicing_interrupt())
74*10923SEvan.Yan@Sun.COM 		return (NDI_FAILURE);
75*10923SEvan.Yan@Sun.COM 
76*10923SEvan.Yan@Sun.COM 	/* Validate the arguments */
77*10923SEvan.Yan@Sun.COM 	if ((dip == NULL) || (info_p == NULL))
78*10923SEvan.Yan@Sun.COM 		return (NDI_EINVAL);
79*10923SEvan.Yan@Sun.COM 
80*10923SEvan.Yan@Sun.COM 	if (!NEXUS_HAS_HP_OP(dip)) {
81*10923SEvan.Yan@Sun.COM 		return (NDI_ENOTSUP);
82*10923SEvan.Yan@Sun.COM 	}
83*10923SEvan.Yan@Sun.COM 	/* Lock before access */
84*10923SEvan.Yan@Sun.COM 	ndi_devi_enter(dip, &count);
85*10923SEvan.Yan@Sun.COM 
86*10923SEvan.Yan@Sun.COM 	hdlp = ddihp_cn_name_to_handle(dip, info_p->cn_name);
87*10923SEvan.Yan@Sun.COM 	if (hdlp) {
88*10923SEvan.Yan@Sun.COM 		/* This cn_name is already registered. */
89*10923SEvan.Yan@Sun.COM 		ndi_devi_exit(dip, count);
90*10923SEvan.Yan@Sun.COM 
91*10923SEvan.Yan@Sun.COM 		return (NDI_SUCCESS);
92*10923SEvan.Yan@Sun.COM 	}
93*10923SEvan.Yan@Sun.COM 	/*
94*10923SEvan.Yan@Sun.COM 	 * Create and initialize hotplug Connection handle
95*10923SEvan.Yan@Sun.COM 	 */
96*10923SEvan.Yan@Sun.COM 	hdlp = (ddi_hp_cn_handle_t *)kmem_zalloc(
97*10923SEvan.Yan@Sun.COM 	    (sizeof (ddi_hp_cn_handle_t)), KM_SLEEP);
98*10923SEvan.Yan@Sun.COM 
99*10923SEvan.Yan@Sun.COM 	/* Copy the Connection information */
100*10923SEvan.Yan@Sun.COM 	hdlp->cn_dip = dip;
101*10923SEvan.Yan@Sun.COM 	bcopy(info_p, &(hdlp->cn_info), sizeof (*info_p));
102*10923SEvan.Yan@Sun.COM 
103*10923SEvan.Yan@Sun.COM 	/* Copy cn_name */
104*10923SEvan.Yan@Sun.COM 	hdlp->cn_info.cn_name = ddi_strdup(info_p->cn_name, KM_SLEEP);
105*10923SEvan.Yan@Sun.COM 
106*10923SEvan.Yan@Sun.COM 	if (ddihp_cn_getstate(hdlp) != DDI_SUCCESS) {
107*10923SEvan.Yan@Sun.COM 		DDI_HP_NEXDBG((CE_CONT, "ndi_hp_register: dip %p, hdlp %p"
108*10923SEvan.Yan@Sun.COM 		    "ddi_cn_getstate failed\n", (void *)dip, (void *)hdlp));
109*10923SEvan.Yan@Sun.COM 
110*10923SEvan.Yan@Sun.COM 		goto fail;
111*10923SEvan.Yan@Sun.COM 	}
112*10923SEvan.Yan@Sun.COM 
113*10923SEvan.Yan@Sun.COM 	/*
114*10923SEvan.Yan@Sun.COM 	 * Append the handle to the list
115*10923SEvan.Yan@Sun.COM 	 */
116*10923SEvan.Yan@Sun.COM 	DDIHP_LIST_APPEND(ddi_hp_cn_handle_t, (DEVI(dip)->devi_hp_hdlp),
117*10923SEvan.Yan@Sun.COM 	    hdlp);
118*10923SEvan.Yan@Sun.COM 
119*10923SEvan.Yan@Sun.COM 	ndi_devi_exit(dip, count);
120*10923SEvan.Yan@Sun.COM 
121*10923SEvan.Yan@Sun.COM 	return (NDI_SUCCESS);
122*10923SEvan.Yan@Sun.COM 
123*10923SEvan.Yan@Sun.COM fail:
124*10923SEvan.Yan@Sun.COM 	kmem_free(hdlp->cn_info.cn_name, strlen(hdlp->cn_info.cn_name) + 1);
125*10923SEvan.Yan@Sun.COM 	kmem_free(hdlp, sizeof (ddi_hp_cn_handle_t));
126*10923SEvan.Yan@Sun.COM 	ndi_devi_exit(dip, count);
127*10923SEvan.Yan@Sun.COM 
128*10923SEvan.Yan@Sun.COM 	return (NDI_FAILURE);
129*10923SEvan.Yan@Sun.COM }
130*10923SEvan.Yan@Sun.COM 
131*10923SEvan.Yan@Sun.COM /*
132*10923SEvan.Yan@Sun.COM  * Unregister a Hotplug Connection (CN)
133*10923SEvan.Yan@Sun.COM  */
134*10923SEvan.Yan@Sun.COM int
ndi_hp_unregister(dev_info_t * dip,char * cn_name)135*10923SEvan.Yan@Sun.COM ndi_hp_unregister(dev_info_t *dip, char *cn_name)
136*10923SEvan.Yan@Sun.COM {
137*10923SEvan.Yan@Sun.COM 	ddi_hp_cn_handle_t	*hdlp;
138*10923SEvan.Yan@Sun.COM 	int			count;
139*10923SEvan.Yan@Sun.COM 	int			ret;
140*10923SEvan.Yan@Sun.COM 
141*10923SEvan.Yan@Sun.COM 	DDI_HP_NEXDBG((CE_CONT, "ndi_hp_unregister: dip %p, cn name %s\n",
142*10923SEvan.Yan@Sun.COM 	    (void *)dip, cn_name));
143*10923SEvan.Yan@Sun.COM 
144*10923SEvan.Yan@Sun.COM 	ASSERT(!servicing_interrupt());
145*10923SEvan.Yan@Sun.COM 	if (servicing_interrupt())
146*10923SEvan.Yan@Sun.COM 		return (NDI_FAILURE);
147*10923SEvan.Yan@Sun.COM 
148*10923SEvan.Yan@Sun.COM 	/* Validate the arguments */
149*10923SEvan.Yan@Sun.COM 	if ((dip == NULL) || (cn_name == NULL))
150*10923SEvan.Yan@Sun.COM 		return (NDI_EINVAL);
151*10923SEvan.Yan@Sun.COM 
152*10923SEvan.Yan@Sun.COM 	ndi_devi_enter(dip, &count);
153*10923SEvan.Yan@Sun.COM 
154*10923SEvan.Yan@Sun.COM 	hdlp = ddihp_cn_name_to_handle(dip, cn_name);
155*10923SEvan.Yan@Sun.COM 	if (hdlp == NULL) {
156*10923SEvan.Yan@Sun.COM 		ndi_devi_exit(dip, count);
157*10923SEvan.Yan@Sun.COM 		return (NDI_EINVAL);
158*10923SEvan.Yan@Sun.COM 	}
159*10923SEvan.Yan@Sun.COM 
160*10923SEvan.Yan@Sun.COM 	switch (ddihp_cn_unregister(hdlp)) {
161*10923SEvan.Yan@Sun.COM 	case DDI_SUCCESS:
162*10923SEvan.Yan@Sun.COM 		ret = NDI_SUCCESS;
163*10923SEvan.Yan@Sun.COM 		break;
164*10923SEvan.Yan@Sun.COM 	case DDI_EINVAL:
165*10923SEvan.Yan@Sun.COM 		ret = NDI_EINVAL;
166*10923SEvan.Yan@Sun.COM 		break;
167*10923SEvan.Yan@Sun.COM 	case DDI_EBUSY:
168*10923SEvan.Yan@Sun.COM 		ret = NDI_BUSY;
169*10923SEvan.Yan@Sun.COM 		break;
170*10923SEvan.Yan@Sun.COM 	default:
171*10923SEvan.Yan@Sun.COM 		ret = NDI_FAILURE;
172*10923SEvan.Yan@Sun.COM 		break;
173*10923SEvan.Yan@Sun.COM 	}
174*10923SEvan.Yan@Sun.COM 
175*10923SEvan.Yan@Sun.COM 	ndi_devi_exit(dip, count);
176*10923SEvan.Yan@Sun.COM 
177*10923SEvan.Yan@Sun.COM 	return (ret);
178*10923SEvan.Yan@Sun.COM }
179*10923SEvan.Yan@Sun.COM 
180*10923SEvan.Yan@Sun.COM /*
181*10923SEvan.Yan@Sun.COM  * Notify the Hotplug Connection (CN) to change state.
182*10923SEvan.Yan@Sun.COM  * Flag:
183*10923SEvan.Yan@Sun.COM  *	DDI_HP_REQ_SYNC	    Return after the change is finished.
184*10923SEvan.Yan@Sun.COM  *	DDI_HP_REQ_ASYNC    Return after the request is dispatched.
185*10923SEvan.Yan@Sun.COM  */
186*10923SEvan.Yan@Sun.COM int
ndi_hp_state_change_req(dev_info_t * dip,char * cn_name,ddi_hp_cn_state_t state,uint_t flag)187*10923SEvan.Yan@Sun.COM ndi_hp_state_change_req(dev_info_t *dip, char *cn_name,
188*10923SEvan.Yan@Sun.COM     ddi_hp_cn_state_t state, uint_t flag)
189*10923SEvan.Yan@Sun.COM {
190*10923SEvan.Yan@Sun.COM 	ddi_hp_cn_async_event_entry_t	*eventp;
191*10923SEvan.Yan@Sun.COM 
192*10923SEvan.Yan@Sun.COM 	DDI_HP_NEXDBG((CE_CONT, "ndi_hp_state_change_req: dip %p "
193*10923SEvan.Yan@Sun.COM 	    "cn_name: %s, state %x, flag %x\n",
194*10923SEvan.Yan@Sun.COM 	    (void *)dip, cn_name, state, flag));
195*10923SEvan.Yan@Sun.COM 
196*10923SEvan.Yan@Sun.COM 	/* Validate the arguments */
197*10923SEvan.Yan@Sun.COM 	if (dip == NULL || cn_name == NULL)
198*10923SEvan.Yan@Sun.COM 		return (NDI_EINVAL);
199*10923SEvan.Yan@Sun.COM 
200*10923SEvan.Yan@Sun.COM 	if (!NEXUS_HAS_HP_OP(dip)) {
201*10923SEvan.Yan@Sun.COM 		return (NDI_ENOTSUP);
202*10923SEvan.Yan@Sun.COM 	}
203*10923SEvan.Yan@Sun.COM 	/*
204*10923SEvan.Yan@Sun.COM 	 * If the request is to handle the event synchronously, then call
205*10923SEvan.Yan@Sun.COM 	 * the event handler without queuing the event.
206*10923SEvan.Yan@Sun.COM 	 */
207*10923SEvan.Yan@Sun.COM 	if (flag & DDI_HP_REQ_SYNC) {
208*10923SEvan.Yan@Sun.COM 		ddi_hp_cn_handle_t	*hdlp;
209*10923SEvan.Yan@Sun.COM 		int			count;
210*10923SEvan.Yan@Sun.COM 		int			ret;
211*10923SEvan.Yan@Sun.COM 
212*10923SEvan.Yan@Sun.COM 		ASSERT(!servicing_interrupt());
213*10923SEvan.Yan@Sun.COM 		if (servicing_interrupt())
214*10923SEvan.Yan@Sun.COM 			return (NDI_FAILURE);
215*10923SEvan.Yan@Sun.COM 
216*10923SEvan.Yan@Sun.COM 		ndi_devi_enter(dip, &count);
217*10923SEvan.Yan@Sun.COM 
218*10923SEvan.Yan@Sun.COM 		hdlp = ddihp_cn_name_to_handle(dip, cn_name);
219*10923SEvan.Yan@Sun.COM 		if (hdlp == NULL) {
220*10923SEvan.Yan@Sun.COM 			ndi_devi_exit(dip, count);
221*10923SEvan.Yan@Sun.COM 
222*10923SEvan.Yan@Sun.COM 			return (NDI_EINVAL);
223*10923SEvan.Yan@Sun.COM 		}
224*10923SEvan.Yan@Sun.COM 
225*10923SEvan.Yan@Sun.COM 		DDI_HP_NEXDBG((CE_CONT, "ndi_hp_state_change_req: hdlp %p "
226*10923SEvan.Yan@Sun.COM 		    "calling ddihp_cn_req_handler() directly to handle "
227*10923SEvan.Yan@Sun.COM 		    "target_state %x\n", (void *)hdlp, state));
228*10923SEvan.Yan@Sun.COM 
229*10923SEvan.Yan@Sun.COM 		ret = ddihp_cn_req_handler(hdlp, state);
230*10923SEvan.Yan@Sun.COM 
231*10923SEvan.Yan@Sun.COM 		ndi_devi_exit(dip, count);
232*10923SEvan.Yan@Sun.COM 
233*10923SEvan.Yan@Sun.COM 		return (ret);
234*10923SEvan.Yan@Sun.COM 	}
235*10923SEvan.Yan@Sun.COM 
236*10923SEvan.Yan@Sun.COM 	eventp = kmem_zalloc(sizeof (ddi_hp_cn_async_event_entry_t),
237*10923SEvan.Yan@Sun.COM 	    KM_NOSLEEP);
238*10923SEvan.Yan@Sun.COM 	if (eventp == NULL)
239*10923SEvan.Yan@Sun.COM 		return (NDI_NOMEM);
240*10923SEvan.Yan@Sun.COM 
241*10923SEvan.Yan@Sun.COM 	eventp->cn_name = ddi_strdup(cn_name, KM_NOSLEEP);
242*10923SEvan.Yan@Sun.COM 	if (eventp->cn_name == NULL) {
243*10923SEvan.Yan@Sun.COM 		kmem_free(eventp, sizeof (ddi_hp_cn_async_event_entry_t));
244*10923SEvan.Yan@Sun.COM 		return (NDI_NOMEM);
245*10923SEvan.Yan@Sun.COM 	}
246*10923SEvan.Yan@Sun.COM 	eventp->dip = dip;
247*10923SEvan.Yan@Sun.COM 	eventp->target_state = state;
248*10923SEvan.Yan@Sun.COM 
249*10923SEvan.Yan@Sun.COM 	/*
250*10923SEvan.Yan@Sun.COM 	 * Hold the parent's ref so that it won't disappear when the taskq is
251*10923SEvan.Yan@Sun.COM 	 * scheduled to run.
252*10923SEvan.Yan@Sun.COM 	 */
253*10923SEvan.Yan@Sun.COM 	ndi_hold_devi(dip);
254*10923SEvan.Yan@Sun.COM 
255*10923SEvan.Yan@Sun.COM 	if (!taskq_dispatch(system_taskq, ddihp_cn_run_event, eventp,
256*10923SEvan.Yan@Sun.COM 	    TQ_NOSLEEP)) {
257*10923SEvan.Yan@Sun.COM 		ndi_rele_devi(dip);
258*10923SEvan.Yan@Sun.COM 		DDI_HP_NEXDBG((CE_CONT, "ndi_hp_state_change_req: "
259*10923SEvan.Yan@Sun.COM 		    "taskq_dispatch failed! dip %p "
260*10923SEvan.Yan@Sun.COM 		    "target_state %x\n", (void *)dip, state));
261*10923SEvan.Yan@Sun.COM 		return (NDI_NOMEM);
262*10923SEvan.Yan@Sun.COM 	}
263*10923SEvan.Yan@Sun.COM 
264*10923SEvan.Yan@Sun.COM 	return (NDI_CLAIMED);
265*10923SEvan.Yan@Sun.COM }
266*10923SEvan.Yan@Sun.COM 
267*10923SEvan.Yan@Sun.COM /*
268*10923SEvan.Yan@Sun.COM  * Walk the link of Hotplug Connection handles of a dip:
269*10923SEvan.Yan@Sun.COM  *	DEVI(dip)->devi_hp_hdlp->[link of connections]
270*10923SEvan.Yan@Sun.COM  */
271*10923SEvan.Yan@Sun.COM void
ndi_hp_walk_cn(dev_info_t * dip,int (* f)(ddi_hp_cn_info_t *,void *),void * arg)272*10923SEvan.Yan@Sun.COM ndi_hp_walk_cn(dev_info_t *dip, int (*f)(ddi_hp_cn_info_t *,
273*10923SEvan.Yan@Sun.COM     void *), void *arg)
274*10923SEvan.Yan@Sun.COM {
275*10923SEvan.Yan@Sun.COM 	int			count;
276*10923SEvan.Yan@Sun.COM 	ddi_hp_cn_handle_t	*head, *curr, *prev;
277*10923SEvan.Yan@Sun.COM 
278*10923SEvan.Yan@Sun.COM 	DDI_HP_NEXDBG((CE_CONT, "ndi_hp_walk_cn: dip %p arg %p\n",
279*10923SEvan.Yan@Sun.COM 	    (void *)dip, arg));
280*10923SEvan.Yan@Sun.COM 
281*10923SEvan.Yan@Sun.COM 	ASSERT(!servicing_interrupt());
282*10923SEvan.Yan@Sun.COM 	if (servicing_interrupt())
283*10923SEvan.Yan@Sun.COM 		return;
284*10923SEvan.Yan@Sun.COM 
285*10923SEvan.Yan@Sun.COM 	/* Validate the arguments */
286*10923SEvan.Yan@Sun.COM 	if (dip == NULL)
287*10923SEvan.Yan@Sun.COM 		return;
288*10923SEvan.Yan@Sun.COM 
289*10923SEvan.Yan@Sun.COM 	ndi_devi_enter(dip, &count);
290*10923SEvan.Yan@Sun.COM 
291*10923SEvan.Yan@Sun.COM 	head = DEVI(dip)->devi_hp_hdlp;
292*10923SEvan.Yan@Sun.COM 	curr = head;
293*10923SEvan.Yan@Sun.COM 	prev = NULL;
294*10923SEvan.Yan@Sun.COM 	while (curr != NULL) {
295*10923SEvan.Yan@Sun.COM 		DDI_HP_NEXDBG((CE_CONT, "ndi_hp_walk_cn: dip %p "
296*10923SEvan.Yan@Sun.COM 		    "current cn_name: %s\n",
297*10923SEvan.Yan@Sun.COM 		    (void *)dip, curr->cn_info.cn_name));
298*10923SEvan.Yan@Sun.COM 		switch ((*f)(&(curr->cn_info), arg)) {
299*10923SEvan.Yan@Sun.COM 		case DDI_WALK_TERMINATE:
300*10923SEvan.Yan@Sun.COM 			ndi_devi_exit(dip, count);
301*10923SEvan.Yan@Sun.COM 
302*10923SEvan.Yan@Sun.COM 			return;
303*10923SEvan.Yan@Sun.COM 		case DDI_WALK_CONTINUE:
304*10923SEvan.Yan@Sun.COM 		default:
305*10923SEvan.Yan@Sun.COM 			if (DEVI(dip)->devi_hp_hdlp != head) {
306*10923SEvan.Yan@Sun.COM 				/*
307*10923SEvan.Yan@Sun.COM 				 * The current node is head and it is removed
308*10923SEvan.Yan@Sun.COM 				 * by last call to (*f)()
309*10923SEvan.Yan@Sun.COM 				 */
310*10923SEvan.Yan@Sun.COM 				head = DEVI(dip)->devi_hp_hdlp;
311*10923SEvan.Yan@Sun.COM 				curr = head;
312*10923SEvan.Yan@Sun.COM 				prev = NULL;
313*10923SEvan.Yan@Sun.COM 			} else if (prev && prev->next != curr) {
314*10923SEvan.Yan@Sun.COM 				/*
315*10923SEvan.Yan@Sun.COM 				 * The current node is a middle node or tail
316*10923SEvan.Yan@Sun.COM 				 * node and it is removed by last call to
317*10923SEvan.Yan@Sun.COM 				 * (*f)()
318*10923SEvan.Yan@Sun.COM 				 */
319*10923SEvan.Yan@Sun.COM 				curr = prev->next;
320*10923SEvan.Yan@Sun.COM 			} else {
321*10923SEvan.Yan@Sun.COM 				/* no removal accurred on curr node */
322*10923SEvan.Yan@Sun.COM 				prev = curr;
323*10923SEvan.Yan@Sun.COM 				curr = curr->next;
324*10923SEvan.Yan@Sun.COM 			}
325*10923SEvan.Yan@Sun.COM 		}
326*10923SEvan.Yan@Sun.COM 	}
327*10923SEvan.Yan@Sun.COM 	ndi_devi_exit(dip, count);
328*10923SEvan.Yan@Sun.COM }
329*10923SEvan.Yan@Sun.COM 
330*10923SEvan.Yan@Sun.COM /*
331*10923SEvan.Yan@Sun.COM  * Local functions (called within this file)
332*10923SEvan.Yan@Sun.COM  */
333*10923SEvan.Yan@Sun.COM 
334*10923SEvan.Yan@Sun.COM /*
335*10923SEvan.Yan@Sun.COM  * Wrapper function for ddihp_cn_req_handler() called from taskq
336*10923SEvan.Yan@Sun.COM  */
337*10923SEvan.Yan@Sun.COM static void
ddihp_cn_run_event(void * arg)338*10923SEvan.Yan@Sun.COM ddihp_cn_run_event(void *arg)
339*10923SEvan.Yan@Sun.COM {
340*10923SEvan.Yan@Sun.COM 	ddi_hp_cn_async_event_entry_t	*eventp =
341*10923SEvan.Yan@Sun.COM 	    (ddi_hp_cn_async_event_entry_t *)arg;
342*10923SEvan.Yan@Sun.COM 	dev_info_t			*dip = eventp->dip;
343*10923SEvan.Yan@Sun.COM 	ddi_hp_cn_handle_t		*hdlp;
344*10923SEvan.Yan@Sun.COM 	int				count;
345*10923SEvan.Yan@Sun.COM 
346*10923SEvan.Yan@Sun.COM 	/* Lock before access */
347*10923SEvan.Yan@Sun.COM 	ndi_devi_enter(dip, &count);
348*10923SEvan.Yan@Sun.COM 
349*10923SEvan.Yan@Sun.COM 	hdlp = ddihp_cn_name_to_handle(dip, eventp->cn_name);
350*10923SEvan.Yan@Sun.COM 	if (hdlp) {
351*10923SEvan.Yan@Sun.COM 		(void) ddihp_cn_req_handler(hdlp, eventp->target_state);
352*10923SEvan.Yan@Sun.COM 	} else {
353*10923SEvan.Yan@Sun.COM 		DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_run_event: no handle for "
354*10923SEvan.Yan@Sun.COM 		    "cn_name: %s dip %p. Request for target_state %x is"
355*10923SEvan.Yan@Sun.COM 		    " dropped. \n",
356*10923SEvan.Yan@Sun.COM 		    eventp->cn_name, (void *)dip, eventp->target_state));
357*10923SEvan.Yan@Sun.COM 	}
358*10923SEvan.Yan@Sun.COM 
359*10923SEvan.Yan@Sun.COM 	ndi_devi_exit(dip, count);
360*10923SEvan.Yan@Sun.COM 
361*10923SEvan.Yan@Sun.COM 	/* Release the devi's ref that is held from interrupt context. */
362*10923SEvan.Yan@Sun.COM 	ndi_rele_devi((dev_info_t *)DEVI(dip));
363*10923SEvan.Yan@Sun.COM 	kmem_free(eventp->cn_name, strlen(eventp->cn_name) + 1);
364*10923SEvan.Yan@Sun.COM 	kmem_free(eventp, sizeof (ddi_hp_cn_async_event_entry_t));
365*10923SEvan.Yan@Sun.COM }
366*10923SEvan.Yan@Sun.COM 
367*10923SEvan.Yan@Sun.COM /*
368*10923SEvan.Yan@Sun.COM  * Handle state change request of a Hotplug Connection (CN)
369*10923SEvan.Yan@Sun.COM  */
370*10923SEvan.Yan@Sun.COM static int
ddihp_cn_req_handler(ddi_hp_cn_handle_t * hdlp,ddi_hp_cn_state_t target_state)371*10923SEvan.Yan@Sun.COM ddihp_cn_req_handler(ddi_hp_cn_handle_t *hdlp,
372*10923SEvan.Yan@Sun.COM     ddi_hp_cn_state_t target_state)
373*10923SEvan.Yan@Sun.COM {
374*10923SEvan.Yan@Sun.COM 	dev_info_t	*dip = hdlp->cn_dip;
375*10923SEvan.Yan@Sun.COM 	int		ret = DDI_SUCCESS;
376*10923SEvan.Yan@Sun.COM 
377*10923SEvan.Yan@Sun.COM 	DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_req_handler:"
378*10923SEvan.Yan@Sun.COM 	    " hdlp %p, target_state %x\n",
379*10923SEvan.Yan@Sun.COM 	    (void *)hdlp, target_state));
380*10923SEvan.Yan@Sun.COM 
381*10923SEvan.Yan@Sun.COM 	ASSERT(DEVI_BUSY_OWNED(dip));
382*10923SEvan.Yan@Sun.COM 
383*10923SEvan.Yan@Sun.COM 	if (ddihp_cn_getstate(hdlp) != DDI_SUCCESS) {
384*10923SEvan.Yan@Sun.COM 		DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_req_handler: dip %p, "
385*10923SEvan.Yan@Sun.COM 		    "hdlp %p ddi_cn_getstate failed\n", (void *)dip,
386*10923SEvan.Yan@Sun.COM 		    (void *)hdlp));
387*10923SEvan.Yan@Sun.COM 
388*10923SEvan.Yan@Sun.COM 		return (NDI_UNCLAIMED);
389*10923SEvan.Yan@Sun.COM 	}
390*10923SEvan.Yan@Sun.COM 	if (hdlp->cn_info.cn_state != target_state) {
391*10923SEvan.Yan@Sun.COM 		ddi_hp_cn_state_t result_state = 0;
392*10923SEvan.Yan@Sun.COM 
393*10923SEvan.Yan@Sun.COM 		DDIHP_CN_OPS(hdlp, DDI_HPOP_CN_CHANGE_STATE,
394*10923SEvan.Yan@Sun.COM 		    (void *)&target_state, (void *)&result_state, ret);
395*10923SEvan.Yan@Sun.COM 
396*10923SEvan.Yan@Sun.COM 		DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_req_handler: dip %p, "
397*10923SEvan.Yan@Sun.COM 		    "hdlp %p changed state to %x, ret=%x\n",
398*10923SEvan.Yan@Sun.COM 		    (void *)dip, (void *)hdlp, result_state, ret));
399*10923SEvan.Yan@Sun.COM 	}
400*10923SEvan.Yan@Sun.COM 
401*10923SEvan.Yan@Sun.COM 	if (ret == DDI_SUCCESS)
402*10923SEvan.Yan@Sun.COM 		return (NDI_CLAIMED);
403*10923SEvan.Yan@Sun.COM 	else
404*10923SEvan.Yan@Sun.COM 		return (NDI_UNCLAIMED);
405*10923SEvan.Yan@Sun.COM }
406