4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /*
26 * Layered driver support.
27 */
28
29 #include <sys/atomic.h>
30 #include <sys/types.h>
31 #include <sys/t_lock.h>
32 #include <sys/param.h>
33 #include <sys/conf.h>
34 #include <sys/systm.h>
35 #include <sys/sysmacros.h>
36 #include <sys/buf.h>
37 #include <sys/cred.h>
38 #include <sys/uio.h>
39 #include <sys/vnode.h>
40 #include <sys/fs/snode.h>
41 #include <sys/open.h>
42 #include <sys/kmem.h>
43 #include <sys/file.h>
110 #define NDI_EVENT_SERVICE "NDI_EVENT_SERVICE"
111
112 static void ldi_ev_lock(void);
113 static void ldi_ev_unlock(void);
114
115 #ifdef LDI_OBSOLETE_EVENT
116 int ldi_remove_event_handler(ldi_handle_t lh, ldi_callback_id_t id);
117 #endif
118
119
120 /*
121 * globals
122 */
123 static kmutex_t ldi_ident_hash_lock[LI_HASH_SZ];
124 static struct ldi_ident *ldi_ident_hash[LI_HASH_SZ];
125
126 static kmutex_t ldi_handle_hash_lock[LH_HASH_SZ];
127 static struct ldi_handle *ldi_handle_hash[LH_HASH_SZ];
128 static size_t ldi_handle_hash_count;
129
130 static struct ldi_ev_callback_list ldi_ev_callback_list;
131
132 static uint32_t ldi_ev_id_pool = 0;
133
134 struct ldi_ev_cookie {
135 char *ck_evname;
136 uint_t ck_sync;
137 uint_t ck_ctype;
138 };
139
140 static struct ldi_ev_cookie ldi_ev_cookies[] = {
141 { LDI_EV_OFFLINE, 1, CT_DEV_EV_OFFLINE},
142 { LDI_EV_DEGRADE, 0, CT_DEV_EV_DEGRADED},
143 { LDI_EV_DEVICE_REMOVE, 0, 0},
144 { NULL} /* must terminate list */
145 };
146
147 void
148 ldi_init(void)
149 {
150 int i;
151
152 ldi_handle_hash_count = 0;
153 for (i = 0; i < LH_HASH_SZ; i++) {
154 mutex_init(&ldi_handle_hash_lock[i], NULL, MUTEX_DEFAULT, NULL);
155 ldi_handle_hash[i] = NULL;
156 }
157 for (i = 0; i < LI_HASH_SZ; i++) {
158 mutex_init(&ldi_ident_hash_lock[i], NULL, MUTEX_DEFAULT, NULL);
159 ldi_ident_hash[i] = NULL;
160 }
161
162 /*
163 * Initialize the LDI event subsystem
164 */
165 mutex_init(&ldi_ev_callback_list.le_lock, NULL, MUTEX_DEFAULT, NULL);
166 cv_init(&ldi_ev_callback_list.le_cv, NULL, CV_DEFAULT, NULL);
167 ldi_ev_callback_list.le_busy = 0;
168 ldi_ev_callback_list.le_thread = NULL;
169 list_create(&ldi_ev_callback_list.le_head,
170 sizeof (ldi_ev_callback_impl_t),
171 offsetof(ldi_ev_callback_impl_t, lec_list));
172 }
173
174 /*
175 * LDI ident manipulation functions
176 */
177 static uint_t
178 ident_hash_func(modid_t modid, dev_info_t *dip, dev_t dev)
179 {
180 if (dip != NULL) {
181 uintptr_t k = (uintptr_t)dip;
182 k >>= (int)highbit(sizeof (struct dev_info));
183 return ((uint_t)k);
184 } else if (dev != DDI_DEV_T_NONE) {
185 return (modid + getminor(dev) + getmajor(dev));
186 } else {
187 return (modid);
188 }
3312 {
3313 ldi_ev_callback_impl_t *lecp;
3314 list_t *listp;
3315 int ret;
3316 char *lec_event;
3317
3318 ASSERT(dip);
3319 ASSERT(dev != DDI_DEV_T_NONE);
3320 ASSERT(dev != NODEV);
3321 ASSERT((dev == DDI_DEV_T_ANY && spec_type == 0) ||
3322 (spec_type == S_IFCHR || spec_type == S_IFBLK));
3323 ASSERT(event);
3324 ASSERT(ldi_native_event(event));
3325 ASSERT(ldi_ev_sync_event(event));
3326
3327 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): entered: dip=%p, ev=%s",
3328 (void *)dip, event));
3329
3330 ret = LDI_EV_NONE;
3331 ldi_ev_lock();
3332 listp = &ldi_ev_callback_list.le_head;
3333 for (lecp = list_head(listp); lecp; lecp = list_next(listp, lecp)) {
3334
3335 /* Check if matching device */
3336 if (!ldi_ev_device_match(lecp, dip, dev, spec_type))
3337 continue;
3338
3339 if (lecp->lec_lhp == NULL) {
3340 /*
3341 * Consumer has unregistered the handle and so
3342 * is no longer interested in notify events.
3343 */
3344 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): No LDI "
3345 "handle, skipping"));
3346 continue;
3347 }
3348
3349 if (lecp->lec_notify == NULL) {
3350 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): No notify "
3351 "callback. skipping"));
3352 continue; /* not interested in notify */
3353 }
3369 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): notify"
3370 " FAILURE"));
3371 break;
3372 }
3373
3374 /* We have a matching callback that allows the event to occur */
3375 ret = LDI_EV_SUCCESS;
3376
3377 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): 1 consumer success"));
3378 }
3379
3380 if (ret != LDI_EV_FAILURE)
3381 goto out;
3382
3383 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): undoing notify"));
3384
3385 /*
3386 * Undo notifies already sent
3387 */
3388 lecp = list_prev(listp, lecp);
3389 for (; lecp; lecp = list_prev(listp, lecp)) {
3390
3391 /*
3392 * Check if matching device
3393 */
3394 if (!ldi_ev_device_match(lecp, dip, dev, spec_type))
3395 continue;
3396
3397
3398 if (lecp->lec_finalize == NULL) {
3399 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): no finalize, "
3400 "skipping"));
3401 continue; /* not interested in finalize */
3402 }
3403
3404 /*
3405 * it is possible that in response to a notify event a
3406 * layered driver closed its LDI handle so it is ok
3407 * to have a NULL LDI handle for finalize. The layered
3408 * driver is expected to maintain state in its "arg"
3409 * parameter to keep track of the closed device.
3420 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): calling finalize"));
3421
3422 lecp->lec_finalize(lecp->lec_lhp, lecp->lec_cookie,
3423 LDI_EV_FAILURE, lecp->lec_arg, ev_data);
3424
3425 /*
3426 * If LDI native event and LDI handle closed in context
3427 * of notify, NULL out the finalize callback as we have
3428 * already called the 1 finalize above allowed in this situation
3429 */
3430 if (lecp->lec_lhp == NULL &&
3431 ldi_native_cookie(lecp->lec_cookie)) {
3432 LDI_EVDBG((CE_NOTE,
3433 "ldi_invoke_notify(): NULL-ing finalize after "
3434 "calling 1 finalize following ldi_close"));
3435 lecp->lec_finalize = NULL;
3436 }
3437 }
3438
3439 out:
3440 ldi_ev_unlock();
3441
3442 if (ret == LDI_EV_NONE) {
3443 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): no matching "
3444 "LDI callbacks"));
3445 }
3446
3447 return (ret);
3448 }
3449
3450 /*
3451 * Framework function to be called from a layered driver to propagate
3452 * LDI "notify" events to exported minors.
3453 *
3454 * This function is a public interface exported by the LDI framework
3455 * for use by layered drivers to propagate device events up the software
3456 * stack.
3457 */
3458 int
3459 ldi_ev_notify(dev_info_t *dip, minor_t minor, int spec_type,
3535 int ldi_result, void *ev_data)
3536 {
3537 ldi_ev_callback_impl_t *lecp;
3538 list_t *listp;
3539 char *lec_event;
3540 int found = 0;
3541
3542 ASSERT(dip);
3543 ASSERT(dev != DDI_DEV_T_NONE);
3544 ASSERT(dev != NODEV);
3545 ASSERT((dev == DDI_DEV_T_ANY && spec_type == 0) ||
3546 (spec_type == S_IFCHR || spec_type == S_IFBLK));
3547 ASSERT(event);
3548 ASSERT(ldi_native_event(event));
3549 ASSERT(ldi_result == LDI_EV_SUCCESS || ldi_result == LDI_EV_FAILURE);
3550
3551 LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): entered: dip=%p, result=%d"
3552 " event=%s", (void *)dip, ldi_result, event));
3553
3554 ldi_ev_lock();
3555 listp = &ldi_ev_callback_list.le_head;
3556 for (lecp = list_head(listp); lecp; lecp = list_next(listp, lecp)) {
3557
3558 if (lecp->lec_finalize == NULL) {
3559 LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): No "
3560 "finalize. Skipping"));
3561 continue; /* Not interested in finalize */
3562 }
3563
3564 /*
3565 * Check if matching device
3566 */
3567 if (!ldi_ev_device_match(lecp, dip, dev, spec_type))
3568 continue;
3569
3570 /*
3571 * It is valid for the LDI handle to be NULL during finalize.
3572 * The layered driver may have done an LDI close in the notify
3573 * callback.
3574 */
3575
3576 /*
3587 LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): calling finalize"));
3588
3589 found = 1;
3590
3591 lecp->lec_finalize(lecp->lec_lhp, lecp->lec_cookie,
3592 ldi_result, lecp->lec_arg, ev_data);
3593
3594 /*
3595 * If LDI native event and LDI handle closed in context
3596 * of notify, NULL out the finalize callback as we have
3597 * already called the 1 finalize above allowed in this situation
3598 */
3599 if (lecp->lec_lhp == NULL &&
3600 ldi_native_cookie(lecp->lec_cookie)) {
3601 LDI_EVDBG((CE_NOTE,
3602 "ldi_invoke_finalize(): NULLing finalize after "
3603 "calling 1 finalize following ldi_close"));
3604 lecp->lec_finalize = NULL;
3605 }
3606 }
3607 ldi_ev_unlock();
3608
3609 if (found)
3610 return;
3611
3612 LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): no matching callbacks"));
3613 }
3614
3615 /*
3616 * Framework function to be called from a layered driver to propagate
3617 * LDI "finalize" events to exported minors.
3618 *
3619 * This function is a public interface exported by the LDI framework
3620 * for use by layered drivers to propagate device events up the software
3621 * stack.
3622 */
3623 void
3624 ldi_ev_finalize(dev_info_t *dip, minor_t minor, int spec_type, int ldi_result,
3625 ldi_ev_cookie_t cookie, void *ev_data)
3626 {
3667 ldi_ev_callback_impl_t *found;
3668 list_t *listp;
3669
3670 ASSERT(!servicing_interrupt());
3671
3672 if (id == 0) {
3673 cmn_err(CE_WARN, "ldi_ev_remove_callbacks: Invalid ID 0");
3674 return (LDI_EV_FAILURE);
3675 }
3676
3677 LDI_EVDBG((CE_NOTE, "ldi_ev_remove_callbacks: entered: id=%p",
3678 (void *)id));
3679
3680 ldi_ev_lock();
3681
3682 listp = &ldi_ev_callback_list.le_head;
3683 next = found = NULL;
3684 for (lecp = list_head(listp); lecp; lecp = next) {
3685 next = list_next(listp, lecp);
3686 if (lecp->lec_id == id) {
3687 ASSERT(found == NULL);
3688 list_remove(listp, lecp);
3689 found = lecp;
3690 }
3691 }
3692 ldi_ev_unlock();
3693
3694 if (found == NULL) {
3695 cmn_err(CE_WARN, "No LDI event handler for id (%p)",
3696 (void *)id);
3697 return (LDI_EV_SUCCESS);
3698 }
3699
3700 if (!ldi_native_cookie(found->lec_cookie)) {
3701 ASSERT(found->lec_notify == NULL);
3702 if (ddi_remove_event_handler((ddi_callback_id_t)id)
3703 != DDI_SUCCESS) {
3704 cmn_err(CE_WARN, "failed to remove NDI event handler "
3705 "for id (%p)", (void *)id);
3706 ldi_ev_lock();
3707 list_insert_tail(listp, found);
|
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24 /*
25 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
26 */
27
28 /*
29 * Layered driver support.
30 */
31
32 #include <sys/atomic.h>
33 #include <sys/types.h>
34 #include <sys/t_lock.h>
35 #include <sys/param.h>
36 #include <sys/conf.h>
37 #include <sys/systm.h>
38 #include <sys/sysmacros.h>
39 #include <sys/buf.h>
40 #include <sys/cred.h>
41 #include <sys/uio.h>
42 #include <sys/vnode.h>
43 #include <sys/fs/snode.h>
44 #include <sys/open.h>
45 #include <sys/kmem.h>
46 #include <sys/file.h>
113 #define NDI_EVENT_SERVICE "NDI_EVENT_SERVICE"
114
115 static void ldi_ev_lock(void);
116 static void ldi_ev_unlock(void);
117
118 #ifdef LDI_OBSOLETE_EVENT
119 int ldi_remove_event_handler(ldi_handle_t lh, ldi_callback_id_t id);
120 #endif
121
122
123 /*
124 * globals
125 */
126 static kmutex_t ldi_ident_hash_lock[LI_HASH_SZ];
127 static struct ldi_ident *ldi_ident_hash[LI_HASH_SZ];
128
129 static kmutex_t ldi_handle_hash_lock[LH_HASH_SZ];
130 static struct ldi_handle *ldi_handle_hash[LH_HASH_SZ];
131 static size_t ldi_handle_hash_count;
132
133 /*
134 * Use of "ldi_ev_callback_list" must be protected by ldi_ev_lock()
135 * and ldi_ev_unlock().
136 */
137 static struct ldi_ev_callback_list ldi_ev_callback_list;
138
139 static uint32_t ldi_ev_id_pool = 0;
140
141 struct ldi_ev_cookie {
142 char *ck_evname;
143 uint_t ck_sync;
144 uint_t ck_ctype;
145 };
146
147 static struct ldi_ev_cookie ldi_ev_cookies[] = {
148 { LDI_EV_OFFLINE, 1, CT_DEV_EV_OFFLINE},
149 { LDI_EV_DEGRADE, 0, CT_DEV_EV_DEGRADED},
150 { LDI_EV_DEVICE_REMOVE, 0, 0},
151 { NULL} /* must terminate list */
152 };
153
154 void
155 ldi_init(void)
156 {
157 int i;
158
159 ldi_handle_hash_count = 0;
160 for (i = 0; i < LH_HASH_SZ; i++) {
161 mutex_init(&ldi_handle_hash_lock[i], NULL, MUTEX_DEFAULT, NULL);
162 ldi_handle_hash[i] = NULL;
163 }
164 for (i = 0; i < LI_HASH_SZ; i++) {
165 mutex_init(&ldi_ident_hash_lock[i], NULL, MUTEX_DEFAULT, NULL);
166 ldi_ident_hash[i] = NULL;
167 }
168
169 /*
170 * Initialize the LDI event subsystem
171 */
172 mutex_init(&ldi_ev_callback_list.le_lock, NULL, MUTEX_DEFAULT, NULL);
173 cv_init(&ldi_ev_callback_list.le_cv, NULL, CV_DEFAULT, NULL);
174 ldi_ev_callback_list.le_busy = 0;
175 ldi_ev_callback_list.le_thread = NULL;
176 ldi_ev_callback_list.le_walker_next = NULL;
177 ldi_ev_callback_list.le_walker_prev = NULL;
178 list_create(&ldi_ev_callback_list.le_head,
179 sizeof (ldi_ev_callback_impl_t),
180 offsetof(ldi_ev_callback_impl_t, lec_list));
181 }
182
183 /*
184 * LDI ident manipulation functions
185 */
186 static uint_t
187 ident_hash_func(modid_t modid, dev_info_t *dip, dev_t dev)
188 {
189 if (dip != NULL) {
190 uintptr_t k = (uintptr_t)dip;
191 k >>= (int)highbit(sizeof (struct dev_info));
192 return ((uint_t)k);
193 } else if (dev != DDI_DEV_T_NONE) {
194 return (modid + getminor(dev) + getmajor(dev));
195 } else {
196 return (modid);
197 }
3321 {
3322 ldi_ev_callback_impl_t *lecp;
3323 list_t *listp;
3324 int ret;
3325 char *lec_event;
3326
3327 ASSERT(dip);
3328 ASSERT(dev != DDI_DEV_T_NONE);
3329 ASSERT(dev != NODEV);
3330 ASSERT((dev == DDI_DEV_T_ANY && spec_type == 0) ||
3331 (spec_type == S_IFCHR || spec_type == S_IFBLK));
3332 ASSERT(event);
3333 ASSERT(ldi_native_event(event));
3334 ASSERT(ldi_ev_sync_event(event));
3335
3336 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): entered: dip=%p, ev=%s",
3337 (void *)dip, event));
3338
3339 ret = LDI_EV_NONE;
3340 ldi_ev_lock();
3341
3342 VERIFY(ldi_ev_callback_list.le_walker_next == NULL);
3343 listp = &ldi_ev_callback_list.le_head;
3344 for (lecp = list_head(listp); lecp; lecp =
3345 ldi_ev_callback_list.le_walker_next) {
3346 ldi_ev_callback_list.le_walker_next = list_next(listp, lecp);
3347
3348 /* Check if matching device */
3349 if (!ldi_ev_device_match(lecp, dip, dev, spec_type))
3350 continue;
3351
3352 if (lecp->lec_lhp == NULL) {
3353 /*
3354 * Consumer has unregistered the handle and so
3355 * is no longer interested in notify events.
3356 */
3357 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): No LDI "
3358 "handle, skipping"));
3359 continue;
3360 }
3361
3362 if (lecp->lec_notify == NULL) {
3363 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): No notify "
3364 "callback. skipping"));
3365 continue; /* not interested in notify */
3366 }
3382 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): notify"
3383 " FAILURE"));
3384 break;
3385 }
3386
3387 /* We have a matching callback that allows the event to occur */
3388 ret = LDI_EV_SUCCESS;
3389
3390 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): 1 consumer success"));
3391 }
3392
3393 if (ret != LDI_EV_FAILURE)
3394 goto out;
3395
3396 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): undoing notify"));
3397
3398 /*
3399 * Undo notifies already sent
3400 */
3401 lecp = list_prev(listp, lecp);
3402 VERIFY(ldi_ev_callback_list.le_walker_prev == NULL);
3403 for (; lecp; lecp = ldi_ev_callback_list.le_walker_prev) {
3404 ldi_ev_callback_list.le_walker_prev = list_prev(listp, lecp);
3405
3406 /*
3407 * Check if matching device
3408 */
3409 if (!ldi_ev_device_match(lecp, dip, dev, spec_type))
3410 continue;
3411
3412
3413 if (lecp->lec_finalize == NULL) {
3414 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): no finalize, "
3415 "skipping"));
3416 continue; /* not interested in finalize */
3417 }
3418
3419 /*
3420 * it is possible that in response to a notify event a
3421 * layered driver closed its LDI handle so it is ok
3422 * to have a NULL LDI handle for finalize. The layered
3423 * driver is expected to maintain state in its "arg"
3424 * parameter to keep track of the closed device.
3435 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): calling finalize"));
3436
3437 lecp->lec_finalize(lecp->lec_lhp, lecp->lec_cookie,
3438 LDI_EV_FAILURE, lecp->lec_arg, ev_data);
3439
3440 /*
3441 * If LDI native event and LDI handle closed in context
3442 * of notify, NULL out the finalize callback as we have
3443 * already called the 1 finalize above allowed in this situation
3444 */
3445 if (lecp->lec_lhp == NULL &&
3446 ldi_native_cookie(lecp->lec_cookie)) {
3447 LDI_EVDBG((CE_NOTE,
3448 "ldi_invoke_notify(): NULL-ing finalize after "
3449 "calling 1 finalize following ldi_close"));
3450 lecp->lec_finalize = NULL;
3451 }
3452 }
3453
3454 out:
3455 ldi_ev_callback_list.le_walker_next = NULL;
3456 ldi_ev_callback_list.le_walker_prev = NULL;
3457 ldi_ev_unlock();
3458
3459 if (ret == LDI_EV_NONE) {
3460 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): no matching "
3461 "LDI callbacks"));
3462 }
3463
3464 return (ret);
3465 }
3466
3467 /*
3468 * Framework function to be called from a layered driver to propagate
3469 * LDI "notify" events to exported minors.
3470 *
3471 * This function is a public interface exported by the LDI framework
3472 * for use by layered drivers to propagate device events up the software
3473 * stack.
3474 */
3475 int
3476 ldi_ev_notify(dev_info_t *dip, minor_t minor, int spec_type,
3552 int ldi_result, void *ev_data)
3553 {
3554 ldi_ev_callback_impl_t *lecp;
3555 list_t *listp;
3556 char *lec_event;
3557 int found = 0;
3558
3559 ASSERT(dip);
3560 ASSERT(dev != DDI_DEV_T_NONE);
3561 ASSERT(dev != NODEV);
3562 ASSERT((dev == DDI_DEV_T_ANY && spec_type == 0) ||
3563 (spec_type == S_IFCHR || spec_type == S_IFBLK));
3564 ASSERT(event);
3565 ASSERT(ldi_native_event(event));
3566 ASSERT(ldi_result == LDI_EV_SUCCESS || ldi_result == LDI_EV_FAILURE);
3567
3568 LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): entered: dip=%p, result=%d"
3569 " event=%s", (void *)dip, ldi_result, event));
3570
3571 ldi_ev_lock();
3572 VERIFY(ldi_ev_callback_list.le_walker_next == NULL);
3573 listp = &ldi_ev_callback_list.le_head;
3574 for (lecp = list_head(listp); lecp; lecp =
3575 ldi_ev_callback_list.le_walker_next) {
3576 ldi_ev_callback_list.le_walker_next = list_next(listp, lecp);
3577
3578 if (lecp->lec_finalize == NULL) {
3579 LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): No "
3580 "finalize. Skipping"));
3581 continue; /* Not interested in finalize */
3582 }
3583
3584 /*
3585 * Check if matching device
3586 */
3587 if (!ldi_ev_device_match(lecp, dip, dev, spec_type))
3588 continue;
3589
3590 /*
3591 * It is valid for the LDI handle to be NULL during finalize.
3592 * The layered driver may have done an LDI close in the notify
3593 * callback.
3594 */
3595
3596 /*
3607 LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): calling finalize"));
3608
3609 found = 1;
3610
3611 lecp->lec_finalize(lecp->lec_lhp, lecp->lec_cookie,
3612 ldi_result, lecp->lec_arg, ev_data);
3613
3614 /*
3615 * If LDI native event and LDI handle closed in context
3616 * of notify, NULL out the finalize callback as we have
3617 * already called the 1 finalize above allowed in this situation
3618 */
3619 if (lecp->lec_lhp == NULL &&
3620 ldi_native_cookie(lecp->lec_cookie)) {
3621 LDI_EVDBG((CE_NOTE,
3622 "ldi_invoke_finalize(): NULLing finalize after "
3623 "calling 1 finalize following ldi_close"));
3624 lecp->lec_finalize = NULL;
3625 }
3626 }
3627 ldi_ev_callback_list.le_walker_next = NULL;
3628 ldi_ev_unlock();
3629
3630 if (found)
3631 return;
3632
3633 LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): no matching callbacks"));
3634 }
3635
3636 /*
3637 * Framework function to be called from a layered driver to propagate
3638 * LDI "finalize" events to exported minors.
3639 *
3640 * This function is a public interface exported by the LDI framework
3641 * for use by layered drivers to propagate device events up the software
3642 * stack.
3643 */
3644 void
3645 ldi_ev_finalize(dev_info_t *dip, minor_t minor, int spec_type, int ldi_result,
3646 ldi_ev_cookie_t cookie, void *ev_data)
3647 {
3688 ldi_ev_callback_impl_t *found;
3689 list_t *listp;
3690
3691 ASSERT(!servicing_interrupt());
3692
3693 if (id == 0) {
3694 cmn_err(CE_WARN, "ldi_ev_remove_callbacks: Invalid ID 0");
3695 return (LDI_EV_FAILURE);
3696 }
3697
3698 LDI_EVDBG((CE_NOTE, "ldi_ev_remove_callbacks: entered: id=%p",
3699 (void *)id));
3700
3701 ldi_ev_lock();
3702
3703 listp = &ldi_ev_callback_list.le_head;
3704 next = found = NULL;
3705 for (lecp = list_head(listp); lecp; lecp = next) {
3706 next = list_next(listp, lecp);
3707 if (lecp->lec_id == id) {
3708 VERIFY(found == NULL);
3709
3710 /*
3711 * If there is a walk in progress, shift that walk
3712 * along to the next element so that we can remove
3713 * this one. This allows us to unregister an arbitrary
3714 * number of callbacks from within a callback.
3715 *
3716 * See the struct definition (in sunldi_impl.h) for
3717 * more information.
3718 */
3719 if (ldi_ev_callback_list.le_walker_next == lecp)
3720 ldi_ev_callback_list.le_walker_next = next;
3721 if (ldi_ev_callback_list.le_walker_prev == lecp)
3722 ldi_ev_callback_list.le_walker_prev = list_prev(
3723 listp, ldi_ev_callback_list.le_walker_prev);
3724
3725 list_remove(listp, lecp);
3726 found = lecp;
3727 }
3728 }
3729 ldi_ev_unlock();
3730
3731 if (found == NULL) {
3732 cmn_err(CE_WARN, "No LDI event handler for id (%p)",
3733 (void *)id);
3734 return (LDI_EV_SUCCESS);
3735 }
3736
3737 if (!ldi_native_cookie(found->lec_cookie)) {
3738 ASSERT(found->lec_notify == NULL);
3739 if (ddi_remove_event_handler((ddi_callback_id_t)id)
3740 != DDI_SUCCESS) {
3741 cmn_err(CE_WARN, "failed to remove NDI event handler "
3742 "for id (%p)", (void *)id);
3743 ldi_ev_lock();
3744 list_insert_tail(listp, found);
|