1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Layered driver support. 31 */ 32 33 #include <sys/atomic.h> 34 #include <sys/types.h> 35 #include <sys/t_lock.h> 36 #include <sys/param.h> 37 #include <sys/conf.h> 38 #include <sys/systm.h> 39 #include <sys/sysmacros.h> 40 #include <sys/buf.h> 41 #include <sys/cred.h> 42 #include <sys/uio.h> 43 #include <sys/vnode.h> 44 #include <sys/fs/snode.h> 45 #include <sys/open.h> 46 #include <sys/kmem.h> 47 #include <sys/file.h> 48 #include <sys/bootconf.h> 49 #include <sys/pathname.h> 50 #include <sys/bitmap.h> 51 #include <sys/stat.h> 52 #include <sys/dditypes.h> 53 #include <sys/ddi_impldefs.h> 54 #include <sys/ddi.h> 55 #include <sys/sunddi.h> 56 #include <sys/sunndi.h> 57 #include <sys/esunddi.h> 58 #include <sys/autoconf.h> 59 #include <sys/sunldi.h> 60 #include <sys/sunldi_impl.h> 61 #include <sys/errno.h> 62 #include <sys/debug.h> 63 #include <sys/modctl.h> 64 #include <sys/var.h> 65 #include <vm/seg_vn.h> 66 67 #include <sys/stropts.h> 68 #include <sys/strsubr.h> 69 #include <sys/socket.h> 70 #include <sys/socketvar.h> 71 #include <sys/kstr.h> 72 73 74 /* 75 * Define macros to manipulate snode, vnode, and open device flags 76 */ 77 #define VTYP_VALID(i) (((i) == VCHR) || ((i) == VBLK)) 78 #define VTYP_TO_OTYP(i) (((i) == VCHR) ? OTYP_CHR : OTYP_BLK) 79 #define VTYP_TO_STYP(i) (((i) == VCHR) ? S_IFCHR : S_IFBLK) 80 81 #define OTYP_VALID(i) (((i) == OTYP_CHR) || ((i) == OTYP_BLK)) 82 #define OTYP_TO_VTYP(i) (((i) == OTYP_CHR) ? VCHR : VBLK) 83 #define OTYP_TO_STYP(i) (((i) == OTYP_CHR) ? S_IFCHR : S_IFBLK) 84 85 #define STYP_VALID(i) (((i) == S_IFCHR) || ((i) == S_IFBLK)) 86 #define STYP_TO_VTYP(i) (((i) == S_IFCHR) ? VCHR : VBLK) 87 88 /* 89 * Define macros for accessing layered driver hash structures 90 */ 91 #define LH_HASH(vp) (handle_hash_func(vp) % LH_HASH_SZ) 92 #define LI_HASH(mid, dip, dev) (ident_hash_func(mid, dip, dev) % LI_HASH_SZ) 93 94 /* 95 * Define layered handle flags used in the lh_type field 96 */ 97 #define LH_STREAM (0x1) /* handle to a streams device */ 98 #define LH_CBDEV (0x2) /* handle to a char/block device */ 99 100 /* 101 * Define marco for devid property lookups 102 */ 103 #define DEVID_PROP_FLAGS (DDI_PROP_DONTPASS | \ 104 DDI_PROP_TYPE_STRING|DDI_PROP_CANSLEEP) 105 106 107 /* 108 * globals 109 */ 110 static kmutex_t ldi_ident_hash_lock[LI_HASH_SZ]; 111 static struct ldi_ident *ldi_ident_hash[LI_HASH_SZ]; 112 113 static kmutex_t ldi_handle_hash_lock[LH_HASH_SZ]; 114 static struct ldi_handle *ldi_handle_hash[LH_HASH_SZ]; 115 static size_t ldi_handle_hash_count; 116 117 void 118 ldi_init(void) 119 { 120 int i; 121 122 ldi_handle_hash_count = 0; 123 for (i = 0; i < LH_HASH_SZ; i++) { 124 mutex_init(&ldi_handle_hash_lock[i], NULL, MUTEX_DEFAULT, NULL); 125 ldi_handle_hash[i] = NULL; 126 } 127 for (i = 0; i < LI_HASH_SZ; i++) { 128 mutex_init(&ldi_ident_hash_lock[i], NULL, MUTEX_DEFAULT, NULL); 129 ldi_ident_hash[i] = NULL; 130 } 131 } 132 133 /* 134 * LDI ident manipulation functions 135 */ 136 static uint_t 137 ident_hash_func(modid_t modid, dev_info_t *dip, dev_t dev) 138 { 139 if (dip != NULL) { 140 uintptr_t k = (uintptr_t)dip; 141 k >>= (int)highbit(sizeof (struct dev_info)); 142 return ((uint_t)k); 143 } else if (dev != DDI_DEV_T_NONE) { 144 return (modid + getminor(dev) + getmajor(dev)); 145 } else { 146 return (modid); 147 } 148 } 149 150 static struct ldi_ident ** 151 ident_find_ref_nolock(modid_t modid, dev_info_t *dip, dev_t dev, major_t major) 152 { 153 struct ldi_ident **lipp = NULL; 154 uint_t index = LI_HASH(modid, dip, dev); 155 156 ASSERT(MUTEX_HELD(&ldi_ident_hash_lock[index])); 157 158 for (lipp = &(ldi_ident_hash[index]); 159 (*lipp != NULL); 160 lipp = &((*lipp)->li_next)) { 161 if (((*lipp)->li_modid == modid) && 162 ((*lipp)->li_major == major) && 163 ((*lipp)->li_dip == dip) && 164 ((*lipp)->li_dev == dev)) 165 break; 166 } 167 168 ASSERT(lipp != NULL); 169 return (lipp); 170 } 171 172 static struct ldi_ident * 173 ident_alloc(char *mod_name, dev_info_t *dip, dev_t dev, major_t major) 174 { 175 struct ldi_ident *lip, **lipp; 176 modid_t modid; 177 uint_t index; 178 179 ASSERT(mod_name != NULL); 180 181 /* get the module id */ 182 modid = mod_name_to_modid(mod_name); 183 ASSERT(modid != -1); 184 185 /* allocate a new ident in case we need it */ 186 lip = kmem_zalloc(sizeof (*lip), KM_SLEEP); 187 188 /* search the hash for a matching ident */ 189 index = LI_HASH(modid, dip, dev); 190 mutex_enter(&ldi_ident_hash_lock[index]); 191 lipp = ident_find_ref_nolock(modid, dip, dev, major); 192 193 if (*lipp != NULL) { 194 /* we found an indent in the hash */ 195 ASSERT(strcmp((*lipp)->li_modname, mod_name) == 0); 196 (*lipp)->li_ref++; 197 mutex_exit(&ldi_ident_hash_lock[index]); 198 kmem_free(lip, sizeof (struct ldi_ident)); 199 return (*lipp); 200 } 201 202 /* initialize the new ident */ 203 lip->li_next = NULL; 204 lip->li_ref = 1; 205 lip->li_modid = modid; 206 lip->li_major = major; 207 lip->li_dip = dip; 208 lip->li_dev = dev; 209 (void) strncpy(lip->li_modname, mod_name, sizeof (lip->li_modname) - 1); 210 211 /* add it to the ident hash */ 212 lip->li_next = ldi_ident_hash[index]; 213 ldi_ident_hash[index] = lip; 214 215 mutex_exit(&ldi_ident_hash_lock[index]); 216 return (lip); 217 } 218 219 static void 220 ident_hold(struct ldi_ident *lip) 221 { 222 uint_t index; 223 224 ASSERT(lip != NULL); 225 index = LI_HASH(lip->li_modid, lip->li_dip, lip->li_dev); 226 mutex_enter(&ldi_ident_hash_lock[index]); 227 ASSERT(lip->li_ref > 0); 228 lip->li_ref++; 229 mutex_exit(&ldi_ident_hash_lock[index]); 230 } 231 232 static void 233 ident_release(struct ldi_ident *lip) 234 { 235 struct ldi_ident **lipp; 236 uint_t index; 237 238 ASSERT(lip != NULL); 239 index = LI_HASH(lip->li_modid, lip->li_dip, lip->li_dev); 240 mutex_enter(&ldi_ident_hash_lock[index]); 241 242 ASSERT(lip->li_ref > 0); 243 if (--lip->li_ref > 0) { 244 /* there are more references to this ident */ 245 mutex_exit(&ldi_ident_hash_lock[index]); 246 return; 247 } 248 249 /* this was the last reference/open for this ident. free it. */ 250 lipp = ident_find_ref_nolock( 251 lip->li_modid, lip->li_dip, lip->li_dev, lip->li_major); 252 253 ASSERT((lipp != NULL) && (*lipp != NULL)); 254 *lipp = lip->li_next; 255 mutex_exit(&ldi_ident_hash_lock[index]); 256 kmem_free(lip, sizeof (struct ldi_ident)); 257 } 258 259 /* 260 * LDI handle manipulation functions 261 */ 262 static uint_t 263 handle_hash_func(void *vp) 264 { 265 uintptr_t k = (uintptr_t)vp; 266 k >>= (int)highbit(sizeof (vnode_t)); 267 return ((uint_t)k); 268 } 269 270 static struct ldi_handle ** 271 handle_find_ref_nolock(vnode_t *vp, struct ldi_ident *ident) 272 { 273 struct ldi_handle **lhpp = NULL; 274 uint_t index = LH_HASH(vp); 275 276 ASSERT(MUTEX_HELD(&ldi_handle_hash_lock[index])); 277 278 for (lhpp = &(ldi_handle_hash[index]); 279 (*lhpp != NULL); 280 lhpp = &((*lhpp)->lh_next)) { 281 if (((*lhpp)->lh_ident == ident) && 282 ((*lhpp)->lh_vp == vp)) 283 break; 284 } 285 286 ASSERT(lhpp != NULL); 287 return (lhpp); 288 } 289 290 static struct ldi_handle * 291 handle_find(vnode_t *vp, struct ldi_ident *ident) 292 { 293 struct ldi_handle **lhpp; 294 int index = LH_HASH(vp); 295 296 mutex_enter(&ldi_handle_hash_lock[index]); 297 lhpp = handle_find_ref_nolock(vp, ident); 298 mutex_exit(&ldi_handle_hash_lock[index]); 299 ASSERT(lhpp != NULL); 300 return (*lhpp); 301 } 302 303 static struct ldi_handle * 304 handle_alloc(vnode_t *vp, struct ldi_ident *ident) 305 { 306 struct ldi_handle *lhp, **lhpp; 307 uint_t index; 308 309 ASSERT((vp != NULL) && (ident != NULL)); 310 311 /* allocate a new handle in case we need it */ 312 lhp = kmem_zalloc(sizeof (*lhp), KM_SLEEP); 313 314 /* search the hash for a matching handle */ 315 index = LH_HASH(vp); 316 mutex_enter(&ldi_handle_hash_lock[index]); 317 lhpp = handle_find_ref_nolock(vp, ident); 318 319 if (*lhpp != NULL) { 320 /* we found a handle in the hash */ 321 (*lhpp)->lh_ref++; 322 mutex_exit(&ldi_handle_hash_lock[index]); 323 324 LDI_ALLOCFREE((CE_WARN, "ldi handle alloc: dup " 325 "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x", 326 (void *)*lhpp, (void *)ident, (void *)vp, 327 mod_major_to_name(getmajor(vp->v_rdev)), 328 getminor(vp->v_rdev))); 329 330 kmem_free(lhp, sizeof (struct ldi_handle)); 331 return (*lhpp); 332 } 333 334 /* initialize the new handle */ 335 lhp->lh_ref = 1; 336 lhp->lh_vp = vp; 337 lhp->lh_ident = ident; 338 mutex_init(lhp->lh_lock, NULL, MUTEX_DEFAULT, NULL); 339 340 /* set the device type for this handle */ 341 lhp->lh_type = 0; 342 if (STREAMSTAB(getmajor(vp->v_rdev))) { 343 ASSERT(vp->v_type == VCHR); 344 lhp->lh_type |= LH_STREAM; 345 } else { 346 lhp->lh_type |= LH_CBDEV; 347 } 348 349 /* get holds on other objects */ 350 ident_hold(ident); 351 ASSERT(vp->v_count >= 1); 352 VN_HOLD(vp); 353 354 /* add it to the handle hash */ 355 lhp->lh_next = ldi_handle_hash[index]; 356 ldi_handle_hash[index] = lhp; 357 atomic_add_long(&ldi_handle_hash_count, 1); 358 359 LDI_ALLOCFREE((CE_WARN, "ldi handle alloc: new " 360 "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x", 361 (void *)lhp, (void *)ident, (void *)vp, 362 mod_major_to_name(getmajor(vp->v_rdev)), 363 getminor(vp->v_rdev))); 364 365 mutex_exit(&ldi_handle_hash_lock[index]); 366 return (lhp); 367 } 368 369 static void 370 handle_release(struct ldi_handle *lhp) 371 { 372 struct ldi_handle **lhpp; 373 uint_t index; 374 375 ASSERT(lhp != NULL); 376 377 index = LH_HASH(lhp->lh_vp); 378 mutex_enter(&ldi_handle_hash_lock[index]); 379 380 LDI_ALLOCFREE((CE_WARN, "ldi handle release: " 381 "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x", 382 (void *)lhp, (void *)lhp->lh_ident, (void *)lhp->lh_vp, 383 mod_major_to_name(getmajor(lhp->lh_vp->v_rdev)), 384 getminor(lhp->lh_vp->v_rdev))); 385 386 ASSERT(lhp->lh_ref > 0); 387 if (--lhp->lh_ref > 0) { 388 /* there are more references to this handle */ 389 mutex_exit(&ldi_handle_hash_lock[index]); 390 return; 391 } 392 393 /* this was the last reference/open for this handle. free it. */ 394 lhpp = handle_find_ref_nolock(lhp->lh_vp, lhp->lh_ident); 395 ASSERT((lhpp != NULL) && (*lhpp != NULL)); 396 *lhpp = lhp->lh_next; 397 atomic_add_long(&ldi_handle_hash_count, -1); 398 mutex_exit(&ldi_handle_hash_lock[index]); 399 400 VN_RELE(lhp->lh_vp); 401 ident_release(lhp->lh_ident); 402 mutex_destroy(lhp->lh_lock); 403 kmem_free(lhp, sizeof (struct ldi_handle)); 404 } 405 406 /* 407 * LDI event manipulation functions 408 */ 409 static void 410 handle_event_add(ldi_event_t *lep) 411 { 412 struct ldi_handle *lhp = lep->le_lhp; 413 414 ASSERT(lhp != NULL); 415 416 mutex_enter(lhp->lh_lock); 417 if (lhp->lh_events == NULL) { 418 lhp->lh_events = lep; 419 mutex_exit(lhp->lh_lock); 420 return; 421 } 422 423 lep->le_next = lhp->lh_events; 424 lhp->lh_events->le_prev = lep; 425 lhp->lh_events = lep; 426 mutex_exit(lhp->lh_lock); 427 } 428 429 static void 430 handle_event_remove(ldi_event_t *lep) 431 { 432 struct ldi_handle *lhp = lep->le_lhp; 433 434 ASSERT(lhp != NULL); 435 436 mutex_enter(lhp->lh_lock); 437 if (lep->le_prev) 438 lep->le_prev->le_next = lep->le_next; 439 if (lep->le_next) 440 lep->le_next->le_prev = lep->le_prev; 441 if (lhp->lh_events == lep) 442 lhp->lh_events = lep->le_next; 443 mutex_exit(lhp->lh_lock); 444 445 } 446 447 static void 448 i_ldi_callback(dev_info_t *dip, ddi_eventcookie_t event_cookie, 449 void *arg, void *bus_impldata) 450 { 451 ldi_event_t *lep = (ldi_event_t *)arg; 452 453 ASSERT(lep != NULL); 454 455 LDI_EVENTCB((CE_NOTE, "%s: dip=0x%p, " 456 "event_cookie=0x%p, ldi_eventp=0x%p", "i_ldi_callback", 457 (void *)dip, (void *)event_cookie, (void *)lep)); 458 459 lep->le_handler(lep->le_lhp, event_cookie, lep->le_arg, bus_impldata); 460 } 461 462 /* 463 * LDI open helper functions 464 */ 465 466 /* get a vnode to a device by dev_t and otyp */ 467 static int 468 ldi_vp_from_dev(dev_t dev, int otyp, vnode_t **vpp) 469 { 470 dev_info_t *dip; 471 vnode_t *vp; 472 473 /* sanity check required input parameters */ 474 if ((dev == DDI_DEV_T_NONE) || (!OTYP_VALID(otyp)) || (vpp == NULL)) 475 return (EINVAL); 476 477 if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL) 478 return (ENODEV); 479 480 if (STREAMSTAB(getmajor(dev)) && (otyp != OTYP_CHR)) { 481 ddi_release_devi(dip); /* from e_ddi_hold_devi_by_dev */ 482 return (ENXIO); 483 } 484 485 vp = makespecvp(dev, OTYP_TO_VTYP(otyp)); 486 spec_assoc_vp_with_devi(vp, dip); 487 ddi_release_devi(dip); /* from e_ddi_hold_devi_by_dev */ 488 489 *vpp = vp; 490 return (0); 491 } 492 493 /* get a vnode to a device by pathname */ 494 static int 495 ldi_vp_from_name(char *path, vnode_t **vpp) 496 { 497 vnode_t *vp = NULL; 498 int ret; 499 500 /* sanity check required input parameters */ 501 if ((path == NULL) || (vpp == NULL)) 502 return (EINVAL); 503 504 if (modrootloaded) { 505 cred_t *saved_cred = curthread->t_cred; 506 507 /* we don't want lookupname to fail because of credentials */ 508 curthread->t_cred = kcred; 509 510 /* 511 * all lookups should be done in the global zone. but 512 * lookupnameat() won't actually do this if an absolute 513 * path is passed in. since the ldi interfaces require an 514 * absolute path we pass lookupnameat() a pointer to 515 * the character after the leading '/' and tell it to 516 * start searching at the current system root directory. 517 */ 518 ASSERT(*path == '/'); 519 ret = lookupnameat(path + 1, UIO_SYSSPACE, FOLLOW, NULLVPP, 520 &vp, rootdir); 521 522 /* restore this threads credentials */ 523 curthread->t_cred = saved_cred; 524 525 if (ret == 0) { 526 if (!vn_matchops(vp, spec_getvnodeops()) || 527 !VTYP_VALID(vp->v_type)) { 528 VN_RELE(vp); 529 return (ENXIO); 530 } 531 } 532 } 533 534 if (vp == NULL) { 535 dev_info_t *dip; 536 dev_t dev; 537 int spec_type; 538 539 /* 540 * Root is not mounted, the minor node is not specified, 541 * or an OBP path has been specified. 542 */ 543 544 /* 545 * Determine if path can be pruned to produce an 546 * OBP or devfs path for resolve_pathname. 547 */ 548 if (strncmp(path, "/devices/", 9) == 0) 549 path += strlen("/devices"); 550 551 /* 552 * if no minor node was specified the DEFAULT minor node 553 * will be returned. if there is no DEFAULT minor node 554 * one will be fabricated of type S_IFCHR with the minor 555 * number equal to the instance number. 556 */ 557 ret = resolve_pathname(path, &dip, &dev, &spec_type); 558 if (ret != 0) 559 return (ENODEV); 560 561 ASSERT(STYP_VALID(spec_type)); 562 vp = makespecvp(dev, STYP_TO_VTYP(spec_type)); 563 spec_assoc_vp_with_devi(vp, dip); 564 ddi_release_devi(dip); 565 } 566 567 *vpp = vp; 568 return (0); 569 } 570 571 static int 572 ldi_devid_match(ddi_devid_t devid, dev_info_t *dip, dev_t dev) 573 { 574 char *devidstr; 575 ddi_prop_t *propp; 576 577 /* convert devid as a string property */ 578 if ((devidstr = ddi_devid_str_encode(devid, NULL)) == NULL) 579 return (0); 580 581 /* 582 * Search for the devid. For speed and ease in locking this 583 * code directly uses the property implementation. See 584 * ddi_common_devid_to_devlist() for a comment as to why. 585 */ 586 mutex_enter(&(DEVI(dip)->devi_lock)); 587 588 /* check if there is a DDI_DEV_T_NONE devid property */ 589 propp = i_ddi_prop_search(DDI_DEV_T_NONE, 590 DEVID_PROP_NAME, DEVID_PROP_FLAGS, &DEVI(dip)->devi_hw_prop_ptr); 591 if (propp != NULL) { 592 if (ddi_devid_str_compare(propp->prop_val, devidstr) == 0) { 593 /* a DDI_DEV_T_NONE devid exists and matchs */ 594 mutex_exit(&(DEVI(dip)->devi_lock)); 595 ddi_devid_str_free(devidstr); 596 return (1); 597 } else { 598 /* a DDI_DEV_T_NONE devid exists and doesn't match */ 599 mutex_exit(&(DEVI(dip)->devi_lock)); 600 ddi_devid_str_free(devidstr); 601 return (0); 602 } 603 } 604 605 /* check if there is a devt specific devid property */ 606 propp = i_ddi_prop_search(dev, 607 DEVID_PROP_NAME, DEVID_PROP_FLAGS, &(DEVI(dip)->devi_hw_prop_ptr)); 608 if (propp != NULL) { 609 if (ddi_devid_str_compare(propp->prop_val, devidstr) == 0) { 610 /* a devt specific devid exists and matchs */ 611 mutex_exit(&(DEVI(dip)->devi_lock)); 612 ddi_devid_str_free(devidstr); 613 return (1); 614 } else { 615 /* a devt specific devid exists and doesn't match */ 616 mutex_exit(&(DEVI(dip)->devi_lock)); 617 ddi_devid_str_free(devidstr); 618 return (0); 619 } 620 } 621 622 /* we didn't find any devids associated with the device */ 623 mutex_exit(&(DEVI(dip)->devi_lock)); 624 ddi_devid_str_free(devidstr); 625 return (0); 626 } 627 628 /* get a handle to a device by devid and minor name */ 629 static int 630 ldi_vp_from_devid(ddi_devid_t devid, char *minor_name, vnode_t **vpp) 631 { 632 dev_info_t *dip; 633 vnode_t *vp; 634 int ret, i, ndevs, styp; 635 dev_t dev, *devs; 636 637 /* sanity check required input parameters */ 638 if ((devid == NULL) || (minor_name == NULL) || (vpp == NULL)) 639 return (EINVAL); 640 641 ret = ddi_lyr_devid_to_devlist(devid, minor_name, &ndevs, &devs); 642 if ((ret != DDI_SUCCESS) || (ndevs <= 0)) 643 return (ENODEV); 644 645 for (i = 0; i < ndevs; i++) { 646 dev = devs[i]; 647 648 if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL) 649 continue; 650 651 /* 652 * now we have to verify that the devid of the disk 653 * still matches what was requested. 654 * 655 * we have to do this because the devid could have 656 * changed between the call to ddi_lyr_devid_to_devlist() 657 * and e_ddi_hold_devi_by_dev(). this is because when 658 * ddi_lyr_devid_to_devlist() returns a list of devts 659 * there is no kind of hold on those devts so a device 660 * could have been replaced out from under us in the 661 * interim. 662 */ 663 if ((i_ddi_minorname_to_devtspectype(dip, minor_name, 664 NULL, &styp) == DDI_SUCCESS) && 665 ldi_devid_match(devid, dip, dev)) 666 break; 667 668 ddi_release_devi(dip); /* from e_ddi_hold_devi_by_dev() */ 669 } 670 671 ddi_lyr_free_devlist(devs, ndevs); 672 673 if (i == ndevs) 674 return (ENODEV); 675 676 ASSERT(STYP_VALID(styp)); 677 vp = makespecvp(dev, STYP_TO_VTYP(styp)); 678 spec_assoc_vp_with_devi(vp, dip); 679 ddi_release_devi(dip); /* from e_ddi_hold_devi_by_dev */ 680 681 *vpp = vp; 682 return (0); 683 } 684 685 /* given a vnode, open a device */ 686 static int 687 ldi_open_by_vp(vnode_t **vpp, int flag, cred_t *cr, 688 ldi_handle_t *lhp, struct ldi_ident *li) 689 { 690 struct ldi_handle *nlhp; 691 vnode_t *vp; 692 int err; 693 694 ASSERT((vpp != NULL) && (*vpp != NULL)); 695 ASSERT((lhp != NULL) && (li != NULL)); 696 697 vp = *vpp; 698 /* if the vnode passed in is not a device, then bail */ 699 if (!vn_matchops(vp, spec_getvnodeops()) || !VTYP_VALID(vp->v_type)) 700 return (ENXIO); 701 702 /* 703 * the caller may have specified a node that 704 * doesn't have cb_ops defined. the ldi doesn't yet 705 * support opening devices without a valid cb_ops. 706 */ 707 if (devopsp[getmajor(vp->v_rdev)]->devo_cb_ops == NULL) 708 return (ENXIO); 709 710 /* open the device */ 711 if ((err = VOP_OPEN(&vp, flag | FKLYR, cr)) != 0) 712 return (err); 713 714 /* possible clone open, make sure that we still have a spec node */ 715 ASSERT(vn_matchops(vp, spec_getvnodeops())); 716 717 nlhp = handle_alloc(vp, li); 718 719 if (vp != *vpp) { 720 /* 721 * allocating the layered handle took a new hold on the vnode 722 * so we can release the hold that was returned by the clone 723 * open 724 */ 725 LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p", 726 "ldi clone open", (void *)nlhp)); 727 } else { 728 LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p", 729 "ldi open", (void *)nlhp)); 730 } 731 732 /* Flush back any dirty pages associated with the device. */ 733 if (nlhp->lh_type & LH_CBDEV) { 734 vnode_t *cvp = common_specvp(nlhp->lh_vp); 735 dev_t dev = cvp->v_rdev; 736 737 (void) VOP_PUTPAGE(cvp, 0, 0, B_INVAL, kcred); 738 bflush(dev); 739 } 740 741 *vpp = vp; 742 *lhp = (ldi_handle_t)nlhp; 743 return (0); 744 } 745 746 /* Call a drivers prop_op(9E) interface */ 747 static int 748 i_ldi_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 749 int flags, char *name, caddr_t valuep, int *lengthp) 750 { 751 struct dev_ops *ops = NULL; 752 int res; 753 754 ASSERT((dip != NULL) && (name != NULL)); 755 ASSERT((prop_op == PROP_LEN) || (valuep != NULL)); 756 ASSERT(lengthp != NULL); 757 758 /* 759 * we can only be invoked after a driver has been opened and 760 * someone has a layered handle to it, so there had better be 761 * a valid ops vector. 762 */ 763 ops = DEVI(dip)->devi_ops; 764 ASSERT(ops && ops->devo_cb_ops); 765 766 /* 767 * Some nexus drivers incorrectly set cb_prop_op to nodev, 768 * nulldev or even NULL. 769 */ 770 if ((ops->devo_cb_ops->cb_prop_op == nodev) || 771 (ops->devo_cb_ops->cb_prop_op == nulldev) || 772 (ops->devo_cb_ops->cb_prop_op == NULL)) { 773 return (DDI_PROP_NOT_FOUND); 774 } 775 776 /* check if this is actually DDI_DEV_T_ANY query */ 777 if (flags & LDI_DEV_T_ANY) { 778 flags &= ~LDI_DEV_T_ANY; 779 dev = DDI_DEV_T_ANY; 780 } 781 782 res = cdev_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp); 783 return (res); 784 } 785 786 static void 787 i_ldi_prop_op_free(struct prop_driver_data *pdd) 788 { 789 kmem_free(pdd, pdd->pdd_size); 790 } 791 792 static caddr_t 793 i_ldi_prop_op_alloc(int prop_len) 794 { 795 struct prop_driver_data *pdd; 796 int pdd_size; 797 798 pdd_size = sizeof (struct prop_driver_data) + prop_len; 799 pdd = kmem_alloc(pdd_size, KM_SLEEP); 800 pdd->pdd_size = pdd_size; 801 pdd->pdd_prop_free = i_ldi_prop_op_free; 802 return ((caddr_t)&pdd[1]); 803 } 804 805 /* 806 * i_ldi_prop_op_typed() is a wrapper for i_ldi_prop_op that is used 807 * by the typed ldi property lookup interfaces. 808 */ 809 static int 810 i_ldi_prop_op_typed(dev_t dev, dev_info_t *dip, int flags, char *name, 811 caddr_t *datap, int *lengthp, int elem_size) 812 { 813 caddr_t prop_val; 814 int prop_len, res; 815 816 ASSERT((dip != NULL) && (name != NULL)); 817 ASSERT((datap != NULL) && (lengthp != NULL)); 818 819 /* 820 * first call the drivers prop_op() interface to allow it 821 * it to override default property values. 822 */ 823 res = i_ldi_prop_op(dev, dip, PROP_LEN, 824 flags | DDI_PROP_DYNAMIC, name, NULL, &prop_len); 825 if (res != DDI_PROP_SUCCESS) 826 return (DDI_PROP_NOT_FOUND); 827 828 /* sanity check the property length */ 829 if (prop_len == 0) { 830 /* 831 * the ddi typed interfaces don't allow a drivers to 832 * create properties with a length of 0. so we should 833 * prevent drivers from returning 0 length dynamic 834 * properties for typed property lookups. 835 */ 836 return (DDI_PROP_NOT_FOUND); 837 } 838 839 /* sanity check the property length against the element size */ 840 if (elem_size && ((prop_len % elem_size) != 0)) 841 return (DDI_PROP_NOT_FOUND); 842 843 /* 844 * got it. now allocate a prop_driver_data struct so that the 845 * user can free the property via ddi_prop_free(). 846 */ 847 prop_val = i_ldi_prop_op_alloc(prop_len); 848 849 /* lookup the property again, this time get the value */ 850 res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF, 851 flags | DDI_PROP_DYNAMIC, name, prop_val, &prop_len); 852 if (res != DDI_PROP_SUCCESS) { 853 ddi_prop_free(prop_val); 854 return (DDI_PROP_NOT_FOUND); 855 } 856 857 /* sanity check the property length */ 858 if (prop_len == 0) { 859 ddi_prop_free(prop_val); 860 return (DDI_PROP_NOT_FOUND); 861 } 862 863 /* sanity check the property length against the element size */ 864 if (elem_size && ((prop_len % elem_size) != 0)) { 865 ddi_prop_free(prop_val); 866 return (DDI_PROP_NOT_FOUND); 867 } 868 869 /* 870 * return the prop_driver_data struct and, optionally, the length 871 * of the data. 872 */ 873 *datap = prop_val; 874 *lengthp = prop_len; 875 876 return (DDI_PROP_SUCCESS); 877 } 878 879 /* 880 * i_check_string looks at a string property and makes sure its 881 * a valid null terminated string 882 */ 883 static int 884 i_check_string(char *str, int prop_len) 885 { 886 int i; 887 888 ASSERT(str != NULL); 889 890 for (i = 0; i < prop_len; i++) { 891 if (str[i] == '\0') 892 return (0); 893 } 894 return (1); 895 } 896 897 /* 898 * i_pack_string_array takes a a string array property that is represented 899 * as a concatination of strings (with the NULL character included for 900 * each string) and converts it into a format that can be returned by 901 * ldi_prop_lookup_string_array. 902 */ 903 static int 904 i_pack_string_array(char *str_concat, int prop_len, 905 char ***str_arrayp, int *nelemp) 906 { 907 int i, nelem, pack_size; 908 char **str_array, *strptr; 909 910 /* 911 * first we need to sanity check the input string array. 912 * in essence this can be done my making sure that the last 913 * character of the array passed in is null. (meaning the last 914 * string in the array is NULL terminated. 915 */ 916 if (str_concat[prop_len - 1] != '\0') 917 return (1); 918 919 /* now let's count the number of strings in the array */ 920 for (nelem = i = 0; i < prop_len; i++) 921 if (str_concat[i] == '\0') 922 nelem++; 923 ASSERT(nelem >= 1); 924 925 /* now let's allocate memory for the new packed property */ 926 pack_size = (sizeof (char *) * (nelem + 1)) + prop_len; 927 str_array = (char **)i_ldi_prop_op_alloc(pack_size); 928 929 /* let's copy the actual string data into the new property */ 930 strptr = (char *)&(str_array[nelem + 1]); 931 bcopy(str_concat, strptr, prop_len); 932 933 /* now initialize the string array pointers */ 934 for (i = 0; i < nelem; i++) { 935 str_array[i] = strptr; 936 strptr += strlen(strptr) + 1; 937 } 938 str_array[nelem] = NULL; 939 940 /* set the return values */ 941 *str_arrayp = str_array; 942 *nelemp = nelem; 943 944 return (0); 945 } 946 947 948 /* 949 * LDI Project private device usage interfaces 950 */ 951 952 /* 953 * Get a count of how many devices are currentl open by different consumers 954 */ 955 int 956 ldi_usage_count() 957 { 958 return (ldi_handle_hash_count); 959 } 960 961 static void 962 ldi_usage_walker_tgt_helper(ldi_usage_t *ldi_usage, vnode_t *vp) 963 { 964 dev_info_t *dip; 965 dev_t dev; 966 967 ASSERT(STYP_VALID(VTYP_TO_STYP(vp->v_type))); 968 969 /* get the target devt */ 970 dev = vp->v_rdev; 971 972 /* try to get the target dip */ 973 dip = VTOCS(vp)->s_dip; 974 if (dip != NULL) { 975 e_ddi_hold_devi(dip); 976 } else if (dev != DDI_DEV_T_NONE) { 977 dip = e_ddi_hold_devi_by_dev(dev, 0); 978 } 979 980 /* set the target information */ 981 ldi_usage->tgt_name = mod_major_to_name(getmajor(dev)); 982 ldi_usage->tgt_modid = mod_name_to_modid(ldi_usage->tgt_name); 983 ldi_usage->tgt_devt = dev; 984 ldi_usage->tgt_spec_type = VTYP_TO_STYP(vp->v_type); 985 ldi_usage->tgt_dip = dip; 986 } 987 988 989 static int 990 ldi_usage_walker_helper(struct ldi_ident *lip, vnode_t *vp, 991 void *arg, int (*callback)(const ldi_usage_t *, void *)) 992 { 993 ldi_usage_t ldi_usage; 994 struct devnames *dnp; 995 dev_info_t *dip; 996 major_t major; 997 dev_t dev; 998 int ret = LDI_USAGE_CONTINUE; 999 1000 /* set the target device information */ 1001 ldi_usage_walker_tgt_helper(&ldi_usage, vp); 1002 1003 /* get the source devt */ 1004 dev = lip->li_dev; 1005 1006 /* try to get the source dip */ 1007 dip = lip->li_dip; 1008 if (dip != NULL) { 1009 e_ddi_hold_devi(dip); 1010 } else if (dev != DDI_DEV_T_NONE) { 1011 dip = e_ddi_hold_devi_by_dev(dev, 0); 1012 } 1013 1014 /* set the valid source information */ 1015 ldi_usage.src_modid = lip->li_modid; 1016 ldi_usage.src_name = lip->li_modname; 1017 ldi_usage.src_devt = dev; 1018 ldi_usage.src_dip = dip; 1019 1020 /* 1021 * if the source ident represents either: 1022 * 1023 * - a kernel module (and not a device or device driver) 1024 * - a device node 1025 * 1026 * then we currently have all the info we need to report the 1027 * usage information so invoke the callback function. 1028 */ 1029 if (((lip->li_major == -1) && (dev == DDI_DEV_T_NONE)) || 1030 (dip != NULL)) { 1031 ret = callback(&ldi_usage, arg); 1032 if (dip != NULL) 1033 ddi_release_devi(dip); 1034 if (ldi_usage.tgt_dip != NULL) 1035 ddi_release_devi(ldi_usage.tgt_dip); 1036 return (ret); 1037 } 1038 1039 /* 1040 * now this is kinda gross. 1041 * 1042 * what we do here is attempt to associate every device instance 1043 * of the source driver on the system with the open target driver. 1044 * we do this because we don't know which instance of the device 1045 * could potentially access the lower device so we assume that all 1046 * the instances could access it. 1047 * 1048 * there are two ways we could have gotten here: 1049 * 1050 * 1) this layered ident represents one created using only a 1051 * major number or a driver module name. this means that when 1052 * it was created we could not associate it with a particular 1053 * dev_t or device instance. 1054 * 1055 * when could this possibly happen you ask? 1056 * 1057 * a perfect example of this is streams persistent links. 1058 * when a persistant streams link is formed we can't associate 1059 * the lower device stream with any particular upper device 1060 * stream or instance. this is because any particular upper 1061 * device stream could be closed, then another could be 1062 * opened with a different dev_t and device instance, and it 1063 * would still have access to the lower linked stream. 1064 * 1065 * since any instance of the upper streams driver could 1066 * potentially access the lower stream whenever it wants, 1067 * we represent that here by associating the opened lower 1068 * device with every existing device instance of the upper 1069 * streams driver. 1070 * 1071 * 2) This case should really never happen but we'll include it 1072 * for completeness. 1073 * 1074 * it's possible that we could have gotten here because we 1075 * have a dev_t for the upper device but we couldn't find a 1076 * dip associated with that dev_t. 1077 * 1078 * the only types of devices that have dev_t without an 1079 * associated dip are unbound DLPIv2 network devices. These 1080 * types of devices exist to be able to attach a stream to any 1081 * instance of a hardware network device. since these types of 1082 * devices are usually hardware devices they should never 1083 * really have other devices open. 1084 */ 1085 if (dev != DDI_DEV_T_NONE) 1086 major = getmajor(dev); 1087 else 1088 major = lip->li_major; 1089 1090 ASSERT((major >= 0) && (major < devcnt)); 1091 1092 dnp = &devnamesp[major]; 1093 LOCK_DEV_OPS(&dnp->dn_lock); 1094 dip = dnp->dn_head; 1095 while ((dip) && (ret == LDI_USAGE_CONTINUE)) { 1096 e_ddi_hold_devi(dip); 1097 UNLOCK_DEV_OPS(&dnp->dn_lock); 1098 1099 /* set the source dip */ 1100 ldi_usage.src_dip = dip; 1101 1102 /* invoke the callback function */ 1103 ret = callback(&ldi_usage, arg); 1104 1105 LOCK_DEV_OPS(&dnp->dn_lock); 1106 ddi_release_devi(dip); 1107 dip = ddi_get_next(dip); 1108 } 1109 UNLOCK_DEV_OPS(&dnp->dn_lock); 1110 1111 /* if there was a target dip, release it */ 1112 if (ldi_usage.tgt_dip != NULL) 1113 ddi_release_devi(ldi_usage.tgt_dip); 1114 1115 return (ret); 1116 } 1117 1118 /* 1119 * ldi_usage_walker() - this walker reports LDI kernel device usage 1120 * information via the callback() callback function. the LDI keeps track 1121 * of what devices are being accessed in its own internal data structures. 1122 * this function walks those data structures to determine device usage. 1123 */ 1124 void 1125 ldi_usage_walker(void *arg, int (*callback)(const ldi_usage_t *, void *)) 1126 { 1127 struct ldi_handle *lhp; 1128 struct ldi_ident *lip; 1129 vnode_t *vp; 1130 int i; 1131 int ret = LDI_USAGE_CONTINUE; 1132 1133 for (i = 0; i < LH_HASH_SZ; i++) { 1134 mutex_enter(&ldi_handle_hash_lock[i]); 1135 1136 lhp = ldi_handle_hash[i]; 1137 while ((lhp != NULL) && (ret == LDI_USAGE_CONTINUE)) { 1138 lip = lhp->lh_ident; 1139 vp = lhp->lh_vp; 1140 1141 /* invoke the devinfo callback function */ 1142 ret = ldi_usage_walker_helper(lip, vp, arg, callback); 1143 1144 lhp = lhp->lh_next; 1145 } 1146 mutex_exit(&ldi_handle_hash_lock[i]); 1147 1148 if (ret != LDI_USAGE_CONTINUE) 1149 break; 1150 } 1151 } 1152 1153 /* 1154 * LDI Project private interfaces (streams linking interfaces) 1155 * 1156 * Streams supports a type of built in device layering via linking. 1157 * Certain types of streams drivers can be streams multiplexors. 1158 * A streams multiplexor supports the I_LINK/I_PLINK operation. 1159 * These operations allows other streams devices to be linked under the 1160 * multiplexor. By definition all streams multiplexors are devices 1161 * so this linking is a type of device layering where the multiplexor 1162 * device is layered on top of the device linked below it. 1163 */ 1164 1165 /* 1166 * ldi_mlink_lh() is invoked when streams are linked using LDI handles. 1167 * It is not used for normal I_LINKs and I_PLINKs using file descriptors. 1168 * 1169 * The streams framework keeps track of links via the file_t of the lower 1170 * stream. The LDI keeps track of devices using a vnode. In the case 1171 * of a streams link created via an LDI handle, fnk_lh() allocates 1172 * a file_t that the streams framework can use to track the linkage. 1173 */ 1174 int 1175 ldi_mlink_lh(vnode_t *vp, int cmd, intptr_t arg, cred_t *crp, int *rvalp) 1176 { 1177 struct ldi_handle *lhp = (struct ldi_handle *)arg; 1178 vnode_t *vpdown; 1179 file_t *fpdown; 1180 int err; 1181 1182 if (lhp == NULL) 1183 return (EINVAL); 1184 1185 vpdown = lhp->lh_vp; 1186 ASSERT(vn_matchops(vpdown, spec_getvnodeops())); 1187 ASSERT(cmd == _I_PLINK_LH); 1188 1189 /* 1190 * create a new lower vnode and a file_t that points to it, 1191 * streams linking requires a file_t. falloc() returns with 1192 * fpdown locked. 1193 */ 1194 VN_HOLD(vpdown); 1195 (void) falloc(vpdown, FREAD|FWRITE, &fpdown, NULL); 1196 mutex_exit(&fpdown->f_tlock); 1197 1198 /* try to establish the link */ 1199 err = mlink_file(vp, I_PLINK, fpdown, crp, rvalp, 1); 1200 1201 if (err != 0) { 1202 /* the link failed, free the file_t and release the vnode */ 1203 mutex_enter(&fpdown->f_tlock); 1204 unfalloc(fpdown); 1205 VN_RELE(vpdown); 1206 } 1207 1208 return (err); 1209 } 1210 1211 /* 1212 * ldi_mlink_fp() is invoked for all successfull streams linkages created 1213 * via I_LINK and I_PLINK. ldi_mlink_fp() records the linkage information 1214 * in its internal state so that the devinfo snapshot code has some 1215 * observability into streams device linkage information. 1216 */ 1217 void 1218 ldi_mlink_fp(struct stdata *stp, file_t *fpdown, int lhlink, int type) 1219 { 1220 vnode_t *vp = fpdown->f_vnode; 1221 struct snode *sp, *csp; 1222 ldi_ident_t li; 1223 major_t major; 1224 int ret; 1225 1226 /* if the lower stream is not a device then return */ 1227 if (!vn_matchops(vp, spec_getvnodeops())) 1228 return; 1229 1230 ASSERT(!servicing_interrupt()); 1231 1232 LDI_STREAMS_LNK((CE_NOTE, "%s: linking streams " 1233 "stp=0x%p, fpdown=0x%p", "ldi_mlink_fp", 1234 (void *)stp, (void *)fpdown)); 1235 1236 sp = VTOS(vp); 1237 csp = VTOS(sp->s_commonvp); 1238 1239 /* check if this was a plink via a layered handle */ 1240 if (lhlink) { 1241 /* 1242 * increment the common snode s_count. 1243 * 1244 * this is done because after the link operation there 1245 * are two ways that s_count can be decremented. 1246 * 1247 * when the layered handle used to create the link is 1248 * closed, spec_close() is called and it will decrement 1249 * s_count in the common snode. if we don't increment 1250 * s_count here then this could cause spec_close() to 1251 * actually close the device while it's still linked 1252 * under a multiplexer. 1253 * 1254 * also, when the lower stream is unlinked, closef() is 1255 * called for the file_t associated with this snode. 1256 * closef() will call spec_close(), which will decrement 1257 * s_count. if we dont't increment s_count here then this 1258 * could cause spec_close() to actually close the device 1259 * while there may still be valid layered handles 1260 * pointing to it. 1261 */ 1262 mutex_enter(&csp->s_lock); 1263 ASSERT(csp->s_count >= 1); 1264 csp->s_count++; 1265 mutex_exit(&csp->s_lock); 1266 1267 /* 1268 * decrement the f_count. 1269 * this is done because the layered driver framework does 1270 * not actually cache a copy of the file_t allocated to 1271 * do the link. this is done here instead of in ldi_mlink_lh() 1272 * because there is a window in ldi_mlink_lh() between where 1273 * milnk_file() returns and we would decrement the f_count 1274 * when the stream could be unlinked. 1275 */ 1276 mutex_enter(&fpdown->f_tlock); 1277 fpdown->f_count--; 1278 mutex_exit(&fpdown->f_tlock); 1279 } 1280 1281 /* 1282 * NOTE: here we rely on the streams subsystem not allowing 1283 * a stream to be multiplexed more than once. if this 1284 * changes, we break. 1285 * 1286 * mark the snode/stream as multiplexed 1287 */ 1288 mutex_enter(&sp->s_lock); 1289 ASSERT(!(sp->s_flag & SMUXED)); 1290 sp->s_flag |= SMUXED; 1291 mutex_exit(&sp->s_lock); 1292 1293 /* get a layered ident for the upper stream */ 1294 if (type == LINKNORMAL) { 1295 /* 1296 * if the link is not persistant then we can associate 1297 * the upper stream with a dev_t. this is because the 1298 * upper stream is associated with a vnode, which is 1299 * associated with a dev_t and this binding can't change 1300 * during the life of the stream. since the link isn't 1301 * persistant once the stream is destroyed the link is 1302 * destroyed. so the dev_t will be valid for the life 1303 * of the link. 1304 */ 1305 ret = ldi_ident_from_stream(getendq(stp->sd_wrq), &li); 1306 } else { 1307 /* 1308 * if the link is persistant we can only associate the 1309 * link with a driver (and not a dev_t.) this is 1310 * because subsequent opens of the upper device may result 1311 * in a different stream (and dev_t) having access to 1312 * the lower stream. 1313 * 1314 * for example, if the upper stream is closed after the 1315 * persistant link operation is compleated, a subsequent 1316 * open of the upper device will create a new stream which 1317 * may have a different dev_t and an unlink operation 1318 * can be performed using this new upper stream. 1319 */ 1320 ASSERT(type == LINKPERSIST); 1321 major = getmajor(stp->sd_vnode->v_rdev); 1322 ret = ldi_ident_from_major(major, &li); 1323 } 1324 1325 ASSERT(ret == 0); 1326 (void) handle_alloc(vp, (struct ldi_ident *)li); 1327 ldi_ident_release(li); 1328 } 1329 1330 void 1331 ldi_munlink_fp(struct stdata *stp, file_t *fpdown, int type) 1332 { 1333 struct ldi_handle *lhp; 1334 vnode_t *vp = (vnode_t *)fpdown->f_vnode; 1335 struct snode *sp; 1336 ldi_ident_t li; 1337 major_t major; 1338 int ret; 1339 1340 /* if the lower stream is not a device then return */ 1341 if (!vn_matchops(vp, spec_getvnodeops())) 1342 return; 1343 1344 ASSERT(!servicing_interrupt()); 1345 ASSERT((type == LINKNORMAL) || (type == LINKPERSIST)); 1346 1347 LDI_STREAMS_LNK((CE_NOTE, "%s: unlinking streams " 1348 "stp=0x%p, fpdown=0x%p", "ldi_munlink_fp", 1349 (void *)stp, (void *)fpdown)); 1350 1351 /* 1352 * NOTE: here we rely on the streams subsystem not allowing 1353 * a stream to be multiplexed more than once. if this 1354 * changes, we break. 1355 * 1356 * mark the snode/stream as not multiplexed 1357 */ 1358 sp = VTOS(vp); 1359 mutex_enter(&sp->s_lock); 1360 ASSERT(sp->s_flag & SMUXED); 1361 sp->s_flag &= ~SMUXED; 1362 mutex_exit(&sp->s_lock); 1363 1364 /* 1365 * clear the owner for this snode 1366 * see the comment in ldi_mlink_fp() for information about how 1367 * the ident is allocated 1368 */ 1369 if (type == LINKNORMAL) { 1370 ret = ldi_ident_from_stream(getendq(stp->sd_wrq), &li); 1371 } else { 1372 ASSERT(type == LINKPERSIST); 1373 major = getmajor(stp->sd_vnode->v_rdev); 1374 ret = ldi_ident_from_major(major, &li); 1375 } 1376 1377 ASSERT(ret == 0); 1378 lhp = handle_find(vp, (struct ldi_ident *)li); 1379 handle_release(lhp); 1380 ldi_ident_release(li); 1381 } 1382 1383 /* 1384 * LDI Consolidation private interfaces 1385 */ 1386 int 1387 ldi_ident_from_mod(struct modlinkage *modlp, ldi_ident_t *lip) 1388 { 1389 struct modctl *modp; 1390 major_t major; 1391 char *name; 1392 1393 if ((modlp == NULL) || (lip == NULL)) 1394 return (EINVAL); 1395 1396 ASSERT(!servicing_interrupt()); 1397 1398 modp = mod_getctl(modlp); 1399 if (modp == NULL) 1400 return (EINVAL); 1401 name = modp->mod_modname; 1402 if (name == NULL) 1403 return (EINVAL); 1404 major = mod_name_to_major(name); 1405 1406 *lip = (ldi_ident_t)ident_alloc(name, NULL, DDI_DEV_T_NONE, major); 1407 1408 LDI_ALLOCFREE((CE_WARN, "%s: li=0x%p, mod=%s", 1409 "ldi_ident_from_mod", (void *)*lip, name)); 1410 1411 return (0); 1412 } 1413 1414 ldi_ident_t 1415 ldi_ident_from_anon() 1416 { 1417 ldi_ident_t lip; 1418 1419 ASSERT(!servicing_interrupt()); 1420 1421 lip = (ldi_ident_t)ident_alloc("genunix", NULL, DDI_DEV_T_NONE, -1); 1422 1423 LDI_ALLOCFREE((CE_WARN, "%s: li=0x%p, mod=%s", 1424 "ldi_ident_from_anon", (void *)lip, "genunix")); 1425 1426 return (lip); 1427 } 1428 1429 1430 /* 1431 * LDI Public interfaces 1432 */ 1433 int 1434 ldi_ident_from_stream(struct queue *sq, ldi_ident_t *lip) 1435 { 1436 struct stdata *stp; 1437 dev_t dev; 1438 char *name; 1439 1440 if ((sq == NULL) || (lip == NULL)) 1441 return (EINVAL); 1442 1443 ASSERT(!servicing_interrupt()); 1444 1445 stp = sq->q_stream; 1446 if (!vn_matchops(stp->sd_vnode, spec_getvnodeops())) 1447 return (EINVAL); 1448 1449 dev = stp->sd_vnode->v_rdev; 1450 name = mod_major_to_name(getmajor(dev)); 1451 if (name == NULL) 1452 return (EINVAL); 1453 *lip = (ldi_ident_t)ident_alloc(name, NULL, dev, -1); 1454 1455 LDI_ALLOCFREE((CE_WARN, 1456 "%s: li=0x%p, mod=%s, minor=0x%x, stp=0x%p", 1457 "ldi_ident_from_stream", (void *)*lip, name, getminor(dev), 1458 (void *)stp)); 1459 1460 return (0); 1461 } 1462 1463 int 1464 ldi_ident_from_dev(dev_t dev, ldi_ident_t *lip) 1465 { 1466 char *name; 1467 1468 if (lip == NULL) 1469 return (EINVAL); 1470 1471 ASSERT(!servicing_interrupt()); 1472 1473 name = mod_major_to_name(getmajor(dev)); 1474 if (name == NULL) 1475 return (EINVAL); 1476 *lip = (ldi_ident_t)ident_alloc(name, NULL, dev, -1); 1477 1478 LDI_ALLOCFREE((CE_WARN, 1479 "%s: li=0x%p, mod=%s, minor=0x%x", 1480 "ldi_ident_from_dev", (void *)*lip, name, getminor(dev))); 1481 1482 return (0); 1483 } 1484 1485 int 1486 ldi_ident_from_dip(dev_info_t *dip, ldi_ident_t *lip) 1487 { 1488 struct dev_info *devi = (struct dev_info *)dip; 1489 char *name; 1490 1491 if ((dip == NULL) || (lip == NULL)) 1492 return (EINVAL); 1493 1494 ASSERT(!servicing_interrupt()); 1495 1496 name = mod_major_to_name(devi->devi_major); 1497 if (name == NULL) 1498 return (EINVAL); 1499 *lip = (ldi_ident_t)ident_alloc(name, dip, DDI_DEV_T_NONE, -1); 1500 1501 LDI_ALLOCFREE((CE_WARN, 1502 "%s: li=0x%p, mod=%s, dip=0x%p", 1503 "ldi_ident_from_dip", (void *)*lip, name, (void *)devi)); 1504 1505 return (0); 1506 } 1507 1508 int 1509 ldi_ident_from_major(major_t major, ldi_ident_t *lip) 1510 { 1511 char *name; 1512 1513 if (lip == NULL) 1514 return (EINVAL); 1515 1516 ASSERT(!servicing_interrupt()); 1517 1518 name = mod_major_to_name(major); 1519 if (name == NULL) 1520 return (EINVAL); 1521 *lip = (ldi_ident_t)ident_alloc(name, NULL, DDI_DEV_T_NONE, major); 1522 1523 LDI_ALLOCFREE((CE_WARN, 1524 "%s: li=0x%p, mod=%s", 1525 "ldi_ident_from_major", (void *)*lip, name)); 1526 1527 return (0); 1528 } 1529 1530 void 1531 ldi_ident_release(ldi_ident_t li) 1532 { 1533 struct ldi_ident *ident = (struct ldi_ident *)li; 1534 char *name; 1535 1536 if (li == NULL) 1537 return; 1538 1539 ASSERT(!servicing_interrupt()); 1540 1541 name = ident->li_modname; 1542 1543 LDI_ALLOCFREE((CE_WARN, 1544 "%s: li=0x%p, mod=%s", 1545 "ldi_ident_release", (void *)li, name)); 1546 1547 ident_release((struct ldi_ident *)li); 1548 } 1549 1550 /* get a handle to a device by dev_t and otyp */ 1551 int 1552 ldi_open_by_dev(dev_t *devp, int otyp, int flag, cred_t *cr, 1553 ldi_handle_t *lhp, ldi_ident_t li) 1554 { 1555 struct ldi_ident *lip = (struct ldi_ident *)li; 1556 int ret; 1557 vnode_t *vp; 1558 1559 /* sanity check required input parameters */ 1560 if ((devp == NULL) || (!OTYP_VALID(otyp)) || (cr == NULL) || 1561 (lhp == NULL) || (lip == NULL)) 1562 return (EINVAL); 1563 1564 ASSERT(!servicing_interrupt()); 1565 1566 if ((ret = ldi_vp_from_dev(*devp, otyp, &vp)) != 0) 1567 return (ret); 1568 1569 if ((ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip)) == 0) { 1570 *devp = vp->v_rdev; 1571 } 1572 VN_RELE(vp); 1573 1574 return (ret); 1575 } 1576 1577 /* get a handle to a device by pathname */ 1578 int 1579 ldi_open_by_name(char *pathname, int flag, cred_t *cr, 1580 ldi_handle_t *lhp, ldi_ident_t li) 1581 { 1582 struct ldi_ident *lip = (struct ldi_ident *)li; 1583 int ret; 1584 vnode_t *vp; 1585 1586 /* sanity check required input parameters */ 1587 if ((pathname == NULL) || (*pathname != '/') || 1588 (cr == NULL) || (lhp == NULL) || (lip == NULL)) 1589 return (EINVAL); 1590 1591 ASSERT(!servicing_interrupt()); 1592 1593 if ((ret = ldi_vp_from_name(pathname, &vp)) != 0) 1594 return (ret); 1595 1596 ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip); 1597 VN_RELE(vp); 1598 1599 return (ret); 1600 } 1601 1602 /* get a handle to a device by devid and minor_name */ 1603 int 1604 ldi_open_by_devid(ddi_devid_t devid, char *minor_name, 1605 int flag, cred_t *cr, ldi_handle_t *lhp, ldi_ident_t li) 1606 { 1607 struct ldi_ident *lip = (struct ldi_ident *)li; 1608 int ret; 1609 vnode_t *vp; 1610 1611 /* sanity check required input parameters */ 1612 if ((minor_name == NULL) || (cr == NULL) || 1613 (lhp == NULL) || (lip == NULL)) 1614 return (EINVAL); 1615 1616 ASSERT(!servicing_interrupt()); 1617 1618 if ((ret = ldi_vp_from_devid(devid, minor_name, &vp)) != 0) 1619 return (ret); 1620 1621 ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip); 1622 VN_RELE(vp); 1623 1624 return (ret); 1625 } 1626 1627 int 1628 ldi_close(ldi_handle_t lh, int flag, cred_t *cr) 1629 { 1630 struct ldi_handle *handlep = (struct ldi_handle *)lh; 1631 struct ldi_event *lep; 1632 int err = 0; 1633 1634 if (lh == NULL) 1635 return (EINVAL); 1636 1637 ASSERT(!servicing_interrupt()); 1638 1639 /* Flush back any dirty pages associated with the device. */ 1640 if (handlep->lh_type & LH_CBDEV) { 1641 vnode_t *cvp = common_specvp(handlep->lh_vp); 1642 dev_t dev = cvp->v_rdev; 1643 1644 (void) VOP_PUTPAGE(cvp, 0, 0, B_INVAL, kcred); 1645 bflush(dev); 1646 } 1647 1648 /* 1649 * Any event handlers should have been unregistered by the 1650 * time ldi_close() is called. If they haven't then it's a 1651 * bug. 1652 * 1653 * In a debug kernel we'll panic to make the problem obvious. 1654 */ 1655 ASSERT(handlep->lh_events == NULL); 1656 1657 /* 1658 * On a production kernel we'll "do the right thing" (unregister 1659 * the event handlers) and then complain about having to do the 1660 * work ourselves. 1661 */ 1662 while ((lep = handlep->lh_events) != NULL) { 1663 err = 1; 1664 (void) ldi_remove_event_handler(lh, (ldi_callback_id_t)lep); 1665 } 1666 if (err) { 1667 struct ldi_ident *lip = handlep->lh_ident; 1668 ASSERT(lip != NULL); 1669 cmn_err(CE_NOTE, "ldi err: %s " 1670 "failed to unregister layered event handlers before " 1671 "closing devices", lip->li_modname); 1672 } 1673 1674 /* do a layered close on the device */ 1675 err = VOP_CLOSE(handlep->lh_vp, flag | FKLYR, 1, (offset_t)0, cr); 1676 1677 LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p", "ldi close", (void *)lh)); 1678 1679 /* 1680 * Free the handle even if the device close failed. why? 1681 * 1682 * If the device close failed we can't really make assumptions 1683 * about the devices state so we shouldn't allow access to the 1684 * device via this handle any more. If the device consumer wants 1685 * to access the device again they should open it again. 1686 * 1687 * This is the same way file/device close failures are handled 1688 * in other places like spec_close() and closeandsetf(). 1689 */ 1690 handle_release(handlep); 1691 return (err); 1692 } 1693 1694 int 1695 ldi_read(ldi_handle_t lh, struct uio *uiop, cred_t *credp) 1696 { 1697 struct ldi_handle *handlep = (struct ldi_handle *)lh; 1698 vnode_t *vp; 1699 dev_t dev; 1700 int ret; 1701 1702 if (lh == NULL) 1703 return (EINVAL); 1704 1705 vp = handlep->lh_vp; 1706 dev = vp->v_rdev; 1707 if (handlep->lh_type & LH_CBDEV) { 1708 ret = cdev_read(dev, uiop, credp); 1709 } else if (handlep->lh_type & LH_STREAM) { 1710 ret = strread(vp, uiop, credp); 1711 } else { 1712 return (ENOTSUP); 1713 } 1714 return (ret); 1715 } 1716 1717 int 1718 ldi_write(ldi_handle_t lh, struct uio *uiop, cred_t *credp) 1719 { 1720 struct ldi_handle *handlep = (struct ldi_handle *)lh; 1721 vnode_t *vp; 1722 dev_t dev; 1723 int ret; 1724 1725 if (lh == NULL) 1726 return (EINVAL); 1727 1728 vp = handlep->lh_vp; 1729 dev = vp->v_rdev; 1730 if (handlep->lh_type & LH_CBDEV) { 1731 ret = cdev_write(dev, uiop, credp); 1732 } else if (handlep->lh_type & LH_STREAM) { 1733 ret = strwrite(vp, uiop, credp); 1734 } else { 1735 return (ENOTSUP); 1736 } 1737 return (ret); 1738 } 1739 1740 int 1741 ldi_get_size(ldi_handle_t lh, uint64_t *sizep) 1742 { 1743 int otyp; 1744 uint_t value; 1745 int64_t drv_prop64; 1746 struct ldi_handle *handlep = (struct ldi_handle *)lh; 1747 1748 1749 if ((lh == NULL) || (sizep == NULL)) 1750 return (DDI_FAILURE); 1751 1752 if (handlep->lh_type & LH_STREAM) 1753 return (DDI_FAILURE); 1754 1755 /* 1756 * Determine device type (char or block). 1757 * Character devices support Size/size 1758 * property value. Block devices may support 1759 * Nblocks/nblocks or Size/size property value. 1760 */ 1761 if ((ldi_get_otyp(lh, &otyp)) != 0) 1762 return (DDI_FAILURE); 1763 1764 if (otyp == OTYP_BLK) { 1765 if (ldi_prop_exists(lh, 1766 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Nblocks")) { 1767 1768 drv_prop64 = ldi_prop_get_int64(lh, 1769 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 1770 "Nblocks", 0); 1771 *sizep = (uint64_t)ldbtob((uint64_t)drv_prop64); 1772 return (DDI_SUCCESS); 1773 } 1774 1775 if (ldi_prop_exists(lh, 1776 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "nblocks")) { 1777 1778 value = ldi_prop_get_int(lh, 1779 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 1780 "nblocks", 0); 1781 *sizep = (uint64_t)ldbtob(value); 1782 return (DDI_SUCCESS); 1783 } 1784 } 1785 1786 if (ldi_prop_exists(lh, 1787 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Size")) { 1788 1789 drv_prop64 = ldi_prop_get_int64(lh, 1790 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Size", 0); 1791 *sizep = (uint64_t)drv_prop64; 1792 return (DDI_SUCCESS); 1793 } 1794 1795 if (ldi_prop_exists(lh, 1796 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "size")) { 1797 1798 value = ldi_prop_get_int(lh, 1799 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "size", 0); 1800 *sizep = (uint64_t)value; 1801 return (DDI_SUCCESS); 1802 } 1803 1804 /* unable to determine device size */ 1805 return (DDI_FAILURE); 1806 } 1807 1808 int 1809 ldi_ioctl(ldi_handle_t lh, int cmd, intptr_t arg, int mode, 1810 cred_t *cr, int *rvalp) 1811 { 1812 struct ldi_handle *handlep = (struct ldi_handle *)lh; 1813 vnode_t *vp; 1814 dev_t dev; 1815 int ret, copymode; 1816 1817 if (lh == NULL) 1818 return (EINVAL); 1819 1820 /* 1821 * if the data pointed to by arg is located in the kernel then 1822 * make sure the FNATIVE flag is set. 1823 */ 1824 if (mode & FKIOCTL) 1825 mode = (mode & ~FMODELS) | FNATIVE | FKIOCTL; 1826 1827 vp = handlep->lh_vp; 1828 dev = vp->v_rdev; 1829 if (handlep->lh_type & LH_CBDEV) { 1830 ret = cdev_ioctl(dev, cmd, arg, mode, cr, rvalp); 1831 } else if (handlep->lh_type & LH_STREAM) { 1832 copymode = (mode & FKIOCTL) ? K_TO_K : U_TO_K; 1833 1834 /* 1835 * if we get an I_PLINK from within the kernel the 1836 * arg is a layered handle pointer instead of 1837 * a file descriptor, so we translate this ioctl 1838 * into a private one that can handle this. 1839 */ 1840 if ((mode & FKIOCTL) && (cmd == I_PLINK)) 1841 cmd = _I_PLINK_LH; 1842 1843 ret = strioctl(vp, cmd, arg, mode, copymode, cr, rvalp); 1844 } else { 1845 return (ENOTSUP); 1846 } 1847 1848 return (ret); 1849 } 1850 1851 int 1852 ldi_poll(ldi_handle_t lh, short events, int anyyet, short *reventsp, 1853 struct pollhead **phpp) 1854 { 1855 struct ldi_handle *handlep = (struct ldi_handle *)lh; 1856 vnode_t *vp; 1857 dev_t dev; 1858 int ret; 1859 1860 if (lh == NULL) 1861 return (EINVAL); 1862 1863 vp = handlep->lh_vp; 1864 dev = vp->v_rdev; 1865 if (handlep->lh_type & LH_CBDEV) { 1866 ret = cdev_poll(dev, events, anyyet, reventsp, phpp); 1867 } else if (handlep->lh_type & LH_STREAM) { 1868 ret = strpoll(vp->v_stream, events, anyyet, reventsp, phpp); 1869 } else { 1870 return (ENOTSUP); 1871 } 1872 1873 return (ret); 1874 } 1875 1876 int 1877 ldi_prop_op(ldi_handle_t lh, ddi_prop_op_t prop_op, 1878 int flags, char *name, caddr_t valuep, int *length) 1879 { 1880 struct ldi_handle *handlep = (struct ldi_handle *)lh; 1881 dev_t dev; 1882 dev_info_t *dip; 1883 int ret; 1884 struct snode *csp; 1885 1886 if ((lh == NULL) || (name == NULL) || (strlen(name) == 0)) 1887 return (DDI_PROP_INVAL_ARG); 1888 1889 if ((prop_op != PROP_LEN) && (valuep == NULL)) 1890 return (DDI_PROP_INVAL_ARG); 1891 1892 if (length == NULL) 1893 return (DDI_PROP_INVAL_ARG); 1894 1895 /* 1896 * try to find the associated dip, 1897 * this places a hold on the driver 1898 */ 1899 dev = handlep->lh_vp->v_rdev; 1900 1901 csp = VTOCS(handlep->lh_vp); 1902 mutex_enter(&csp->s_lock); 1903 if ((dip = csp->s_dip) != NULL) 1904 e_ddi_hold_devi(dip); 1905 mutex_exit(&csp->s_lock); 1906 if (dip == NULL) 1907 dip = e_ddi_hold_devi_by_dev(dev, 0); 1908 1909 if (dip == NULL) 1910 return (DDI_PROP_NOT_FOUND); 1911 1912 ret = i_ldi_prop_op(dev, dip, prop_op, flags, name, valuep, length); 1913 ddi_release_devi(dip); 1914 1915 return (ret); 1916 } 1917 1918 int 1919 ldi_strategy(ldi_handle_t lh, struct buf *bp) 1920 { 1921 struct ldi_handle *handlep = (struct ldi_handle *)lh; 1922 dev_t dev; 1923 1924 if ((lh == NULL) || (bp == NULL)) 1925 return (EINVAL); 1926 1927 /* this entry point is only supported for cb devices */ 1928 dev = handlep->lh_vp->v_rdev; 1929 if (!(handlep->lh_type & LH_CBDEV)) 1930 return (ENOTSUP); 1931 1932 bp->b_edev = dev; 1933 bp->b_dev = cmpdev(dev); 1934 return (bdev_strategy(bp)); 1935 } 1936 1937 int 1938 ldi_dump(ldi_handle_t lh, caddr_t addr, daddr_t blkno, int nblk) 1939 { 1940 struct ldi_handle *handlep = (struct ldi_handle *)lh; 1941 dev_t dev; 1942 1943 if (lh == NULL) 1944 return (EINVAL); 1945 1946 /* this entry point is only supported for cb devices */ 1947 dev = handlep->lh_vp->v_rdev; 1948 if (!(handlep->lh_type & LH_CBDEV)) 1949 return (ENOTSUP); 1950 1951 return (bdev_dump(dev, addr, blkno, nblk)); 1952 } 1953 1954 int 1955 ldi_devmap(ldi_handle_t lh, devmap_cookie_t dhp, offset_t off, 1956 size_t len, size_t *maplen, uint_t model) 1957 { 1958 struct ldi_handle *handlep = (struct ldi_handle *)lh; 1959 dev_t dev; 1960 1961 if (lh == NULL) 1962 return (EINVAL); 1963 1964 /* this entry point is only supported for cb devices */ 1965 dev = handlep->lh_vp->v_rdev; 1966 if (!(handlep->lh_type & LH_CBDEV)) 1967 return (ENOTSUP); 1968 1969 return (cdev_devmap(dev, dhp, off, len, maplen, model)); 1970 } 1971 1972 int 1973 ldi_aread(ldi_handle_t lh, struct aio_req *aio_reqp, cred_t *cr) 1974 { 1975 struct ldi_handle *handlep = (struct ldi_handle *)lh; 1976 dev_t dev; 1977 struct cb_ops *cb; 1978 1979 if (lh == NULL) 1980 return (EINVAL); 1981 1982 /* this entry point is only supported for cb devices */ 1983 if (!(handlep->lh_type & LH_CBDEV)) 1984 return (ENOTSUP); 1985 1986 /* 1987 * Kaio is only supported on block devices. 1988 */ 1989 dev = handlep->lh_vp->v_rdev; 1990 cb = devopsp[getmajor(dev)]->devo_cb_ops; 1991 if (cb->cb_strategy == nodev || cb->cb_strategy == NULL) 1992 return (ENOTSUP); 1993 1994 if (cb->cb_aread == NULL) 1995 return (ENOTSUP); 1996 1997 return (cb->cb_aread(dev, aio_reqp, cr)); 1998 } 1999 2000 int 2001 ldi_awrite(ldi_handle_t lh, struct aio_req *aio_reqp, cred_t *cr) 2002 { 2003 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2004 struct cb_ops *cb; 2005 dev_t dev; 2006 2007 if (lh == NULL) 2008 return (EINVAL); 2009 2010 /* this entry point is only supported for cb devices */ 2011 if (!(handlep->lh_type & LH_CBDEV)) 2012 return (ENOTSUP); 2013 2014 /* 2015 * Kaio is only supported on block devices. 2016 */ 2017 dev = handlep->lh_vp->v_rdev; 2018 cb = devopsp[getmajor(dev)]->devo_cb_ops; 2019 if (cb->cb_strategy == nodev || cb->cb_strategy == NULL) 2020 return (ENOTSUP); 2021 2022 if (cb->cb_awrite == NULL) 2023 return (ENOTSUP); 2024 2025 return (cb->cb_awrite(dev, aio_reqp, cr)); 2026 } 2027 2028 int 2029 ldi_putmsg(ldi_handle_t lh, mblk_t *smp) 2030 { 2031 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2032 int ret; 2033 2034 if ((lh == NULL) || (smp == NULL)) 2035 return (EINVAL); 2036 2037 if (!(handlep->lh_type & LH_STREAM)) { 2038 freemsg(smp); 2039 return (ENOTSUP); 2040 } 2041 2042 /* Send message while honoring flow control */ 2043 ret = kstrputmsg(handlep->lh_vp, smp, NULL, 0, 0, 2044 MSG_BAND | MSG_HOLDSIG | MSG_IGNERROR, 0); 2045 2046 return (ret); 2047 } 2048 2049 int 2050 ldi_getmsg(ldi_handle_t lh, mblk_t **rmp, timestruc_t *timeo) 2051 { 2052 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2053 clock_t timout; /* milliseconds */ 2054 uchar_t pri; 2055 rval_t rval; 2056 int ret, pflag; 2057 2058 2059 if (lh == NULL) 2060 return (EINVAL); 2061 2062 if (!(handlep->lh_type & LH_STREAM)) 2063 return (ENOTSUP); 2064 2065 /* Convert from nanoseconds to milliseconds */ 2066 if (timeo != NULL) { 2067 timout = timeo->tv_sec * 1000 + timeo->tv_nsec / 1000000; 2068 if (timout > INT_MAX) 2069 return (EINVAL); 2070 } else 2071 timout = -1; 2072 2073 /* Wait for timeout millseconds for a message */ 2074 pflag = MSG_ANY; 2075 pri = 0; 2076 *rmp = NULL; 2077 ret = kstrgetmsg(handlep->lh_vp, 2078 rmp, NULL, &pri, &pflag, timout, &rval); 2079 return (ret); 2080 } 2081 2082 int 2083 ldi_get_dev(ldi_handle_t lh, dev_t *devp) 2084 { 2085 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2086 2087 if ((lh == NULL) || (devp == NULL)) 2088 return (EINVAL); 2089 2090 *devp = handlep->lh_vp->v_rdev; 2091 return (0); 2092 } 2093 2094 int 2095 ldi_get_otyp(ldi_handle_t lh, int *otyp) 2096 { 2097 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2098 2099 if ((lh == NULL) || (otyp == NULL)) 2100 return (EINVAL); 2101 2102 *otyp = VTYP_TO_OTYP(handlep->lh_vp->v_type); 2103 return (0); 2104 } 2105 2106 int 2107 ldi_get_devid(ldi_handle_t lh, ddi_devid_t *devid) 2108 { 2109 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2110 int ret; 2111 dev_t dev; 2112 2113 if ((lh == NULL) || (devid == NULL)) 2114 return (EINVAL); 2115 2116 dev = handlep->lh_vp->v_rdev; 2117 2118 ret = ddi_lyr_get_devid(dev, devid); 2119 if (ret != DDI_SUCCESS) 2120 return (ENOTSUP); 2121 2122 return (0); 2123 } 2124 2125 int 2126 ldi_get_minor_name(ldi_handle_t lh, char **minor_name) 2127 { 2128 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2129 int ret, otyp; 2130 dev_t dev; 2131 2132 if ((lh == NULL) || (minor_name == NULL)) 2133 return (EINVAL); 2134 2135 dev = handlep->lh_vp->v_rdev; 2136 otyp = VTYP_TO_OTYP(handlep->lh_vp->v_type); 2137 2138 ret = ddi_lyr_get_minor_name(dev, OTYP_TO_STYP(otyp), minor_name); 2139 if (ret != DDI_SUCCESS) 2140 return (ENOTSUP); 2141 2142 return (0); 2143 } 2144 2145 int 2146 ldi_prop_lookup_int_array(ldi_handle_t lh, 2147 uint_t flags, char *name, int **data, uint_t *nelements) 2148 { 2149 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2150 dev_info_t *dip; 2151 dev_t dev; 2152 int res; 2153 struct snode *csp; 2154 2155 if ((lh == NULL) || (name == NULL) || (strlen(name) == 0)) 2156 return (DDI_PROP_INVAL_ARG); 2157 2158 dev = handlep->lh_vp->v_rdev; 2159 2160 csp = VTOCS(handlep->lh_vp); 2161 mutex_enter(&csp->s_lock); 2162 if ((dip = csp->s_dip) != NULL) 2163 e_ddi_hold_devi(dip); 2164 mutex_exit(&csp->s_lock); 2165 if (dip == NULL) 2166 dip = e_ddi_hold_devi_by_dev(dev, 0); 2167 2168 if (dip == NULL) { 2169 flags |= DDI_UNBND_DLPI2; 2170 } else if (flags & LDI_DEV_T_ANY) { 2171 flags &= ~LDI_DEV_T_ANY; 2172 dev = DDI_DEV_T_ANY; 2173 } 2174 2175 if (dip != NULL) { 2176 int *prop_val, prop_len; 2177 2178 res = i_ldi_prop_op_typed(dev, dip, flags, name, 2179 (caddr_t *)&prop_val, &prop_len, sizeof (int)); 2180 2181 /* if we got it then return it */ 2182 if (res == DDI_PROP_SUCCESS) { 2183 *nelements = prop_len / sizeof (int); 2184 *data = prop_val; 2185 2186 ddi_release_devi(dip); 2187 return (res); 2188 } 2189 } 2190 2191 /* call the normal property interfaces */ 2192 res = ddi_prop_lookup_int_array(dev, dip, flags, 2193 name, data, nelements); 2194 2195 if (dip != NULL) 2196 ddi_release_devi(dip); 2197 2198 return (res); 2199 } 2200 2201 int 2202 ldi_prop_lookup_int64_array(ldi_handle_t lh, 2203 uint_t flags, char *name, int64_t **data, uint_t *nelements) 2204 { 2205 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2206 dev_info_t *dip; 2207 dev_t dev; 2208 int res; 2209 struct snode *csp; 2210 2211 if ((lh == NULL) || (name == NULL) || (strlen(name) == 0)) 2212 return (DDI_PROP_INVAL_ARG); 2213 2214 dev = handlep->lh_vp->v_rdev; 2215 2216 csp = VTOCS(handlep->lh_vp); 2217 mutex_enter(&csp->s_lock); 2218 if ((dip = csp->s_dip) != NULL) 2219 e_ddi_hold_devi(dip); 2220 mutex_exit(&csp->s_lock); 2221 if (dip == NULL) 2222 dip = e_ddi_hold_devi_by_dev(dev, 0); 2223 2224 if (dip == NULL) { 2225 flags |= DDI_UNBND_DLPI2; 2226 } else if (flags & LDI_DEV_T_ANY) { 2227 flags &= ~LDI_DEV_T_ANY; 2228 dev = DDI_DEV_T_ANY; 2229 } 2230 2231 if (dip != NULL) { 2232 int64_t *prop_val; 2233 int prop_len; 2234 2235 res = i_ldi_prop_op_typed(dev, dip, flags, name, 2236 (caddr_t *)&prop_val, &prop_len, sizeof (int64_t)); 2237 2238 /* if we got it then return it */ 2239 if (res == DDI_PROP_SUCCESS) { 2240 *nelements = prop_len / sizeof (int64_t); 2241 *data = prop_val; 2242 2243 ddi_release_devi(dip); 2244 return (res); 2245 } 2246 } 2247 2248 /* call the normal property interfaces */ 2249 res = ddi_prop_lookup_int64_array(dev, dip, flags, 2250 name, data, nelements); 2251 2252 if (dip != NULL) 2253 ddi_release_devi(dip); 2254 2255 return (res); 2256 } 2257 2258 int 2259 ldi_prop_lookup_string_array(ldi_handle_t lh, 2260 uint_t flags, char *name, char ***data, uint_t *nelements) 2261 { 2262 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2263 dev_info_t *dip; 2264 dev_t dev; 2265 int res; 2266 struct snode *csp; 2267 2268 if ((lh == NULL) || (name == NULL) || (strlen(name) == 0)) 2269 return (DDI_PROP_INVAL_ARG); 2270 2271 dev = handlep->lh_vp->v_rdev; 2272 2273 csp = VTOCS(handlep->lh_vp); 2274 mutex_enter(&csp->s_lock); 2275 if ((dip = csp->s_dip) != NULL) 2276 e_ddi_hold_devi(dip); 2277 mutex_exit(&csp->s_lock); 2278 if (dip == NULL) 2279 dip = e_ddi_hold_devi_by_dev(dev, 0); 2280 2281 if (dip == NULL) { 2282 flags |= DDI_UNBND_DLPI2; 2283 } else if (flags & LDI_DEV_T_ANY) { 2284 flags &= ~LDI_DEV_T_ANY; 2285 dev = DDI_DEV_T_ANY; 2286 } 2287 2288 if (dip != NULL) { 2289 char *prop_val; 2290 int prop_len; 2291 2292 res = i_ldi_prop_op_typed(dev, dip, flags, name, 2293 (caddr_t *)&prop_val, &prop_len, 0); 2294 2295 /* if we got it then return it */ 2296 if (res == DDI_PROP_SUCCESS) { 2297 char **str_array; 2298 int nelem; 2299 2300 /* 2301 * pack the returned string array into the format 2302 * our callers expect 2303 */ 2304 if (i_pack_string_array(prop_val, prop_len, 2305 &str_array, &nelem) == 0) { 2306 2307 *data = str_array; 2308 *nelements = nelem; 2309 2310 ddi_prop_free(prop_val); 2311 ddi_release_devi(dip); 2312 return (res); 2313 } 2314 2315 /* 2316 * the format of the returned property must have 2317 * been bad so throw it out 2318 */ 2319 ddi_prop_free(prop_val); 2320 } 2321 } 2322 2323 /* call the normal property interfaces */ 2324 res = ddi_prop_lookup_string_array(dev, dip, flags, 2325 name, data, nelements); 2326 2327 if (dip != NULL) 2328 ddi_release_devi(dip); 2329 2330 return (res); 2331 } 2332 2333 int 2334 ldi_prop_lookup_string(ldi_handle_t lh, 2335 uint_t flags, char *name, char **data) 2336 { 2337 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2338 dev_info_t *dip; 2339 dev_t dev; 2340 int res; 2341 struct snode *csp; 2342 2343 if ((lh == NULL) || (name == NULL) || (strlen(name) == 0)) 2344 return (DDI_PROP_INVAL_ARG); 2345 2346 dev = handlep->lh_vp->v_rdev; 2347 2348 csp = VTOCS(handlep->lh_vp); 2349 mutex_enter(&csp->s_lock); 2350 if ((dip = csp->s_dip) != NULL) 2351 e_ddi_hold_devi(dip); 2352 mutex_exit(&csp->s_lock); 2353 if (dip == NULL) 2354 dip = e_ddi_hold_devi_by_dev(dev, 0); 2355 2356 if (dip == NULL) { 2357 flags |= DDI_UNBND_DLPI2; 2358 } else if (flags & LDI_DEV_T_ANY) { 2359 flags &= ~LDI_DEV_T_ANY; 2360 dev = DDI_DEV_T_ANY; 2361 } 2362 2363 if (dip != NULL) { 2364 char *prop_val; 2365 int prop_len; 2366 2367 res = i_ldi_prop_op_typed(dev, dip, flags, name, 2368 (caddr_t *)&prop_val, &prop_len, 0); 2369 2370 /* if we got it then return it */ 2371 if (res == DDI_PROP_SUCCESS) { 2372 /* 2373 * sanity check the vaule returned. 2374 */ 2375 if (i_check_string(prop_val, prop_len)) { 2376 ddi_prop_free(prop_val); 2377 } else { 2378 *data = prop_val; 2379 ddi_release_devi(dip); 2380 return (res); 2381 } 2382 } 2383 } 2384 2385 /* call the normal property interfaces */ 2386 res = ddi_prop_lookup_string(dev, dip, flags, name, data); 2387 2388 if (dip != NULL) 2389 ddi_release_devi(dip); 2390 2391 #ifdef DEBUG 2392 if (res == DDI_PROP_SUCCESS) { 2393 /* 2394 * keep ourselves honest 2395 * make sure the framework returns strings in the 2396 * same format as we're demanding from drivers. 2397 */ 2398 struct prop_driver_data *pdd; 2399 int pdd_prop_size; 2400 2401 pdd = ((struct prop_driver_data *)(*data)) - 1; 2402 pdd_prop_size = pdd->pdd_size - 2403 sizeof (struct prop_driver_data); 2404 ASSERT(i_check_string(*data, pdd_prop_size) == 0); 2405 } 2406 #endif /* DEBUG */ 2407 2408 return (res); 2409 } 2410 2411 int 2412 ldi_prop_lookup_byte_array(ldi_handle_t lh, 2413 uint_t flags, char *name, uchar_t **data, uint_t *nelements) 2414 { 2415 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2416 dev_info_t *dip; 2417 dev_t dev; 2418 int res; 2419 struct snode *csp; 2420 2421 if ((lh == NULL) || (name == NULL) || (strlen(name) == 0)) 2422 return (DDI_PROP_INVAL_ARG); 2423 2424 dev = handlep->lh_vp->v_rdev; 2425 2426 csp = VTOCS(handlep->lh_vp); 2427 mutex_enter(&csp->s_lock); 2428 if ((dip = csp->s_dip) != NULL) 2429 e_ddi_hold_devi(dip); 2430 mutex_exit(&csp->s_lock); 2431 if (dip == NULL) 2432 dip = e_ddi_hold_devi_by_dev(dev, 0); 2433 2434 if (dip == NULL) { 2435 flags |= DDI_UNBND_DLPI2; 2436 } else if (flags & LDI_DEV_T_ANY) { 2437 flags &= ~LDI_DEV_T_ANY; 2438 dev = DDI_DEV_T_ANY; 2439 } 2440 2441 if (dip != NULL) { 2442 uchar_t *prop_val; 2443 int prop_len; 2444 2445 res = i_ldi_prop_op_typed(dev, dip, flags, name, 2446 (caddr_t *)&prop_val, &prop_len, sizeof (uchar_t)); 2447 2448 /* if we got it then return it */ 2449 if (res == DDI_PROP_SUCCESS) { 2450 *nelements = prop_len / sizeof (uchar_t); 2451 *data = prop_val; 2452 2453 ddi_release_devi(dip); 2454 return (res); 2455 } 2456 } 2457 2458 /* call the normal property interfaces */ 2459 res = ddi_prop_lookup_byte_array(dev, dip, flags, 2460 name, data, nelements); 2461 2462 if (dip != NULL) 2463 ddi_release_devi(dip); 2464 2465 return (res); 2466 } 2467 2468 int 2469 ldi_prop_get_int(ldi_handle_t lh, 2470 uint_t flags, char *name, int defvalue) 2471 { 2472 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2473 dev_info_t *dip; 2474 dev_t dev; 2475 int res; 2476 struct snode *csp; 2477 2478 if ((lh == NULL) || (name == NULL) || (strlen(name) == 0)) 2479 return (defvalue); 2480 2481 dev = handlep->lh_vp->v_rdev; 2482 2483 csp = VTOCS(handlep->lh_vp); 2484 mutex_enter(&csp->s_lock); 2485 if ((dip = csp->s_dip) != NULL) 2486 e_ddi_hold_devi(dip); 2487 mutex_exit(&csp->s_lock); 2488 if (dip == NULL) 2489 dip = e_ddi_hold_devi_by_dev(dev, 0); 2490 2491 if (dip == NULL) { 2492 flags |= DDI_UNBND_DLPI2; 2493 } else if (flags & LDI_DEV_T_ANY) { 2494 flags &= ~LDI_DEV_T_ANY; 2495 dev = DDI_DEV_T_ANY; 2496 } 2497 2498 if (dip != NULL) { 2499 int prop_val; 2500 int prop_len; 2501 2502 /* 2503 * first call the drivers prop_op interface to allow it 2504 * it to override default property values. 2505 */ 2506 prop_len = sizeof (int); 2507 res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF, 2508 flags | DDI_PROP_DYNAMIC, name, 2509 (caddr_t)&prop_val, &prop_len); 2510 2511 /* if we got it then return it */ 2512 if ((res == DDI_PROP_SUCCESS) && 2513 (prop_len == sizeof (int))) { 2514 res = prop_val; 2515 ddi_release_devi(dip); 2516 return (res); 2517 } 2518 } 2519 2520 /* call the normal property interfaces */ 2521 res = ddi_prop_get_int(dev, dip, flags, name, defvalue); 2522 2523 if (dip != NULL) 2524 ddi_release_devi(dip); 2525 2526 return (res); 2527 } 2528 2529 int64_t 2530 ldi_prop_get_int64(ldi_handle_t lh, 2531 uint_t flags, char *name, int64_t defvalue) 2532 { 2533 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2534 dev_info_t *dip; 2535 dev_t dev; 2536 int64_t res; 2537 struct snode *csp; 2538 2539 if ((lh == NULL) || (name == NULL) || (strlen(name) == 0)) 2540 return (defvalue); 2541 2542 dev = handlep->lh_vp->v_rdev; 2543 2544 csp = VTOCS(handlep->lh_vp); 2545 mutex_enter(&csp->s_lock); 2546 if ((dip = csp->s_dip) != NULL) 2547 e_ddi_hold_devi(dip); 2548 mutex_exit(&csp->s_lock); 2549 if (dip == NULL) 2550 dip = e_ddi_hold_devi_by_dev(dev, 0); 2551 2552 if (dip == NULL) { 2553 flags |= DDI_UNBND_DLPI2; 2554 } else if (flags & LDI_DEV_T_ANY) { 2555 flags &= ~LDI_DEV_T_ANY; 2556 dev = DDI_DEV_T_ANY; 2557 } 2558 2559 if (dip != NULL) { 2560 int64_t prop_val; 2561 int prop_len; 2562 2563 /* 2564 * first call the drivers prop_op interface to allow it 2565 * it to override default property values. 2566 */ 2567 prop_len = sizeof (int64_t); 2568 res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF, 2569 flags | DDI_PROP_DYNAMIC, name, 2570 (caddr_t)&prop_val, &prop_len); 2571 2572 /* if we got it then return it */ 2573 if ((res == DDI_PROP_SUCCESS) && 2574 (prop_len == sizeof (int64_t))) { 2575 res = prop_val; 2576 ddi_release_devi(dip); 2577 return (res); 2578 } 2579 } 2580 2581 /* call the normal property interfaces */ 2582 res = ddi_prop_get_int64(dev, dip, flags, name, defvalue); 2583 2584 if (dip != NULL) 2585 ddi_release_devi(dip); 2586 2587 return (res); 2588 } 2589 2590 int 2591 ldi_prop_exists(ldi_handle_t lh, uint_t flags, char *name) 2592 { 2593 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2594 dev_info_t *dip; 2595 dev_t dev; 2596 int res, prop_len; 2597 struct snode *csp; 2598 2599 if ((lh == NULL) || (name == NULL) || (strlen(name) == 0)) 2600 return (0); 2601 2602 dev = handlep->lh_vp->v_rdev; 2603 2604 csp = VTOCS(handlep->lh_vp); 2605 mutex_enter(&csp->s_lock); 2606 if ((dip = csp->s_dip) != NULL) 2607 e_ddi_hold_devi(dip); 2608 mutex_exit(&csp->s_lock); 2609 if (dip == NULL) 2610 dip = e_ddi_hold_devi_by_dev(dev, 0); 2611 2612 /* if NULL dip, prop does NOT exist */ 2613 if (dip == NULL) 2614 return (0); 2615 2616 if (flags & LDI_DEV_T_ANY) { 2617 flags &= ~LDI_DEV_T_ANY; 2618 dev = DDI_DEV_T_ANY; 2619 } 2620 2621 /* 2622 * first call the drivers prop_op interface to allow it 2623 * it to override default property values. 2624 */ 2625 res = i_ldi_prop_op(dev, dip, PROP_LEN, 2626 flags | DDI_PROP_DYNAMIC, name, NULL, &prop_len); 2627 2628 if (res == DDI_PROP_SUCCESS) { 2629 ddi_release_devi(dip); 2630 return (1); 2631 } 2632 2633 /* call the normal property interfaces */ 2634 res = ddi_prop_exists(dev, dip, flags, name); 2635 2636 ddi_release_devi(dip); 2637 return (res); 2638 } 2639 2640 int 2641 ldi_get_eventcookie(ldi_handle_t lh, char *name, ddi_eventcookie_t *ecp) 2642 { 2643 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2644 dev_info_t *dip; 2645 dev_t dev; 2646 int res; 2647 struct snode *csp; 2648 2649 if ((lh == NULL) || (name == NULL) || 2650 (strlen(name) == 0) || (ecp == NULL)) { 2651 return (DDI_FAILURE); 2652 } 2653 2654 ASSERT(!servicing_interrupt()); 2655 2656 dev = handlep->lh_vp->v_rdev; 2657 2658 csp = VTOCS(handlep->lh_vp); 2659 mutex_enter(&csp->s_lock); 2660 if ((dip = csp->s_dip) != NULL) 2661 e_ddi_hold_devi(dip); 2662 mutex_exit(&csp->s_lock); 2663 if (dip == NULL) 2664 dip = e_ddi_hold_devi_by_dev(dev, 0); 2665 2666 if (dip == NULL) 2667 return (DDI_FAILURE); 2668 2669 LDI_EVENTCB((CE_NOTE, "%s: event_name=%s, " 2670 "dip=0x%p, event_cookiep=0x%p", "ldi_get_eventcookie", 2671 name, (void *)dip, (void *)ecp)); 2672 2673 res = ddi_get_eventcookie(dip, name, ecp); 2674 2675 ddi_release_devi(dip); 2676 return (res); 2677 } 2678 2679 int 2680 ldi_add_event_handler(ldi_handle_t lh, ddi_eventcookie_t ec, 2681 void (*handler)(ldi_handle_t, ddi_eventcookie_t, void *, void *), 2682 void *arg, ldi_callback_id_t *id) 2683 { 2684 struct ldi_handle *handlep = (struct ldi_handle *)lh; 2685 struct ldi_event *lep; 2686 dev_info_t *dip; 2687 dev_t dev; 2688 int res; 2689 struct snode *csp; 2690 2691 if ((lh == NULL) || (ec == NULL) || (handler == NULL) || (id == NULL)) 2692 return (DDI_FAILURE); 2693 2694 ASSERT(!servicing_interrupt()); 2695 2696 dev = handlep->lh_vp->v_rdev; 2697 2698 csp = VTOCS(handlep->lh_vp); 2699 mutex_enter(&csp->s_lock); 2700 if ((dip = csp->s_dip) != NULL) 2701 e_ddi_hold_devi(dip); 2702 mutex_exit(&csp->s_lock); 2703 if (dip == NULL) 2704 dip = e_ddi_hold_devi_by_dev(dev, 0); 2705 2706 if (dip == NULL) 2707 return (DDI_FAILURE); 2708 2709 lep = kmem_zalloc(sizeof (struct ldi_event), KM_SLEEP); 2710 lep->le_lhp = handlep; 2711 lep->le_arg = arg; 2712 lep->le_handler = handler; 2713 2714 if ((res = ddi_add_event_handler(dip, ec, i_ldi_callback, 2715 (void *)lep, &lep->le_id)) != DDI_SUCCESS) { 2716 LDI_EVENTCB((CE_WARN, "%s: unable to add" 2717 "event callback", "ldi_add_event_handler")); 2718 ddi_release_devi(dip); 2719 kmem_free(lep, sizeof (struct ldi_event)); 2720 return (res); 2721 } 2722 2723 *id = (ldi_callback_id_t)lep; 2724 2725 LDI_EVENTCB((CE_NOTE, "%s: dip=0x%p, event=0x%p, " 2726 "ldi_eventp=0x%p, cb_id=0x%p", "ldi_add_event_handler", 2727 (void *)dip, (void *)ec, (void *)lep, (void *)id)); 2728 2729 handle_event_add(lep); 2730 ddi_release_devi(dip); 2731 return (res); 2732 } 2733 2734 int 2735 ldi_remove_event_handler(ldi_handle_t lh, ldi_callback_id_t id) 2736 { 2737 ldi_event_t *lep = (ldi_event_t *)id; 2738 int res; 2739 2740 if ((lh == NULL) || (id == NULL)) 2741 return (DDI_FAILURE); 2742 2743 ASSERT(!servicing_interrupt()); 2744 2745 if ((res = ddi_remove_event_handler(lep->le_id)) 2746 != DDI_SUCCESS) { 2747 LDI_EVENTCB((CE_WARN, "%s: unable to remove " 2748 "event callback", "ldi_remove_event_handler")); 2749 return (res); 2750 } 2751 2752 handle_event_remove(lep); 2753 kmem_free(lep, sizeof (struct ldi_event)); 2754 return (res); 2755 } 2756