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