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 (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>
  47 #include <sys/bootconf.h>
  48 #include <sys/pathname.h>
  49 #include <sys/bitmap.h>
  50 #include <sys/stat.h>
  51 #include <sys/dditypes.h>
  52 #include <sys/ddi_impldefs.h>
  53 #include <sys/ddi.h>
  54 #include <sys/sunddi.h>
  55 #include <sys/sunndi.h>
  56 #include <sys/esunddi.h>
  57 #include <sys/autoconf.h>
  58 #include <sys/sunldi.h>
  59 #include <sys/sunldi_impl.h>
  60 #include <sys/errno.h>
  61 #include <sys/debug.h>
  62 #include <sys/modctl.h>
  63 #include <sys/var.h>
  64 #include <vm/seg_vn.h>
  65 
  66 #include <sys/stropts.h>
  67 #include <sys/strsubr.h>
  68 #include <sys/socket.h>
  69 #include <sys/socketvar.h>
  70 #include <sys/kstr.h>
  71 
  72 /*
  73  * Device contract related
  74  */
  75 #include <sys/contract_impl.h>
  76 #include <sys/contract/device_impl.h>
  77 
  78 /*
  79  * Define macros to manipulate snode, vnode, and open device flags
  80  */
  81 #define VTYP_VALID(i)   (((i) == VCHR) || ((i) == VBLK))
  82 #define VTYP_TO_OTYP(i) (((i) == VCHR) ? OTYP_CHR : OTYP_BLK)
  83 #define VTYP_TO_STYP(i) (((i) == VCHR) ? S_IFCHR : S_IFBLK)
  84 
  85 #define OTYP_VALID(i)   (((i) == OTYP_CHR) || ((i) == OTYP_BLK))
  86 #define OTYP_TO_VTYP(i) (((i) == OTYP_CHR) ? VCHR : VBLK)
  87 #define OTYP_TO_STYP(i) (((i) == OTYP_CHR) ? S_IFCHR : S_IFBLK)
  88 
  89 #define STYP_VALID(i)   (((i) == S_IFCHR) || ((i) == S_IFBLK))
  90 #define STYP_TO_VTYP(i) (((i) == S_IFCHR) ? VCHR : VBLK)
  91 
  92 /*
  93  * Define macros for accessing layered driver hash structures
  94  */
  95 #define LH_HASH(vp)             (handle_hash_func(vp) % LH_HASH_SZ)
  96 #define LI_HASH(mid, dip, dev)  (ident_hash_func(mid, dip, dev) % LI_HASH_SZ)
  97 
  98 /*
  99  * Define layered handle flags used in the lh_type field
 100  */
 101 #define LH_STREAM       (0x1)   /* handle to a streams device */
 102 #define LH_CBDEV        (0x2)   /* handle to a char/block device */
 103 
 104 /*
 105  * Define macro for devid property lookups
 106  */
 107 #define DEVID_PROP_FLAGS        (DDI_PROP_DONTPASS | \
 108                                 DDI_PROP_TYPE_STRING|DDI_PROP_CANSLEEP)
 109 
 110 /*
 111  * Dummy string for NDI events
 112  */
 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         }
 198 }
 199 
 200 static struct ldi_ident **
 201 ident_find_ref_nolock(modid_t modid, dev_info_t *dip, dev_t dev, major_t major)
 202 {
 203         struct ldi_ident        **lipp = NULL;
 204         uint_t                  index = LI_HASH(modid, dip, dev);
 205 
 206         ASSERT(MUTEX_HELD(&ldi_ident_hash_lock[index]));
 207 
 208         for (lipp = &(ldi_ident_hash[index]);
 209             (*lipp != NULL);
 210             lipp = &((*lipp)->li_next)) {
 211                 if (((*lipp)->li_modid == modid) &&
 212                     ((*lipp)->li_major == major) &&
 213                     ((*lipp)->li_dip == dip) &&
 214                     ((*lipp)->li_dev == dev))
 215                         break;
 216         }
 217 
 218         ASSERT(lipp != NULL);
 219         return (lipp);
 220 }
 221 
 222 static struct ldi_ident *
 223 ident_alloc(char *mod_name, dev_info_t *dip, dev_t dev, major_t major)
 224 {
 225         struct ldi_ident        *lip, **lipp, *retlip;
 226         modid_t                 modid;
 227         uint_t                  index;
 228 
 229         ASSERT(mod_name != NULL);
 230 
 231         /* get the module id */
 232         modid = mod_name_to_modid(mod_name);
 233         ASSERT(modid != -1);
 234 
 235         /* allocate a new ident in case we need it */
 236         lip = kmem_zalloc(sizeof (*lip), KM_SLEEP);
 237 
 238         /* search the hash for a matching ident */
 239         index = LI_HASH(modid, dip, dev);
 240         mutex_enter(&ldi_ident_hash_lock[index]);
 241         lipp = ident_find_ref_nolock(modid, dip, dev, major);
 242 
 243         if (*lipp != NULL) {
 244                 /* we found an ident in the hash */
 245                 ASSERT(strcmp((*lipp)->li_modname, mod_name) == 0);
 246                 (*lipp)->li_ref++;
 247                 retlip = *lipp;
 248                 mutex_exit(&ldi_ident_hash_lock[index]);
 249                 kmem_free(lip, sizeof (struct ldi_ident));
 250                 return (retlip);
 251         }
 252 
 253         /* initialize the new ident */
 254         lip->li_next = NULL;
 255         lip->li_ref = 1;
 256         lip->li_modid = modid;
 257         lip->li_major = major;
 258         lip->li_dip = dip;
 259         lip->li_dev = dev;
 260         (void) strncpy(lip->li_modname, mod_name, sizeof (lip->li_modname) - 1);
 261 
 262         /* add it to the ident hash */
 263         lip->li_next = ldi_ident_hash[index];
 264         ldi_ident_hash[index] = lip;
 265 
 266         mutex_exit(&ldi_ident_hash_lock[index]);
 267         return (lip);
 268 }
 269 
 270 static void
 271 ident_hold(struct ldi_ident *lip)
 272 {
 273         uint_t                  index;
 274 
 275         ASSERT(lip != NULL);
 276         index = LI_HASH(lip->li_modid, lip->li_dip, lip->li_dev);
 277         mutex_enter(&ldi_ident_hash_lock[index]);
 278         ASSERT(lip->li_ref > 0);
 279         lip->li_ref++;
 280         mutex_exit(&ldi_ident_hash_lock[index]);
 281 }
 282 
 283 static void
 284 ident_release(struct ldi_ident *lip)
 285 {
 286         struct ldi_ident        **lipp;
 287         uint_t                  index;
 288 
 289         ASSERT(lip != NULL);
 290         index = LI_HASH(lip->li_modid, lip->li_dip, lip->li_dev);
 291         mutex_enter(&ldi_ident_hash_lock[index]);
 292 
 293         ASSERT(lip->li_ref > 0);
 294         if (--lip->li_ref > 0) {
 295                 /* there are more references to this ident */
 296                 mutex_exit(&ldi_ident_hash_lock[index]);
 297                 return;
 298         }
 299 
 300         /* this was the last reference/open for this ident.  free it. */
 301         lipp = ident_find_ref_nolock(
 302             lip->li_modid, lip->li_dip, lip->li_dev, lip->li_major);
 303 
 304         ASSERT((lipp != NULL) && (*lipp != NULL));
 305         *lipp = lip->li_next;
 306         mutex_exit(&ldi_ident_hash_lock[index]);
 307         kmem_free(lip, sizeof (struct ldi_ident));
 308 }
 309 
 310 /*
 311  * LDI handle manipulation functions
 312  */
 313 static uint_t
 314 handle_hash_func(void *vp)
 315 {
 316         uintptr_t k = (uintptr_t)vp;
 317         k >>= (int)highbit(sizeof (vnode_t));
 318         return ((uint_t)k);
 319 }
 320 
 321 static struct ldi_handle **
 322 handle_find_ref_nolock(vnode_t *vp, struct ldi_ident *ident)
 323 {
 324         struct ldi_handle       **lhpp = NULL;
 325         uint_t                  index = LH_HASH(vp);
 326 
 327         ASSERT(MUTEX_HELD(&ldi_handle_hash_lock[index]));
 328 
 329         for (lhpp = &(ldi_handle_hash[index]);
 330             (*lhpp != NULL);
 331             lhpp = &((*lhpp)->lh_next)) {
 332                 if (((*lhpp)->lh_ident == ident) &&
 333                     ((*lhpp)->lh_vp == vp))
 334                         break;
 335         }
 336 
 337         ASSERT(lhpp != NULL);
 338         return (lhpp);
 339 }
 340 
 341 static struct ldi_handle *
 342 handle_find(vnode_t *vp, struct ldi_ident *ident)
 343 {
 344         struct ldi_handle       **lhpp, *retlhp;
 345         int                     index = LH_HASH(vp);
 346 
 347         mutex_enter(&ldi_handle_hash_lock[index]);
 348         lhpp = handle_find_ref_nolock(vp, ident);
 349         retlhp = *lhpp;
 350         mutex_exit(&ldi_handle_hash_lock[index]);
 351         return (retlhp);
 352 }
 353 
 354 static struct ldi_handle *
 355 handle_alloc(vnode_t *vp, struct ldi_ident *ident)
 356 {
 357         struct ldi_handle       *lhp, **lhpp, *retlhp;
 358         uint_t                  index;
 359 
 360         ASSERT((vp != NULL) && (ident != NULL));
 361 
 362         /* allocate a new handle in case we need it */
 363         lhp = kmem_zalloc(sizeof (*lhp), KM_SLEEP);
 364 
 365         /* search the hash for a matching handle */
 366         index = LH_HASH(vp);
 367         mutex_enter(&ldi_handle_hash_lock[index]);
 368         lhpp = handle_find_ref_nolock(vp, ident);
 369 
 370         if (*lhpp != NULL) {
 371                 /* we found a handle in the hash */
 372                 (*lhpp)->lh_ref++;
 373                 retlhp = *lhpp;
 374                 mutex_exit(&ldi_handle_hash_lock[index]);
 375 
 376                 LDI_ALLOCFREE((CE_WARN, "ldi handle alloc: dup "
 377                     "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
 378                     (void *)retlhp, (void *)ident, (void *)vp,
 379                     mod_major_to_name(getmajor(vp->v_rdev)),
 380                     getminor(vp->v_rdev)));
 381 
 382                 kmem_free(lhp, sizeof (struct ldi_handle));
 383                 return (retlhp);
 384         }
 385 
 386         /* initialize the new handle */
 387         lhp->lh_ref = 1;
 388         lhp->lh_vp = vp;
 389         lhp->lh_ident = ident;
 390 #ifdef  LDI_OBSOLETE_EVENT
 391         mutex_init(lhp->lh_lock, NULL, MUTEX_DEFAULT, NULL);
 392 #endif
 393 
 394         /* set the device type for this handle */
 395         lhp->lh_type = 0;
 396         if (vp->v_stream) {
 397                 ASSERT(vp->v_type == VCHR);
 398                 lhp->lh_type |= LH_STREAM;
 399         } else {
 400                 lhp->lh_type |= LH_CBDEV;
 401         }
 402 
 403         /* get holds on other objects */
 404         ident_hold(ident);
 405         ASSERT(vp->v_count >= 1);
 406         VN_HOLD(vp);
 407 
 408         /* add it to the handle hash */
 409         lhp->lh_next = ldi_handle_hash[index];
 410         ldi_handle_hash[index] = lhp;
 411         atomic_inc_ulong(&ldi_handle_hash_count);
 412 
 413         LDI_ALLOCFREE((CE_WARN, "ldi handle alloc: new "
 414             "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
 415             (void *)lhp, (void *)ident, (void *)vp,
 416             mod_major_to_name(getmajor(vp->v_rdev)),
 417             getminor(vp->v_rdev)));
 418 
 419         mutex_exit(&ldi_handle_hash_lock[index]);
 420         return (lhp);
 421 }
 422 
 423 static void
 424 handle_release(struct ldi_handle *lhp)
 425 {
 426         struct ldi_handle       **lhpp;
 427         uint_t                  index;
 428 
 429         ASSERT(lhp != NULL);
 430 
 431         index = LH_HASH(lhp->lh_vp);
 432         mutex_enter(&ldi_handle_hash_lock[index]);
 433 
 434         LDI_ALLOCFREE((CE_WARN, "ldi handle release: "
 435             "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
 436             (void *)lhp, (void *)lhp->lh_ident, (void *)lhp->lh_vp,
 437             mod_major_to_name(getmajor(lhp->lh_vp->v_rdev)),
 438             getminor(lhp->lh_vp->v_rdev)));
 439 
 440         ASSERT(lhp->lh_ref > 0);
 441         if (--lhp->lh_ref > 0) {
 442                 /* there are more references to this handle */
 443                 mutex_exit(&ldi_handle_hash_lock[index]);
 444                 return;
 445         }
 446 
 447         /* this was the last reference/open for this handle.  free it. */
 448         lhpp = handle_find_ref_nolock(lhp->lh_vp, lhp->lh_ident);
 449         ASSERT((lhpp != NULL) && (*lhpp != NULL));
 450         *lhpp = lhp->lh_next;
 451         atomic_dec_ulong(&ldi_handle_hash_count);
 452         mutex_exit(&ldi_handle_hash_lock[index]);
 453 
 454         VN_RELE(lhp->lh_vp);
 455         ident_release(lhp->lh_ident);
 456 #ifdef  LDI_OBSOLETE_EVENT
 457         mutex_destroy(lhp->lh_lock);
 458 #endif
 459         kmem_free(lhp, sizeof (struct ldi_handle));
 460 }
 461 
 462 #ifdef  LDI_OBSOLETE_EVENT
 463 /*
 464  * LDI event manipulation functions
 465  */
 466 static void
 467 handle_event_add(ldi_event_t *lep)
 468 {
 469         struct ldi_handle *lhp = lep->le_lhp;
 470 
 471         ASSERT(lhp != NULL);
 472 
 473         mutex_enter(lhp->lh_lock);
 474         if (lhp->lh_events == NULL) {
 475                 lhp->lh_events = lep;
 476                 mutex_exit(lhp->lh_lock);
 477                 return;
 478         }
 479 
 480         lep->le_next = lhp->lh_events;
 481         lhp->lh_events->le_prev = lep;
 482         lhp->lh_events = lep;
 483         mutex_exit(lhp->lh_lock);
 484 }
 485 
 486 static void
 487 handle_event_remove(ldi_event_t *lep)
 488 {
 489         struct ldi_handle *lhp = lep->le_lhp;
 490 
 491         ASSERT(lhp != NULL);
 492 
 493         mutex_enter(lhp->lh_lock);
 494         if (lep->le_prev)
 495                 lep->le_prev->le_next = lep->le_next;
 496         if (lep->le_next)
 497                 lep->le_next->le_prev = lep->le_prev;
 498         if (lhp->lh_events == lep)
 499                 lhp->lh_events = lep->le_next;
 500         mutex_exit(lhp->lh_lock);
 501 
 502 }
 503 
 504 static void
 505 i_ldi_callback(dev_info_t *dip, ddi_eventcookie_t event_cookie,
 506     void *arg, void *bus_impldata)
 507 {
 508         ldi_event_t *lep = (ldi_event_t *)arg;
 509 
 510         ASSERT(lep != NULL);
 511 
 512         LDI_EVENTCB((CE_NOTE, "%s: dip=0x%p, "
 513             "event_cookie=0x%p, ldi_eventp=0x%p", "i_ldi_callback",
 514             (void *)dip, (void *)event_cookie, (void *)lep));
 515 
 516         lep->le_handler(lep->le_lhp, event_cookie, lep->le_arg, bus_impldata);
 517 }
 518 #endif
 519 
 520 /*
 521  * LDI open helper functions
 522  */
 523 
 524 /* get a vnode to a device by dev_t and otyp */
 525 static int
 526 ldi_vp_from_dev(dev_t dev, int otyp, vnode_t **vpp)
 527 {
 528         dev_info_t              *dip;
 529         vnode_t                 *vp;
 530 
 531         /* sanity check required input parameters */
 532         if ((dev == DDI_DEV_T_NONE) || (!OTYP_VALID(otyp)) || (vpp == NULL))
 533                 return (EINVAL);
 534 
 535         if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
 536                 return (ENODEV);
 537 
 538         vp = makespecvp(dev, OTYP_TO_VTYP(otyp));
 539         spec_assoc_vp_with_devi(vp, dip);
 540         ddi_release_devi(dip);  /* from e_ddi_hold_devi_by_dev */
 541 
 542         *vpp = vp;
 543         return (0);
 544 }
 545 
 546 /* get a vnode to a device by pathname */
 547 int
 548 ldi_vp_from_name(char *path, vnode_t **vpp)
 549 {
 550         vnode_t                 *vp = NULL;
 551         int                     ret;
 552 
 553         /* sanity check required input parameters */
 554         if ((path == NULL) || (vpp == NULL))
 555                 return (EINVAL);
 556 
 557         if (modrootloaded) {
 558                 cred_t *saved_cred = curthread->t_cred;
 559 
 560                 /* we don't want lookupname to fail because of credentials */
 561                 curthread->t_cred = kcred;
 562 
 563                 /*
 564                  * all lookups should be done in the global zone.  but
 565                  * lookupnameat() won't actually do this if an absolute
 566                  * path is passed in.  since the ldi interfaces require an
 567                  * absolute path we pass lookupnameat() a pointer to
 568                  * the character after the leading '/' and tell it to
 569                  * start searching at the current system root directory.
 570                  */
 571                 ASSERT(*path == '/');
 572                 ret = lookupnameat(path + 1, UIO_SYSSPACE, FOLLOW, NULLVPP,
 573                     &vp, rootdir);
 574 
 575                 /* restore this threads credentials */
 576                 curthread->t_cred = saved_cred;
 577 
 578                 if (ret == 0) {
 579                         if (!vn_matchops(vp, spec_getvnodeops()) ||
 580                             !VTYP_VALID(vp->v_type)) {
 581                                 VN_RELE(vp);
 582                                 return (ENXIO);
 583                         }
 584                 }
 585         }
 586 
 587         if (vp == NULL) {
 588                 dev_info_t      *dip;
 589                 dev_t           dev;
 590                 int             spec_type;
 591 
 592                 /*
 593                  * Root is not mounted, the minor node is not specified,
 594                  * or an OBP path has been specified.
 595                  */
 596 
 597                 /*
 598                  * Determine if path can be pruned to produce an
 599                  * OBP or devfs path for resolve_pathname.
 600                  */
 601                 if (strncmp(path, "/devices/", 9) == 0)
 602                         path += strlen("/devices");
 603 
 604                 /*
 605                  * if no minor node was specified the DEFAULT minor node
 606                  * will be returned.  if there is no DEFAULT minor node
 607                  * one will be fabricated of type S_IFCHR with the minor
 608                  * number equal to the instance number.
 609                  */
 610                 ret = resolve_pathname(path, &dip, &dev, &spec_type);
 611                 if (ret != 0)
 612                         return (ENODEV);
 613 
 614                 ASSERT(STYP_VALID(spec_type));
 615                 vp = makespecvp(dev, STYP_TO_VTYP(spec_type));
 616                 spec_assoc_vp_with_devi(vp, dip);
 617                 ddi_release_devi(dip);
 618         }
 619 
 620         *vpp = vp;
 621         return (0);
 622 }
 623 
 624 static int
 625 ldi_devid_match(ddi_devid_t devid, dev_info_t *dip, dev_t dev)
 626 {
 627         char            *devidstr;
 628         ddi_prop_t      *propp;
 629 
 630         /* convert devid as a string property */
 631         if ((devidstr = ddi_devid_str_encode(devid, NULL)) == NULL)
 632                 return (0);
 633 
 634         /*
 635          * Search for the devid.  For speed and ease in locking this
 636          * code directly uses the property implementation.  See
 637          * ddi_common_devid_to_devlist() for a comment as to why.
 638          */
 639         mutex_enter(&(DEVI(dip)->devi_lock));
 640 
 641         /* check if there is a DDI_DEV_T_NONE devid property */
 642         propp = i_ddi_prop_search(DDI_DEV_T_NONE,
 643             DEVID_PROP_NAME, DEVID_PROP_FLAGS, &DEVI(dip)->devi_hw_prop_ptr);
 644         if (propp != NULL) {
 645                 if (ddi_devid_str_compare(propp->prop_val, devidstr) == 0) {
 646                         /* a DDI_DEV_T_NONE devid exists and matchs */
 647                         mutex_exit(&(DEVI(dip)->devi_lock));
 648                         ddi_devid_str_free(devidstr);
 649                         return (1);
 650                 } else {
 651                         /* a DDI_DEV_T_NONE devid exists and doesn't match */
 652                         mutex_exit(&(DEVI(dip)->devi_lock));
 653                         ddi_devid_str_free(devidstr);
 654                         return (0);
 655                 }
 656         }
 657 
 658         /* check if there is a devt specific devid property */
 659         propp = i_ddi_prop_search(dev,
 660             DEVID_PROP_NAME, DEVID_PROP_FLAGS, &(DEVI(dip)->devi_hw_prop_ptr));
 661         if (propp != NULL) {
 662                 if (ddi_devid_str_compare(propp->prop_val, devidstr) == 0) {
 663                         /* a devt specific devid exists and matchs */
 664                         mutex_exit(&(DEVI(dip)->devi_lock));
 665                         ddi_devid_str_free(devidstr);
 666                         return (1);
 667                 } else {
 668                         /* a devt specific devid exists and doesn't match */
 669                         mutex_exit(&(DEVI(dip)->devi_lock));
 670                         ddi_devid_str_free(devidstr);
 671                         return (0);
 672                 }
 673         }
 674 
 675         /* we didn't find any devids associated with the device */
 676         mutex_exit(&(DEVI(dip)->devi_lock));
 677         ddi_devid_str_free(devidstr);
 678         return (0);
 679 }
 680 
 681 /* get a handle to a device by devid and minor name */
 682 int
 683 ldi_vp_from_devid(ddi_devid_t devid, char *minor_name, vnode_t **vpp)
 684 {
 685         dev_info_t              *dip;
 686         vnode_t                 *vp;
 687         int                     ret, i, ndevs, styp;
 688         dev_t                   dev, *devs;
 689 
 690         /* sanity check required input parameters */
 691         if ((devid == NULL) || (minor_name == NULL) || (vpp == NULL))
 692                 return (EINVAL);
 693 
 694         ret = ddi_lyr_devid_to_devlist(devid, minor_name, &ndevs, &devs);
 695         if ((ret != DDI_SUCCESS) || (ndevs <= 0))
 696                 return (ENODEV);
 697 
 698         for (i = 0; i < ndevs; i++) {
 699                 dev = devs[i];
 700 
 701                 if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
 702                         continue;
 703 
 704                 /*
 705                  * now we have to verify that the devid of the disk
 706                  * still matches what was requested.
 707                  *
 708                  * we have to do this because the devid could have
 709                  * changed between the call to ddi_lyr_devid_to_devlist()
 710                  * and e_ddi_hold_devi_by_dev().  this is because when
 711                  * ddi_lyr_devid_to_devlist() returns a list of devts
 712                  * there is no kind of hold on those devts so a device
 713                  * could have been replaced out from under us in the
 714                  * interim.
 715                  */
 716                 if ((i_ddi_minorname_to_devtspectype(dip, minor_name,
 717                     NULL, &styp) == DDI_SUCCESS) &&
 718                     ldi_devid_match(devid, dip, dev))
 719                         break;
 720 
 721                 ddi_release_devi(dip);  /* from e_ddi_hold_devi_by_dev() */
 722         }
 723 
 724         ddi_lyr_free_devlist(devs, ndevs);
 725 
 726         if (i == ndevs)
 727                 return (ENODEV);
 728 
 729         ASSERT(STYP_VALID(styp));
 730         vp = makespecvp(dev, STYP_TO_VTYP(styp));
 731         spec_assoc_vp_with_devi(vp, dip);
 732         ddi_release_devi(dip);          /* from e_ddi_hold_devi_by_dev */
 733 
 734         *vpp = vp;
 735         return (0);
 736 }
 737 
 738 /* given a vnode, open a device */
 739 static int
 740 ldi_open_by_vp(vnode_t **vpp, int flag, cred_t *cr,
 741     ldi_handle_t *lhp, struct ldi_ident *li)
 742 {
 743         struct ldi_handle       *nlhp;
 744         vnode_t                 *vp;
 745         int                     err;
 746 
 747         ASSERT((vpp != NULL) && (*vpp != NULL));
 748         ASSERT((lhp != NULL) && (li != NULL));
 749 
 750         vp = *vpp;
 751         /* if the vnode passed in is not a device, then bail */
 752         if (!vn_matchops(vp, spec_getvnodeops()) || !VTYP_VALID(vp->v_type))
 753                 return (ENXIO);
 754 
 755         /*
 756          * the caller may have specified a node that
 757          * doesn't have cb_ops defined.  the ldi doesn't yet
 758          * support opening devices without a valid cb_ops.
 759          */
 760         if (devopsp[getmajor(vp->v_rdev)]->devo_cb_ops == NULL)
 761                 return (ENXIO);
 762 
 763         /* open the device */
 764         if ((err = VOP_OPEN(&vp, flag | FKLYR, cr, NULL)) != 0)
 765                 return (err);
 766 
 767         /* possible clone open, make sure that we still have a spec node */
 768         ASSERT(vn_matchops(vp, spec_getvnodeops()));
 769 
 770         nlhp = handle_alloc(vp, li);
 771 
 772         if (vp != *vpp) {
 773                 /*
 774                  * allocating the layered handle took a new hold on the vnode
 775                  * so we can release the hold that was returned by the clone
 776                  * open
 777                  */
 778                 LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p",
 779                     "ldi clone open", (void *)nlhp));
 780         } else {
 781                 LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p",
 782                     "ldi open", (void *)nlhp));
 783         }
 784 
 785         *vpp = vp;
 786         *lhp = (ldi_handle_t)nlhp;
 787         return (0);
 788 }
 789 
 790 /* Call a drivers prop_op(9E) interface */
 791 static int
 792 i_ldi_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
 793     int flags, char *name, caddr_t valuep, int *lengthp)
 794 {
 795         struct dev_ops  *ops = NULL;
 796         int             res;
 797 
 798         ASSERT((dip != NULL) && (name != NULL));
 799         ASSERT((prop_op == PROP_LEN) || (valuep != NULL));
 800         ASSERT(lengthp != NULL);
 801 
 802         /*
 803          * we can only be invoked after a driver has been opened and
 804          * someone has a layered handle to it, so there had better be
 805          * a valid ops vector.
 806          */
 807         ops = DEVI(dip)->devi_ops;
 808         ASSERT(ops && ops->devo_cb_ops);
 809 
 810         /*
 811          * Some nexus drivers incorrectly set cb_prop_op to nodev,
 812          * nulldev or even NULL.
 813          */
 814         if ((ops->devo_cb_ops->cb_prop_op == nodev) ||
 815             (ops->devo_cb_ops->cb_prop_op == nulldev) ||
 816             (ops->devo_cb_ops->cb_prop_op == NULL)) {
 817                 return (DDI_PROP_NOT_FOUND);
 818         }
 819 
 820         /* check if this is actually DDI_DEV_T_ANY query */
 821         if (flags & LDI_DEV_T_ANY) {
 822                 flags &= ~LDI_DEV_T_ANY;
 823                 dev = DDI_DEV_T_ANY;
 824         }
 825 
 826         res = cdev_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp);
 827         return (res);
 828 }
 829 
 830 static void
 831 i_ldi_prop_op_free(struct prop_driver_data *pdd)
 832 {
 833         kmem_free(pdd, pdd->pdd_size);
 834 }
 835 
 836 static caddr_t
 837 i_ldi_prop_op_alloc(int prop_len)
 838 {
 839         struct prop_driver_data *pdd;
 840         int                     pdd_size;
 841 
 842         pdd_size = sizeof (struct prop_driver_data) + prop_len;
 843         pdd = kmem_alloc(pdd_size, KM_SLEEP);
 844         pdd->pdd_size = pdd_size;
 845         pdd->pdd_prop_free = i_ldi_prop_op_free;
 846         return ((caddr_t)&pdd[1]);
 847 }
 848 
 849 /*
 850  * i_ldi_prop_op_typed() is a wrapper for i_ldi_prop_op that is used
 851  * by the typed ldi property lookup interfaces.
 852  */
 853 static int
 854 i_ldi_prop_op_typed(dev_t dev, dev_info_t *dip, int flags, char *name,
 855     caddr_t *datap, int *lengthp, int elem_size)
 856 {
 857         caddr_t prop_val;
 858         int     prop_len, res;
 859 
 860         ASSERT((dip != NULL) && (name != NULL));
 861         ASSERT((datap != NULL) && (lengthp != NULL));
 862 
 863         /*
 864          * first call the drivers prop_op() interface to allow it
 865          * it to override default property values.
 866          */
 867         res = i_ldi_prop_op(dev, dip, PROP_LEN,
 868             flags | DDI_PROP_DYNAMIC, name, NULL, &prop_len);
 869         if (res != DDI_PROP_SUCCESS)
 870                 return (DDI_PROP_NOT_FOUND);
 871 
 872         /* sanity check the property length */
 873         if (prop_len == 0) {
 874                 /*
 875                  * the ddi typed interfaces don't allow a drivers to
 876                  * create properties with a length of 0.  so we should
 877                  * prevent drivers from returning 0 length dynamic
 878                  * properties for typed property lookups.
 879                  */
 880                 return (DDI_PROP_NOT_FOUND);
 881         }
 882 
 883         /* sanity check the property length against the element size */
 884         if (elem_size && ((prop_len % elem_size) != 0))
 885                 return (DDI_PROP_NOT_FOUND);
 886 
 887         /*
 888          * got it.  now allocate a prop_driver_data struct so that the
 889          * user can free the property via ddi_prop_free().
 890          */
 891         prop_val = i_ldi_prop_op_alloc(prop_len);
 892 
 893         /* lookup the property again, this time get the value */
 894         res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
 895             flags | DDI_PROP_DYNAMIC, name, prop_val, &prop_len);
 896         if (res != DDI_PROP_SUCCESS) {
 897                 ddi_prop_free(prop_val);
 898                 return (DDI_PROP_NOT_FOUND);
 899         }
 900 
 901         /* sanity check the property length */
 902         if (prop_len == 0) {
 903                 ddi_prop_free(prop_val);
 904                 return (DDI_PROP_NOT_FOUND);
 905         }
 906 
 907         /* sanity check the property length against the element size */
 908         if (elem_size && ((prop_len % elem_size) != 0)) {
 909                 ddi_prop_free(prop_val);
 910                 return (DDI_PROP_NOT_FOUND);
 911         }
 912 
 913         /*
 914          * return the prop_driver_data struct and, optionally, the length
 915          * of the data.
 916          */
 917         *datap = prop_val;
 918         *lengthp = prop_len;
 919 
 920         return (DDI_PROP_SUCCESS);
 921 }
 922 
 923 /*
 924  * i_check_string looks at a string property and makes sure its
 925  * a valid null terminated string
 926  */
 927 static int
 928 i_check_string(char *str, int prop_len)
 929 {
 930         int i;
 931 
 932         ASSERT(str != NULL);
 933 
 934         for (i = 0; i < prop_len; i++) {
 935                 if (str[i] == '\0')
 936                         return (0);
 937         }
 938         return (1);
 939 }
 940 
 941 /*
 942  * i_pack_string_array takes a a string array property that is represented
 943  * as a concatenation of strings (with the NULL character included for
 944  * each string) and converts it into a format that can be returned by
 945  * ldi_prop_lookup_string_array.
 946  */
 947 static int
 948 i_pack_string_array(char *str_concat, int prop_len,
 949     char ***str_arrayp, int *nelemp)
 950 {
 951         int i, nelem, pack_size;
 952         char **str_array, *strptr;
 953 
 954         /*
 955          * first we need to sanity check the input string array.
 956          * in essence this can be done my making sure that the last
 957          * character of the array passed in is null.  (meaning the last
 958          * string in the array is NULL terminated.
 959          */
 960         if (str_concat[prop_len - 1] != '\0')
 961                 return (1);
 962 
 963         /* now let's count the number of strings in the array */
 964         for (nelem = i = 0; i < prop_len; i++)
 965                 if (str_concat[i] == '\0')
 966                         nelem++;
 967         ASSERT(nelem >= 1);
 968 
 969         /* now let's allocate memory for the new packed property */
 970         pack_size = (sizeof (char *) * (nelem + 1)) + prop_len;
 971         str_array = (char **)i_ldi_prop_op_alloc(pack_size);
 972 
 973         /* let's copy the actual string data into the new property */
 974         strptr = (char *)&(str_array[nelem + 1]);
 975         bcopy(str_concat, strptr, prop_len);
 976 
 977         /* now initialize the string array pointers */
 978         for (i = 0; i < nelem; i++) {
 979                 str_array[i] = strptr;
 980                 strptr += strlen(strptr) + 1;
 981         }
 982         str_array[nelem] = NULL;
 983 
 984         /* set the return values */
 985         *str_arrayp = str_array;
 986         *nelemp = nelem;
 987 
 988         return (0);
 989 }
 990 
 991 
 992 /*
 993  * LDI Project private device usage interfaces
 994  */
 995 
 996 /*
 997  * Get a count of how many devices are currentl open by different consumers
 998  */
 999 int
1000 ldi_usage_count()
1001 {
1002         return (ldi_handle_hash_count);
1003 }
1004 
1005 static void
1006 ldi_usage_walker_tgt_helper(ldi_usage_t *ldi_usage, vnode_t *vp)
1007 {
1008         dev_info_t      *dip;
1009         dev_t           dev;
1010 
1011         ASSERT(STYP_VALID(VTYP_TO_STYP(vp->v_type)));
1012 
1013         /* get the target devt */
1014         dev = vp->v_rdev;
1015 
1016         /* try to get the target dip */
1017         dip = VTOCS(vp)->s_dip;
1018         if (dip != NULL) {
1019                 e_ddi_hold_devi(dip);
1020         } else if (dev != DDI_DEV_T_NONE) {
1021                 dip = e_ddi_hold_devi_by_dev(dev, 0);
1022         }
1023 
1024         /* set the target information */
1025         ldi_usage->tgt_name = mod_major_to_name(getmajor(dev));
1026         ldi_usage->tgt_modid = mod_name_to_modid(ldi_usage->tgt_name);
1027         ldi_usage->tgt_devt = dev;
1028         ldi_usage->tgt_spec_type = VTYP_TO_STYP(vp->v_type);
1029         ldi_usage->tgt_dip = dip;
1030 }
1031 
1032 
1033 static int
1034 ldi_usage_walker_helper(struct ldi_ident *lip, vnode_t *vp,
1035     void *arg, int (*callback)(const ldi_usage_t *, void *))
1036 {
1037         ldi_usage_t     ldi_usage;
1038         struct devnames *dnp;
1039         dev_info_t      *dip;
1040         major_t         major;
1041         dev_t           dev;
1042         int             ret = LDI_USAGE_CONTINUE;
1043 
1044         /* set the target device information */
1045         ldi_usage_walker_tgt_helper(&ldi_usage, vp);
1046 
1047         /* get the source devt */
1048         dev = lip->li_dev;
1049 
1050         /* try to get the source dip */
1051         dip = lip->li_dip;
1052         if (dip != NULL) {
1053                 e_ddi_hold_devi(dip);
1054         } else if (dev != DDI_DEV_T_NONE) {
1055                 dip = e_ddi_hold_devi_by_dev(dev, 0);
1056         }
1057 
1058         /* set the valid source information */
1059         ldi_usage.src_modid = lip->li_modid;
1060         ldi_usage.src_name = lip->li_modname;
1061         ldi_usage.src_devt = dev;
1062         ldi_usage.src_dip = dip;
1063 
1064         /*
1065          * if the source ident represents either:
1066          *
1067          * - a kernel module (and not a device or device driver)
1068          * - a device node
1069          *
1070          * then we currently have all the info we need to report the
1071          * usage information so invoke the callback function.
1072          */
1073         if (((lip->li_major == -1) && (dev == DDI_DEV_T_NONE)) ||
1074             (dip != NULL)) {
1075                 ret = callback(&ldi_usage, arg);
1076                 if (dip != NULL)
1077                         ddi_release_devi(dip);
1078                 if (ldi_usage.tgt_dip != NULL)
1079                         ddi_release_devi(ldi_usage.tgt_dip);
1080                 return (ret);
1081         }
1082 
1083         /*
1084          * now this is kinda gross.
1085          *
1086          * what we do here is attempt to associate every device instance
1087          * of the source driver on the system with the open target driver.
1088          * we do this because we don't know which instance of the device
1089          * could potentially access the lower device so we assume that all
1090          * the instances could access it.
1091          *
1092          * there are two ways we could have gotten here:
1093          *
1094          * 1) this layered ident represents one created using only a
1095          *    major number or a driver module name.  this means that when
1096          *    it was created we could not associate it with a particular
1097          *    dev_t or device instance.
1098          *
1099          *    when could this possibly happen you ask?
1100          *
1101          *    a perfect example of this is streams persistent links.
1102          *    when a persistant streams link is formed we can't associate
1103          *    the lower device stream with any particular upper device
1104          *    stream or instance.  this is because any particular upper
1105          *    device stream could be closed, then another could be
1106          *    opened with a different dev_t and device instance, and it
1107          *    would still have access to the lower linked stream.
1108          *
1109          *    since any instance of the upper streams driver could
1110          *    potentially access the lower stream whenever it wants,
1111          *    we represent that here by associating the opened lower
1112          *    device with every existing device instance of the upper
1113          *    streams driver.
1114          *
1115          * 2) This case should really never happen but we'll include it
1116          *    for completeness.
1117          *
1118          *    it's possible that we could have gotten here because we
1119          *    have a dev_t for the upper device but we couldn't find a
1120          *    dip associated with that dev_t.
1121          *
1122          *    the only types of devices that have dev_t without an
1123          *    associated dip are unbound DLPIv2 network devices.  These
1124          *    types of devices exist to be able to attach a stream to any
1125          *    instance of a hardware network device.  since these types of
1126          *    devices are usually hardware devices they should never
1127          *    really have other devices open.
1128          */
1129         if (dev != DDI_DEV_T_NONE)
1130                 major = getmajor(dev);
1131         else
1132                 major = lip->li_major;
1133 
1134         ASSERT((major >= 0) && (major < devcnt));
1135 
1136         dnp = &devnamesp[major];
1137         LOCK_DEV_OPS(&dnp->dn_lock);
1138         dip = dnp->dn_head;
1139         while ((dip) && (ret == LDI_USAGE_CONTINUE)) {
1140                 e_ddi_hold_devi(dip);
1141                 UNLOCK_DEV_OPS(&dnp->dn_lock);
1142 
1143                 /* set the source dip */
1144                 ldi_usage.src_dip = dip;
1145 
1146                 /* invoke the callback function */
1147                 ret = callback(&ldi_usage, arg);
1148 
1149                 LOCK_DEV_OPS(&dnp->dn_lock);
1150                 ddi_release_devi(dip);
1151                 dip = ddi_get_next(dip);
1152         }
1153         UNLOCK_DEV_OPS(&dnp->dn_lock);
1154 
1155         /* if there was a target dip, release it */
1156         if (ldi_usage.tgt_dip != NULL)
1157                 ddi_release_devi(ldi_usage.tgt_dip);
1158 
1159         return (ret);
1160 }
1161 
1162 /*
1163  * ldi_usage_walker() - this walker reports LDI kernel device usage
1164  * information via the callback() callback function.  the LDI keeps track
1165  * of what devices are being accessed in its own internal data structures.
1166  * this function walks those data structures to determine device usage.
1167  */
1168 void
1169 ldi_usage_walker(void *arg, int (*callback)(const ldi_usage_t *, void *))
1170 {
1171         struct ldi_handle       *lhp;
1172         struct ldi_ident        *lip;
1173         vnode_t                 *vp;
1174         int                     i;
1175         int                     ret = LDI_USAGE_CONTINUE;
1176 
1177         for (i = 0; i < LH_HASH_SZ; i++) {
1178                 mutex_enter(&ldi_handle_hash_lock[i]);
1179 
1180                 lhp = ldi_handle_hash[i];
1181                 while ((lhp != NULL) && (ret == LDI_USAGE_CONTINUE)) {
1182                         lip = lhp->lh_ident;
1183                         vp = lhp->lh_vp;
1184 
1185                         /* invoke the devinfo callback function */
1186                         ret = ldi_usage_walker_helper(lip, vp, arg, callback);
1187 
1188                         lhp = lhp->lh_next;
1189                 }
1190                 mutex_exit(&ldi_handle_hash_lock[i]);
1191 
1192                 if (ret != LDI_USAGE_CONTINUE)
1193                         break;
1194         }
1195 }
1196 
1197 /*
1198  * LDI Project private interfaces (streams linking interfaces)
1199  *
1200  * Streams supports a type of built in device layering via linking.
1201  * Certain types of streams drivers can be streams multiplexors.
1202  * A streams multiplexor supports the I_LINK/I_PLINK operation.
1203  * These operations allows other streams devices to be linked under the
1204  * multiplexor.  By definition all streams multiplexors are devices
1205  * so this linking is a type of device layering where the multiplexor
1206  * device is layered on top of the device linked below it.
1207  */
1208 
1209 /*
1210  * ldi_mlink_lh() is invoked when streams are linked using LDI handles.
1211  * It is not used for normal I_LINKs and I_PLINKs using file descriptors.
1212  *
1213  * The streams framework keeps track of links via the file_t of the lower
1214  * stream.  The LDI keeps track of devices using a vnode.  In the case
1215  * of a streams link created via an LDI handle, fnk_lh() allocates
1216  * a file_t that the streams framework can use to track the linkage.
1217  */
1218 int
1219 ldi_mlink_lh(vnode_t *vp, int cmd, intptr_t arg, cred_t *crp, int *rvalp)
1220 {
1221         struct ldi_handle       *lhp = (struct ldi_handle *)arg;
1222         vnode_t                 *vpdown;
1223         file_t                  *fpdown;
1224         int                     err;
1225 
1226         if (lhp == NULL)
1227                 return (EINVAL);
1228 
1229         vpdown = lhp->lh_vp;
1230         ASSERT(vn_matchops(vpdown, spec_getvnodeops()));
1231         ASSERT(cmd == _I_PLINK_LH);
1232 
1233         /*
1234          * create a new lower vnode and a file_t that points to it,
1235          * streams linking requires a file_t.  falloc() returns with
1236          * fpdown locked.
1237          */
1238         VN_HOLD(vpdown);
1239         (void) falloc(vpdown, FREAD|FWRITE, &fpdown, NULL);
1240         mutex_exit(&fpdown->f_tlock);
1241 
1242         /* try to establish the link */
1243         err = mlink_file(vp, I_PLINK, fpdown, crp, rvalp, 1);
1244 
1245         if (err != 0) {
1246                 /* the link failed, free the file_t and release the vnode */
1247                 mutex_enter(&fpdown->f_tlock);
1248                 unfalloc(fpdown);
1249                 VN_RELE(vpdown);
1250         }
1251 
1252         return (err);
1253 }
1254 
1255 /*
1256  * ldi_mlink_fp() is invoked for all successful streams linkages created
1257  * via I_LINK and I_PLINK.  ldi_mlink_fp() records the linkage information
1258  * in its internal state so that the devinfo snapshot code has some
1259  * observability into streams device linkage information.
1260  */
1261 void
1262 ldi_mlink_fp(struct stdata *stp, file_t *fpdown, int lhlink, int type)
1263 {
1264         vnode_t                 *vp = fpdown->f_vnode;
1265         struct snode            *sp, *csp;
1266         ldi_ident_t             li;
1267         major_t                 major;
1268         int                     ret;
1269 
1270         /* if the lower stream is not a device then return */
1271         if (!vn_matchops(vp, spec_getvnodeops()))
1272                 return;
1273 
1274         ASSERT(!servicing_interrupt());
1275 
1276         LDI_STREAMS_LNK((CE_NOTE, "%s: linking streams "
1277             "stp=0x%p, fpdown=0x%p", "ldi_mlink_fp",
1278             (void *)stp, (void *)fpdown));
1279 
1280         sp = VTOS(vp);
1281         csp = VTOS(sp->s_commonvp);
1282 
1283         /* check if this was a plink via a layered handle */
1284         if (lhlink) {
1285                 /*
1286                  * increment the common snode s_count.
1287                  *
1288                  * this is done because after the link operation there
1289                  * are two ways that s_count can be decremented.
1290                  *
1291                  * when the layered handle used to create the link is
1292                  * closed, spec_close() is called and it will decrement
1293                  * s_count in the common snode.  if we don't increment
1294                  * s_count here then this could cause spec_close() to
1295                  * actually close the device while it's still linked
1296                  * under a multiplexer.
1297                  *
1298                  * also, when the lower stream is unlinked, closef() is
1299                  * called for the file_t associated with this snode.
1300                  * closef() will call spec_close(), which will decrement
1301                  * s_count.  if we dont't increment s_count here then this
1302                  * could cause spec_close() to actually close the device
1303                  * while there may still be valid layered handles
1304                  * pointing to it.
1305                  */
1306                 mutex_enter(&csp->s_lock);
1307                 ASSERT(csp->s_count >= 1);
1308                 csp->s_count++;
1309                 mutex_exit(&csp->s_lock);
1310 
1311                 /*
1312                  * decrement the f_count.
1313                  * this is done because the layered driver framework does
1314                  * not actually cache a copy of the file_t allocated to
1315                  * do the link.  this is done here instead of in ldi_mlink_lh()
1316                  * because there is a window in ldi_mlink_lh() between where
1317                  * milnk_file() returns and we would decrement the f_count
1318                  * when the stream could be unlinked.
1319                  */
1320                 mutex_enter(&fpdown->f_tlock);
1321                 fpdown->f_count--;
1322                 mutex_exit(&fpdown->f_tlock);
1323         }
1324 
1325         /*
1326          * NOTE: here we rely on the streams subsystem not allowing
1327          * a stream to be multiplexed more than once.  if this
1328          * changes, we break.
1329          *
1330          * mark the snode/stream as multiplexed
1331          */
1332         mutex_enter(&sp->s_lock);
1333         ASSERT(!(sp->s_flag & SMUXED));
1334         sp->s_flag |= SMUXED;
1335         mutex_exit(&sp->s_lock);
1336 
1337         /* get a layered ident for the upper stream */
1338         if (type == LINKNORMAL) {
1339                 /*
1340                  * if the link is not persistant then we can associate
1341                  * the upper stream with a dev_t.  this is because the
1342                  * upper stream is associated with a vnode, which is
1343                  * associated with a dev_t and this binding can't change
1344                  * during the life of the stream.  since the link isn't
1345                  * persistant once the stream is destroyed the link is
1346                  * destroyed.  so the dev_t will be valid for the life
1347                  * of the link.
1348                  */
1349                 ret = ldi_ident_from_stream(getendq(stp->sd_wrq), &li);
1350         } else {
1351                 /*
1352                  * if the link is persistant we can only associate the
1353                  * link with a driver (and not a dev_t.)  this is
1354                  * because subsequent opens of the upper device may result
1355                  * in a different stream (and dev_t) having access to
1356                  * the lower stream.
1357                  *
1358                  * for example, if the upper stream is closed after the
1359                  * persistant link operation is compleated, a subsequent
1360                  * open of the upper device will create a new stream which
1361                  * may have a different dev_t and an unlink operation
1362                  * can be performed using this new upper stream.
1363                  */
1364                 ASSERT(type == LINKPERSIST);
1365                 major = getmajor(stp->sd_vnode->v_rdev);
1366                 ret = ldi_ident_from_major(major, &li);
1367         }
1368 
1369         ASSERT(ret == 0);
1370         (void) handle_alloc(vp, (struct ldi_ident *)li);
1371         ldi_ident_release(li);
1372 }
1373 
1374 void
1375 ldi_munlink_fp(struct stdata *stp, file_t *fpdown, int type)
1376 {
1377         struct ldi_handle       *lhp;
1378         vnode_t                 *vp = (vnode_t *)fpdown->f_vnode;
1379         struct snode            *sp;
1380         ldi_ident_t             li;
1381         major_t                 major;
1382         int                     ret;
1383 
1384         /* if the lower stream is not a device then return */
1385         if (!vn_matchops(vp, spec_getvnodeops()))
1386                 return;
1387 
1388         ASSERT(!servicing_interrupt());
1389         ASSERT((type == LINKNORMAL) || (type == LINKPERSIST));
1390 
1391         LDI_STREAMS_LNK((CE_NOTE, "%s: unlinking streams "
1392             "stp=0x%p, fpdown=0x%p", "ldi_munlink_fp",
1393             (void *)stp, (void *)fpdown));
1394 
1395         /*
1396          * NOTE: here we rely on the streams subsystem not allowing
1397          * a stream to be multiplexed more than once.  if this
1398          * changes, we break.
1399          *
1400          * mark the snode/stream as not multiplexed
1401          */
1402         sp = VTOS(vp);
1403         mutex_enter(&sp->s_lock);
1404         ASSERT(sp->s_flag & SMUXED);
1405         sp->s_flag &= ~SMUXED;
1406         mutex_exit(&sp->s_lock);
1407 
1408         /*
1409          * clear the owner for this snode
1410          * see the comment in ldi_mlink_fp() for information about how
1411          * the ident is allocated
1412          */
1413         if (type == LINKNORMAL) {
1414                 ret = ldi_ident_from_stream(getendq(stp->sd_wrq), &li);
1415         } else {
1416                 ASSERT(type == LINKPERSIST);
1417                 major = getmajor(stp->sd_vnode->v_rdev);
1418                 ret = ldi_ident_from_major(major, &li);
1419         }
1420 
1421         ASSERT(ret == 0);
1422         lhp = handle_find(vp, (struct ldi_ident *)li);
1423         handle_release(lhp);
1424         ldi_ident_release(li);
1425 }
1426 
1427 /*
1428  * LDI Consolidation private interfaces
1429  */
1430 int
1431 ldi_ident_from_mod(struct modlinkage *modlp, ldi_ident_t *lip)
1432 {
1433         struct modctl           *modp;
1434         major_t                 major;
1435         char                    *name;
1436 
1437         if ((modlp == NULL) || (lip == NULL))
1438                 return (EINVAL);
1439 
1440         ASSERT(!servicing_interrupt());
1441 
1442         modp = mod_getctl(modlp);
1443         if (modp == NULL)
1444                 return (EINVAL);
1445         name = modp->mod_modname;
1446         if (name == NULL)
1447                 return (EINVAL);
1448         major = mod_name_to_major(name);
1449 
1450         *lip = (ldi_ident_t)ident_alloc(name, NULL, DDI_DEV_T_NONE, major);
1451 
1452         LDI_ALLOCFREE((CE_WARN, "%s: li=0x%p, mod=%s",
1453             "ldi_ident_from_mod", (void *)*lip, name));
1454 
1455         return (0);
1456 }
1457 
1458 ldi_ident_t
1459 ldi_ident_from_anon()
1460 {
1461         ldi_ident_t     lip;
1462 
1463         ASSERT(!servicing_interrupt());
1464 
1465         lip = (ldi_ident_t)ident_alloc("genunix", NULL, DDI_DEV_T_NONE, -1);
1466 
1467         LDI_ALLOCFREE((CE_WARN, "%s: li=0x%p, mod=%s",
1468             "ldi_ident_from_anon", (void *)lip, "genunix"));
1469 
1470         return (lip);
1471 }
1472 
1473 
1474 /*
1475  * LDI Public interfaces
1476  */
1477 int
1478 ldi_ident_from_stream(struct queue *sq, ldi_ident_t *lip)
1479 {
1480         struct stdata           *stp;
1481         dev_t                   dev;
1482         char                    *name;
1483 
1484         if ((sq == NULL) || (lip == NULL))
1485                 return (EINVAL);
1486 
1487         ASSERT(!servicing_interrupt());
1488 
1489         stp = sq->q_stream;
1490         if (!vn_matchops(stp->sd_vnode, spec_getvnodeops()))
1491                 return (EINVAL);
1492 
1493         dev = stp->sd_vnode->v_rdev;
1494         name = mod_major_to_name(getmajor(dev));
1495         if (name == NULL)
1496                 return (EINVAL);
1497         *lip = (ldi_ident_t)ident_alloc(name, NULL, dev, -1);
1498 
1499         LDI_ALLOCFREE((CE_WARN,
1500             "%s: li=0x%p, mod=%s, minor=0x%x, stp=0x%p",
1501             "ldi_ident_from_stream", (void *)*lip, name, getminor(dev),
1502             (void *)stp));
1503 
1504         return (0);
1505 }
1506 
1507 int
1508 ldi_ident_from_dev(dev_t dev, ldi_ident_t *lip)
1509 {
1510         char                    *name;
1511 
1512         if (lip == NULL)
1513                 return (EINVAL);
1514 
1515         ASSERT(!servicing_interrupt());
1516 
1517         name = mod_major_to_name(getmajor(dev));
1518         if (name == NULL)
1519                 return (EINVAL);
1520         *lip = (ldi_ident_t)ident_alloc(name, NULL, dev, -1);
1521 
1522         LDI_ALLOCFREE((CE_WARN,
1523             "%s: li=0x%p, mod=%s, minor=0x%x",
1524             "ldi_ident_from_dev", (void *)*lip, name, getminor(dev)));
1525 
1526         return (0);
1527 }
1528 
1529 int
1530 ldi_ident_from_dip(dev_info_t *dip, ldi_ident_t *lip)
1531 {
1532         struct dev_info         *devi = (struct dev_info *)dip;
1533         char                    *name;
1534 
1535         if ((dip == NULL) || (lip == NULL))
1536                 return (EINVAL);
1537 
1538         ASSERT(!servicing_interrupt());
1539 
1540         name = mod_major_to_name(devi->devi_major);
1541         if (name == NULL)
1542                 return (EINVAL);
1543         *lip = (ldi_ident_t)ident_alloc(name, dip, DDI_DEV_T_NONE, -1);
1544 
1545         LDI_ALLOCFREE((CE_WARN,
1546             "%s: li=0x%p, mod=%s, dip=0x%p",
1547             "ldi_ident_from_dip", (void *)*lip, name, (void *)devi));
1548 
1549         return (0);
1550 }
1551 
1552 int
1553 ldi_ident_from_major(major_t major, ldi_ident_t *lip)
1554 {
1555         char                    *name;
1556 
1557         if (lip == NULL)
1558                 return (EINVAL);
1559 
1560         ASSERT(!servicing_interrupt());
1561 
1562         name = mod_major_to_name(major);
1563         if (name == NULL)
1564                 return (EINVAL);
1565         *lip = (ldi_ident_t)ident_alloc(name, NULL, DDI_DEV_T_NONE, major);
1566 
1567         LDI_ALLOCFREE((CE_WARN,
1568             "%s: li=0x%p, mod=%s",
1569             "ldi_ident_from_major", (void *)*lip, name));
1570 
1571         return (0);
1572 }
1573 
1574 void
1575 ldi_ident_release(ldi_ident_t li)
1576 {
1577         struct ldi_ident        *ident = (struct ldi_ident *)li;
1578         char                    *name;
1579 
1580         if (li == NULL)
1581                 return;
1582 
1583         ASSERT(!servicing_interrupt());
1584 
1585         name = ident->li_modname;
1586 
1587         LDI_ALLOCFREE((CE_WARN,
1588             "%s: li=0x%p, mod=%s",
1589             "ldi_ident_release", (void *)li, name));
1590 
1591         ident_release((struct ldi_ident *)li);
1592 }
1593 
1594 /* get a handle to a device by dev_t and otyp */
1595 int
1596 ldi_open_by_dev(dev_t *devp, int otyp, int flag, cred_t *cr,
1597     ldi_handle_t *lhp, ldi_ident_t li)
1598 {
1599         struct ldi_ident        *lip = (struct ldi_ident *)li;
1600         int                     ret;
1601         vnode_t                 *vp;
1602 
1603         /* sanity check required input parameters */
1604         if ((devp == NULL) || (!OTYP_VALID(otyp)) || (cr == NULL) ||
1605             (lhp == NULL) || (lip == NULL))
1606                 return (EINVAL);
1607 
1608         ASSERT(!servicing_interrupt());
1609 
1610         if ((ret = ldi_vp_from_dev(*devp, otyp, &vp)) != 0)
1611                 return (ret);
1612 
1613         if ((ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip)) == 0) {
1614                 *devp = vp->v_rdev;
1615         }
1616         VN_RELE(vp);
1617 
1618         return (ret);
1619 }
1620 
1621 /* get a handle to a device by pathname */
1622 int
1623 ldi_open_by_name(char *pathname, int flag, cred_t *cr,
1624     ldi_handle_t *lhp, ldi_ident_t li)
1625 {
1626         struct ldi_ident        *lip = (struct ldi_ident *)li;
1627         int                     ret;
1628         vnode_t                 *vp;
1629 
1630         /* sanity check required input parameters */
1631         if ((pathname == NULL) || (*pathname != '/') ||
1632             (cr == NULL) || (lhp == NULL) || (lip == NULL))
1633                 return (EINVAL);
1634 
1635         ASSERT(!servicing_interrupt());
1636 
1637         if ((ret = ldi_vp_from_name(pathname, &vp)) != 0)
1638                 return (ret);
1639 
1640         ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip);
1641         VN_RELE(vp);
1642 
1643         return (ret);
1644 }
1645 
1646 /* get a handle to a device by devid and minor_name */
1647 int
1648 ldi_open_by_devid(ddi_devid_t devid, char *minor_name,
1649     int flag, cred_t *cr, ldi_handle_t *lhp, ldi_ident_t li)
1650 {
1651         struct ldi_ident        *lip = (struct ldi_ident *)li;
1652         int                     ret;
1653         vnode_t                 *vp;
1654 
1655         /* sanity check required input parameters */
1656         if ((minor_name == NULL) || (cr == NULL) ||
1657             (lhp == NULL) || (lip == NULL))
1658                 return (EINVAL);
1659 
1660         ASSERT(!servicing_interrupt());
1661 
1662         if ((ret = ldi_vp_from_devid(devid, minor_name, &vp)) != 0)
1663                 return (ret);
1664 
1665         ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip);
1666         VN_RELE(vp);
1667 
1668         return (ret);
1669 }
1670 
1671 int
1672 ldi_close(ldi_handle_t lh, int flag, cred_t *cr)
1673 {
1674         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
1675         struct ldi_event        *lep;
1676         int                     err = 0;
1677         int                     notify = 0;
1678         list_t                  *listp;
1679         ldi_ev_callback_impl_t  *lecp;
1680 
1681         if (lh == NULL)
1682                 return (EINVAL);
1683 
1684         ASSERT(!servicing_interrupt());
1685 
1686 #ifdef  LDI_OBSOLETE_EVENT
1687 
1688         /*
1689          * Any event handlers should have been unregistered by the
1690          * time ldi_close() is called.  If they haven't then it's a
1691          * bug.
1692          *
1693          * In a debug kernel we'll panic to make the problem obvious.
1694          */
1695         ASSERT(handlep->lh_events == NULL);
1696 
1697         /*
1698          * On a production kernel we'll "do the right thing" (unregister
1699          * the event handlers) and then complain about having to do the
1700          * work ourselves.
1701          */
1702         while ((lep = handlep->lh_events) != NULL) {
1703                 err = 1;
1704                 (void) ldi_remove_event_handler(lh, (ldi_callback_id_t)lep);
1705         }
1706         if (err) {
1707                 struct ldi_ident *lip = handlep->lh_ident;
1708                 ASSERT(lip != NULL);
1709                 cmn_err(CE_NOTE, "ldi err: %s "
1710                     "failed to unregister layered event handlers before "
1711                     "closing devices", lip->li_modname);
1712         }
1713 #endif
1714 
1715         /* do a layered close on the device */
1716         err = VOP_CLOSE(handlep->lh_vp, flag | FKLYR, 1, (offset_t)0, cr, NULL);
1717 
1718         LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p", "ldi close", (void *)lh));
1719 
1720         /*
1721          * Search the event callback list for callbacks with this
1722          * handle. There are 2 cases
1723          * 1. Called in the context of a notify. The handle consumer
1724          *    is releasing its hold on the device to allow a reconfiguration
1725          *    of the device. Simply NULL out the handle and the notify callback.
1726          *    The finalize callback is still available so that the consumer
1727          *    knows of the final disposition of the device.
1728          * 2. Not called in the context of notify. NULL out the handle as well
1729          *    as the notify and finalize callbacks. Since the consumer has
1730          *    closed the handle, we assume it is not interested in the
1731          *    notify and finalize callbacks.
1732          */
1733         ldi_ev_lock();
1734 
1735         if (handlep->lh_flags & LH_FLAGS_NOTIFY)
1736                 notify = 1;
1737         listp = &ldi_ev_callback_list.le_head;
1738         for (lecp = list_head(listp); lecp; lecp = list_next(listp, lecp)) {
1739                 if (lecp->lec_lhp != handlep)
1740                         continue;
1741                 lecp->lec_lhp = NULL;
1742                 lecp->lec_notify = NULL;
1743                 LDI_EVDBG((CE_NOTE, "ldi_close: NULLed lh and notify"));
1744                 if (!notify) {
1745                         LDI_EVDBG((CE_NOTE, "ldi_close: NULLed finalize"));
1746                         lecp->lec_finalize = NULL;
1747                 }
1748         }
1749 
1750         if (notify)
1751                 handlep->lh_flags &= ~LH_FLAGS_NOTIFY;
1752         ldi_ev_unlock();
1753 
1754         /*
1755          * Free the handle even if the device close failed.  why?
1756          *
1757          * If the device close failed we can't really make assumptions
1758          * about the devices state so we shouldn't allow access to the
1759          * device via this handle any more.  If the device consumer wants
1760          * to access the device again they should open it again.
1761          *
1762          * This is the same way file/device close failures are handled
1763          * in other places like spec_close() and closeandsetf().
1764          */
1765         handle_release(handlep);
1766         return (err);
1767 }
1768 
1769 int
1770 ldi_read(ldi_handle_t lh, struct uio *uiop, cred_t *credp)
1771 {
1772         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
1773         vnode_t                 *vp;
1774         dev_t                   dev;
1775         int                     ret;
1776 
1777         if (lh == NULL)
1778                 return (EINVAL);
1779 
1780         vp = handlep->lh_vp;
1781         dev = vp->v_rdev;
1782         if (handlep->lh_type & LH_CBDEV) {
1783                 ret = cdev_read(dev, uiop, credp);
1784         } else if (handlep->lh_type & LH_STREAM) {
1785                 ret = strread(vp, uiop, credp);
1786         } else {
1787                 return (ENOTSUP);
1788         }
1789         return (ret);
1790 }
1791 
1792 int
1793 ldi_write(ldi_handle_t lh, struct uio *uiop, cred_t *credp)
1794 {
1795         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
1796         vnode_t                 *vp;
1797         dev_t                   dev;
1798         int                     ret;
1799 
1800         if (lh == NULL)
1801                 return (EINVAL);
1802 
1803         vp = handlep->lh_vp;
1804         dev = vp->v_rdev;
1805         if (handlep->lh_type & LH_CBDEV) {
1806                 ret = cdev_write(dev, uiop, credp);
1807         } else if (handlep->lh_type & LH_STREAM) {
1808                 ret = strwrite(vp, uiop, credp);
1809         } else {
1810                 return (ENOTSUP);
1811         }
1812         return (ret);
1813 }
1814 
1815 int
1816 ldi_get_size(ldi_handle_t lh, uint64_t *sizep)
1817 {
1818         int                     otyp;
1819         uint_t                  value;
1820         int64_t                 drv_prop64;
1821         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
1822         uint_t                  blksize;
1823         int                     blkshift;
1824 
1825 
1826         if ((lh == NULL) || (sizep == NULL))
1827                 return (DDI_FAILURE);
1828 
1829         if (handlep->lh_type & LH_STREAM)
1830                 return (DDI_FAILURE);
1831 
1832         /*
1833          * Determine device type (char or block).
1834          * Character devices support Size/size
1835          * property value. Block devices may support
1836          * Nblocks/nblocks or Size/size property value.
1837          */
1838         if ((ldi_get_otyp(lh, &otyp)) != 0)
1839                 return (DDI_FAILURE);
1840 
1841         if (otyp == OTYP_BLK) {
1842                 if (ldi_prop_exists(lh,
1843                     DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Nblocks")) {
1844 
1845                         drv_prop64 = ldi_prop_get_int64(lh,
1846                             DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1847                             "Nblocks", 0);
1848                         blksize = ldi_prop_get_int(lh,
1849                             DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1850                             "blksize", DEV_BSIZE);
1851                         if (blksize == DEV_BSIZE)
1852                                 blksize = ldi_prop_get_int(lh, LDI_DEV_T_ANY |
1853                                     DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1854                                     "device-blksize", DEV_BSIZE);
1855 
1856                         /* blksize must be a power of two */
1857                         ASSERT(BIT_ONLYONESET(blksize));
1858                         blkshift = highbit(blksize) - 1;
1859 
1860                         /*
1861                          * We don't support Nblocks values that don't have
1862                          * an accurate uint64_t byte count representation.
1863                          */
1864                         if ((uint64_t)drv_prop64 >= (UINT64_MAX >> blkshift))
1865                                 return (DDI_FAILURE);
1866 
1867                         *sizep = (uint64_t)
1868                             (((u_offset_t)drv_prop64) << blkshift);
1869                         return (DDI_SUCCESS);
1870                 }
1871 
1872                 if (ldi_prop_exists(lh,
1873                     DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "nblocks")) {
1874 
1875                         value = ldi_prop_get_int(lh,
1876                             DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1877                             "nblocks", 0);
1878                         blksize = ldi_prop_get_int(lh,
1879                             DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1880                             "blksize", DEV_BSIZE);
1881                         if (blksize == DEV_BSIZE)
1882                                 blksize = ldi_prop_get_int(lh, LDI_DEV_T_ANY |
1883                                     DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1884                                     "device-blksize", DEV_BSIZE);
1885 
1886                         /* blksize must be a power of two */
1887                         ASSERT(BIT_ONLYONESET(blksize));
1888                         blkshift = highbit(blksize) - 1;
1889 
1890                         /*
1891                          * We don't support nblocks values that don't have an
1892                          * accurate uint64_t byte count representation.
1893                          */
1894                         if ((uint64_t)value >= (UINT64_MAX >> blkshift))
1895                                 return (DDI_FAILURE);
1896 
1897                         *sizep = (uint64_t)
1898                             (((u_offset_t)value) << blkshift);
1899                         return (DDI_SUCCESS);
1900                 }
1901         }
1902 
1903         if (ldi_prop_exists(lh,
1904             DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Size")) {
1905 
1906                 drv_prop64 = ldi_prop_get_int64(lh,
1907                     DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Size", 0);
1908                 *sizep = (uint64_t)drv_prop64;
1909                 return (DDI_SUCCESS);
1910         }
1911 
1912         if (ldi_prop_exists(lh,
1913             DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "size")) {
1914 
1915                 value = ldi_prop_get_int(lh,
1916                     DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "size", 0);
1917                 *sizep = (uint64_t)value;
1918                 return (DDI_SUCCESS);
1919         }
1920 
1921         /* unable to determine device size */
1922         return (DDI_FAILURE);
1923 }
1924 
1925 int
1926 ldi_ioctl(ldi_handle_t lh, int cmd, intptr_t arg, int mode,
1927         cred_t *cr, int *rvalp)
1928 {
1929         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
1930         vnode_t                 *vp;
1931         dev_t                   dev;
1932         int                     ret, copymode, unused;
1933 
1934         if (lh == NULL)
1935                 return (EINVAL);
1936 
1937         /*
1938          * if the data pointed to by arg is located in the kernel then
1939          * make sure the FNATIVE flag is set.
1940          */
1941         if (mode & FKIOCTL)
1942                 mode = (mode & ~FMODELS) | FNATIVE | FKIOCTL;
1943 
1944         /*
1945          * Some drivers assume that rvalp will always be non-NULL, so in
1946          * an attempt to avoid panics if the caller passed in a NULL
1947          * value, update rvalp to point to a temporary variable.
1948          */
1949         if (rvalp == NULL)
1950                 rvalp = &unused;
1951         vp = handlep->lh_vp;
1952         dev = vp->v_rdev;
1953         if (handlep->lh_type & LH_CBDEV) {
1954                 ret = cdev_ioctl(dev, cmd, arg, mode, cr, rvalp);
1955         } else if (handlep->lh_type & LH_STREAM) {
1956                 copymode = (mode & FKIOCTL) ? K_TO_K : U_TO_K;
1957 
1958                 /*
1959                  * if we get an I_PLINK from within the kernel the
1960                  * arg is a layered handle pointer instead of
1961                  * a file descriptor, so we translate this ioctl
1962                  * into a private one that can handle this.
1963                  */
1964                 if ((mode & FKIOCTL) && (cmd == I_PLINK))
1965                         cmd = _I_PLINK_LH;
1966 
1967                 ret = strioctl(vp, cmd, arg, mode, copymode, cr, rvalp);
1968         } else {
1969                 return (ENOTSUP);
1970         }
1971 
1972         return (ret);
1973 }
1974 
1975 int
1976 ldi_poll(ldi_handle_t lh, short events, int anyyet, short *reventsp,
1977     struct pollhead **phpp)
1978 {
1979         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
1980         vnode_t                 *vp;
1981         dev_t                   dev;
1982         int                     ret;
1983 
1984         if (lh == NULL)
1985                 return (EINVAL);
1986 
1987         vp = handlep->lh_vp;
1988         dev = vp->v_rdev;
1989         if (handlep->lh_type & LH_CBDEV) {
1990                 ret = cdev_poll(dev, events, anyyet, reventsp, phpp);
1991         } else if (handlep->lh_type & LH_STREAM) {
1992                 ret = strpoll(vp->v_stream, events, anyyet, reventsp, phpp);
1993         } else {
1994                 return (ENOTSUP);
1995         }
1996 
1997         return (ret);
1998 }
1999 
2000 int
2001 ldi_prop_op(ldi_handle_t lh, ddi_prop_op_t prop_op,
2002         int flags, char *name, caddr_t valuep, int *length)
2003 {
2004         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2005         dev_t                   dev;
2006         dev_info_t              *dip;
2007         int                     ret;
2008         struct snode            *csp;
2009 
2010         if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2011                 return (DDI_PROP_INVAL_ARG);
2012 
2013         if ((prop_op != PROP_LEN) && (valuep == NULL))
2014                 return (DDI_PROP_INVAL_ARG);
2015 
2016         if (length == NULL)
2017                 return (DDI_PROP_INVAL_ARG);
2018 
2019         /*
2020          * try to find the associated dip,
2021          * this places a hold on the driver
2022          */
2023         dev = handlep->lh_vp->v_rdev;
2024 
2025         csp = VTOCS(handlep->lh_vp);
2026         mutex_enter(&csp->s_lock);
2027         if ((dip = csp->s_dip) != NULL)
2028                 e_ddi_hold_devi(dip);
2029         mutex_exit(&csp->s_lock);
2030         if (dip == NULL)
2031                 dip = e_ddi_hold_devi_by_dev(dev, 0);
2032 
2033         if (dip == NULL)
2034                 return (DDI_PROP_NOT_FOUND);
2035 
2036         ret = i_ldi_prop_op(dev, dip, prop_op, flags, name, valuep, length);
2037         ddi_release_devi(dip);
2038 
2039         return (ret);
2040 }
2041 
2042 int
2043 ldi_strategy(ldi_handle_t lh, struct buf *bp)
2044 {
2045         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2046         dev_t                   dev;
2047 
2048         if ((lh == NULL) || (bp == NULL))
2049                 return (EINVAL);
2050 
2051         /* this entry point is only supported for cb devices */
2052         dev = handlep->lh_vp->v_rdev;
2053         if (!(handlep->lh_type & LH_CBDEV))
2054                 return (ENOTSUP);
2055 
2056         bp->b_edev = dev;
2057         bp->b_dev = cmpdev(dev);
2058         return (bdev_strategy(bp));
2059 }
2060 
2061 int
2062 ldi_dump(ldi_handle_t lh, caddr_t addr, daddr_t blkno, int nblk)
2063 {
2064         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2065         dev_t                   dev;
2066 
2067         if (lh == NULL)
2068                 return (EINVAL);
2069 
2070         /* this entry point is only supported for cb devices */
2071         dev = handlep->lh_vp->v_rdev;
2072         if (!(handlep->lh_type & LH_CBDEV))
2073                 return (ENOTSUP);
2074 
2075         return (bdev_dump(dev, addr, blkno, nblk));
2076 }
2077 
2078 int
2079 ldi_devmap(ldi_handle_t lh, devmap_cookie_t dhp, offset_t off,
2080     size_t len, size_t *maplen, uint_t model)
2081 {
2082         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2083         dev_t                   dev;
2084 
2085         if (lh == NULL)
2086                 return (EINVAL);
2087 
2088         /* this entry point is only supported for cb devices */
2089         dev = handlep->lh_vp->v_rdev;
2090         if (!(handlep->lh_type & LH_CBDEV))
2091                 return (ENOTSUP);
2092 
2093         return (cdev_devmap(dev, dhp, off, len, maplen, model));
2094 }
2095 
2096 int
2097 ldi_aread(ldi_handle_t lh, struct aio_req *aio_reqp, cred_t *cr)
2098 {
2099         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2100         dev_t                   dev;
2101         struct cb_ops           *cb;
2102 
2103         if (lh == NULL)
2104                 return (EINVAL);
2105 
2106         /* this entry point is only supported for cb devices */
2107         if (!(handlep->lh_type & LH_CBDEV))
2108                 return (ENOTSUP);
2109 
2110         /*
2111          * Kaio is only supported on block devices.
2112          */
2113         dev = handlep->lh_vp->v_rdev;
2114         cb = devopsp[getmajor(dev)]->devo_cb_ops;
2115         if (cb->cb_strategy == nodev || cb->cb_strategy == NULL)
2116                 return (ENOTSUP);
2117 
2118         if (cb->cb_aread == NULL)
2119                 return (ENOTSUP);
2120 
2121         return (cb->cb_aread(dev, aio_reqp, cr));
2122 }
2123 
2124 int
2125 ldi_awrite(ldi_handle_t lh, struct aio_req *aio_reqp, cred_t *cr)
2126 {
2127         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2128         struct cb_ops           *cb;
2129         dev_t                   dev;
2130 
2131         if (lh == NULL)
2132                 return (EINVAL);
2133 
2134         /* this entry point is only supported for cb devices */
2135         if (!(handlep->lh_type & LH_CBDEV))
2136                 return (ENOTSUP);
2137 
2138         /*
2139          * Kaio is only supported on block devices.
2140          */
2141         dev = handlep->lh_vp->v_rdev;
2142         cb = devopsp[getmajor(dev)]->devo_cb_ops;
2143         if (cb->cb_strategy == nodev || cb->cb_strategy == NULL)
2144                 return (ENOTSUP);
2145 
2146         if (cb->cb_awrite == NULL)
2147                 return (ENOTSUP);
2148 
2149         return (cb->cb_awrite(dev, aio_reqp, cr));
2150 }
2151 
2152 int
2153 ldi_putmsg(ldi_handle_t lh, mblk_t *smp)
2154 {
2155         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2156         int                     ret;
2157 
2158         if ((lh == NULL) || (smp == NULL))
2159                 return (EINVAL);
2160 
2161         if (!(handlep->lh_type & LH_STREAM)) {
2162                 freemsg(smp);
2163                 return (ENOTSUP);
2164         }
2165 
2166         /*
2167          * If we don't have db_credp, set it. Note that we can not be called
2168          * from interrupt context.
2169          */
2170         if (msg_getcred(smp, NULL) == NULL)
2171                 mblk_setcred(smp, CRED(), curproc->p_pid);
2172 
2173         /* Send message while honoring flow control */
2174         ret = kstrputmsg(handlep->lh_vp, smp, NULL, 0, 0,
2175             MSG_BAND | MSG_HOLDSIG | MSG_IGNERROR, 0);
2176 
2177         return (ret);
2178 }
2179 
2180 int
2181 ldi_getmsg(ldi_handle_t lh, mblk_t **rmp, timestruc_t *timeo)
2182 {
2183         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2184         clock_t                 timout; /* milliseconds */
2185         uchar_t                 pri;
2186         rval_t                  rval;
2187         int                     ret, pflag;
2188 
2189 
2190         if (lh == NULL)
2191                 return (EINVAL);
2192 
2193         if (!(handlep->lh_type & LH_STREAM))
2194                 return (ENOTSUP);
2195 
2196         /* Convert from nanoseconds to milliseconds */
2197         if (timeo != NULL) {
2198                 timout = timeo->tv_sec * 1000 + timeo->tv_nsec / 1000000;
2199                 if (timout > INT_MAX)
2200                         return (EINVAL);
2201         } else
2202                 timout = -1;
2203 
2204         /* Wait for timeout millseconds for a message */
2205         pflag = MSG_ANY;
2206         pri = 0;
2207         *rmp = NULL;
2208         ret = kstrgetmsg(handlep->lh_vp,
2209             rmp, NULL, &pri, &pflag, timout, &rval);
2210         return (ret);
2211 }
2212 
2213 int
2214 ldi_get_dev(ldi_handle_t lh, dev_t *devp)
2215 {
2216         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2217 
2218         if ((lh == NULL) || (devp == NULL))
2219                 return (EINVAL);
2220 
2221         *devp = handlep->lh_vp->v_rdev;
2222         return (0);
2223 }
2224 
2225 int
2226 ldi_get_otyp(ldi_handle_t lh, int *otyp)
2227 {
2228         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2229 
2230         if ((lh == NULL) || (otyp == NULL))
2231                 return (EINVAL);
2232 
2233         *otyp = VTYP_TO_OTYP(handlep->lh_vp->v_type);
2234         return (0);
2235 }
2236 
2237 int
2238 ldi_get_devid(ldi_handle_t lh, ddi_devid_t *devid)
2239 {
2240         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2241         int                     ret;
2242         dev_t                   dev;
2243 
2244         if ((lh == NULL) || (devid == NULL))
2245                 return (EINVAL);
2246 
2247         dev = handlep->lh_vp->v_rdev;
2248 
2249         ret = ddi_lyr_get_devid(dev, devid);
2250         if (ret != DDI_SUCCESS)
2251                 return (ENOTSUP);
2252 
2253         return (0);
2254 }
2255 
2256 int
2257 ldi_get_minor_name(ldi_handle_t lh, char **minor_name)
2258 {
2259         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2260         int                     ret, otyp;
2261         dev_t                   dev;
2262 
2263         if ((lh == NULL) || (minor_name == NULL))
2264                 return (EINVAL);
2265 
2266         dev = handlep->lh_vp->v_rdev;
2267         otyp = VTYP_TO_OTYP(handlep->lh_vp->v_type);
2268 
2269         ret = ddi_lyr_get_minor_name(dev, OTYP_TO_STYP(otyp), minor_name);
2270         if (ret != DDI_SUCCESS)
2271                 return (ENOTSUP);
2272 
2273         return (0);
2274 }
2275 
2276 int
2277 ldi_prop_lookup_int_array(ldi_handle_t lh,
2278     uint_t flags, char *name, int **data, uint_t *nelements)
2279 {
2280         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2281         dev_info_t              *dip;
2282         dev_t                   dev;
2283         int                     res;
2284         struct snode            *csp;
2285 
2286         if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2287                 return (DDI_PROP_INVAL_ARG);
2288 
2289         dev = handlep->lh_vp->v_rdev;
2290 
2291         csp = VTOCS(handlep->lh_vp);
2292         mutex_enter(&csp->s_lock);
2293         if ((dip = csp->s_dip) != NULL)
2294                 e_ddi_hold_devi(dip);
2295         mutex_exit(&csp->s_lock);
2296         if (dip == NULL)
2297                 dip = e_ddi_hold_devi_by_dev(dev, 0);
2298 
2299         if (dip == NULL) {
2300                 flags |= DDI_UNBND_DLPI2;
2301         } else if (flags & LDI_DEV_T_ANY) {
2302                 flags &= ~LDI_DEV_T_ANY;
2303                 dev = DDI_DEV_T_ANY;
2304         }
2305 
2306         if (dip != NULL) {
2307                 int *prop_val, prop_len;
2308 
2309                 res = i_ldi_prop_op_typed(dev, dip, flags, name,
2310                     (caddr_t *)&prop_val, &prop_len, sizeof (int));
2311 
2312                 /* if we got it then return it */
2313                 if (res == DDI_PROP_SUCCESS) {
2314                         *nelements = prop_len / sizeof (int);
2315                         *data = prop_val;
2316 
2317                         ddi_release_devi(dip);
2318                         return (res);
2319                 }
2320         }
2321 
2322         /* call the normal property interfaces */
2323         res = ddi_prop_lookup_int_array(dev, dip, flags,
2324             name, data, nelements);
2325 
2326         if (dip != NULL)
2327                 ddi_release_devi(dip);
2328 
2329         return (res);
2330 }
2331 
2332 int
2333 ldi_prop_lookup_int64_array(ldi_handle_t lh,
2334     uint_t flags, char *name, int64_t **data, uint_t *nelements)
2335 {
2336         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2337         dev_info_t              *dip;
2338         dev_t                   dev;
2339         int                     res;
2340         struct snode            *csp;
2341 
2342         if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2343                 return (DDI_PROP_INVAL_ARG);
2344 
2345         dev = handlep->lh_vp->v_rdev;
2346 
2347         csp = VTOCS(handlep->lh_vp);
2348         mutex_enter(&csp->s_lock);
2349         if ((dip = csp->s_dip) != NULL)
2350                 e_ddi_hold_devi(dip);
2351         mutex_exit(&csp->s_lock);
2352         if (dip == NULL)
2353                 dip = e_ddi_hold_devi_by_dev(dev, 0);
2354 
2355         if (dip == NULL) {
2356                 flags |= DDI_UNBND_DLPI2;
2357         } else if (flags & LDI_DEV_T_ANY) {
2358                 flags &= ~LDI_DEV_T_ANY;
2359                 dev = DDI_DEV_T_ANY;
2360         }
2361 
2362         if (dip != NULL) {
2363                 int64_t *prop_val;
2364                 int     prop_len;
2365 
2366                 res = i_ldi_prop_op_typed(dev, dip, flags, name,
2367                     (caddr_t *)&prop_val, &prop_len, sizeof (int64_t));
2368 
2369                 /* if we got it then return it */
2370                 if (res == DDI_PROP_SUCCESS) {
2371                         *nelements = prop_len / sizeof (int64_t);
2372                         *data = prop_val;
2373 
2374                         ddi_release_devi(dip);
2375                         return (res);
2376                 }
2377         }
2378 
2379         /* call the normal property interfaces */
2380         res = ddi_prop_lookup_int64_array(dev, dip, flags,
2381             name, data, nelements);
2382 
2383         if (dip != NULL)
2384                 ddi_release_devi(dip);
2385 
2386         return (res);
2387 }
2388 
2389 int
2390 ldi_prop_lookup_string_array(ldi_handle_t lh,
2391     uint_t flags, char *name, char ***data, uint_t *nelements)
2392 {
2393         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2394         dev_info_t              *dip;
2395         dev_t                   dev;
2396         int                     res;
2397         struct snode            *csp;
2398 
2399         if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2400                 return (DDI_PROP_INVAL_ARG);
2401 
2402         dev = handlep->lh_vp->v_rdev;
2403 
2404         csp = VTOCS(handlep->lh_vp);
2405         mutex_enter(&csp->s_lock);
2406         if ((dip = csp->s_dip) != NULL)
2407                 e_ddi_hold_devi(dip);
2408         mutex_exit(&csp->s_lock);
2409         if (dip == NULL)
2410                 dip = e_ddi_hold_devi_by_dev(dev, 0);
2411 
2412         if (dip == NULL) {
2413                 flags |= DDI_UNBND_DLPI2;
2414         } else if (flags & LDI_DEV_T_ANY) {
2415                 flags &= ~LDI_DEV_T_ANY;
2416                 dev = DDI_DEV_T_ANY;
2417         }
2418 
2419         if (dip != NULL) {
2420                 char    *prop_val;
2421                 int     prop_len;
2422 
2423                 res = i_ldi_prop_op_typed(dev, dip, flags, name,
2424                     (caddr_t *)&prop_val, &prop_len, 0);
2425 
2426                 /* if we got it then return it */
2427                 if (res == DDI_PROP_SUCCESS) {
2428                         char    **str_array;
2429                         int     nelem;
2430 
2431                         /*
2432                          * pack the returned string array into the format
2433                          * our callers expect
2434                          */
2435                         if (i_pack_string_array(prop_val, prop_len,
2436                             &str_array, &nelem) == 0) {
2437 
2438                                 *data = str_array;
2439                                 *nelements = nelem;
2440 
2441                                 ddi_prop_free(prop_val);
2442                                 ddi_release_devi(dip);
2443                                 return (res);
2444                         }
2445 
2446                         /*
2447                          * the format of the returned property must have
2448                          * been bad so throw it out
2449                          */
2450                         ddi_prop_free(prop_val);
2451                 }
2452         }
2453 
2454         /* call the normal property interfaces */
2455         res = ddi_prop_lookup_string_array(dev, dip, flags,
2456             name, data, nelements);
2457 
2458         if (dip != NULL)
2459                 ddi_release_devi(dip);
2460 
2461         return (res);
2462 }
2463 
2464 int
2465 ldi_prop_lookup_string(ldi_handle_t lh,
2466     uint_t flags, char *name, char **data)
2467 {
2468         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2469         dev_info_t              *dip;
2470         dev_t                   dev;
2471         int                     res;
2472         struct snode            *csp;
2473 
2474         if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2475                 return (DDI_PROP_INVAL_ARG);
2476 
2477         dev = handlep->lh_vp->v_rdev;
2478 
2479         csp = VTOCS(handlep->lh_vp);
2480         mutex_enter(&csp->s_lock);
2481         if ((dip = csp->s_dip) != NULL)
2482                 e_ddi_hold_devi(dip);
2483         mutex_exit(&csp->s_lock);
2484         if (dip == NULL)
2485                 dip = e_ddi_hold_devi_by_dev(dev, 0);
2486 
2487         if (dip == NULL) {
2488                 flags |= DDI_UNBND_DLPI2;
2489         } else if (flags & LDI_DEV_T_ANY) {
2490                 flags &= ~LDI_DEV_T_ANY;
2491                 dev = DDI_DEV_T_ANY;
2492         }
2493 
2494         if (dip != NULL) {
2495                 char    *prop_val;
2496                 int     prop_len;
2497 
2498                 res = i_ldi_prop_op_typed(dev, dip, flags, name,
2499                     (caddr_t *)&prop_val, &prop_len, 0);
2500 
2501                 /* if we got it then return it */
2502                 if (res == DDI_PROP_SUCCESS) {
2503                         /*
2504                          * sanity check the vaule returned.
2505                          */
2506                         if (i_check_string(prop_val, prop_len)) {
2507                                 ddi_prop_free(prop_val);
2508                         } else {
2509                                 *data = prop_val;
2510                                 ddi_release_devi(dip);
2511                                 return (res);
2512                         }
2513                 }
2514         }
2515 
2516         /* call the normal property interfaces */
2517         res = ddi_prop_lookup_string(dev, dip, flags, name, data);
2518 
2519         if (dip != NULL)
2520                 ddi_release_devi(dip);
2521 
2522 #ifdef DEBUG
2523         if (res == DDI_PROP_SUCCESS) {
2524                 /*
2525                  * keep ourselves honest
2526                  * make sure the framework returns strings in the
2527                  * same format as we're demanding from drivers.
2528                  */
2529                 struct prop_driver_data *pdd;
2530                 int                     pdd_prop_size;
2531 
2532                 pdd = ((struct prop_driver_data *)(*data)) - 1;
2533                 pdd_prop_size = pdd->pdd_size -
2534                     sizeof (struct prop_driver_data);
2535                 ASSERT(i_check_string(*data, pdd_prop_size) == 0);
2536         }
2537 #endif /* DEBUG */
2538 
2539         return (res);
2540 }
2541 
2542 int
2543 ldi_prop_lookup_byte_array(ldi_handle_t lh,
2544     uint_t flags, char *name, uchar_t **data, uint_t *nelements)
2545 {
2546         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2547         dev_info_t              *dip;
2548         dev_t                   dev;
2549         int                     res;
2550         struct snode            *csp;
2551 
2552         if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2553                 return (DDI_PROP_INVAL_ARG);
2554 
2555         dev = handlep->lh_vp->v_rdev;
2556 
2557         csp = VTOCS(handlep->lh_vp);
2558         mutex_enter(&csp->s_lock);
2559         if ((dip = csp->s_dip) != NULL)
2560                 e_ddi_hold_devi(dip);
2561         mutex_exit(&csp->s_lock);
2562         if (dip == NULL)
2563                 dip = e_ddi_hold_devi_by_dev(dev, 0);
2564 
2565         if (dip == NULL) {
2566                 flags |= DDI_UNBND_DLPI2;
2567         } else if (flags & LDI_DEV_T_ANY) {
2568                 flags &= ~LDI_DEV_T_ANY;
2569                 dev = DDI_DEV_T_ANY;
2570         }
2571 
2572         if (dip != NULL) {
2573                 uchar_t *prop_val;
2574                 int     prop_len;
2575 
2576                 res = i_ldi_prop_op_typed(dev, dip, flags, name,
2577                     (caddr_t *)&prop_val, &prop_len, sizeof (uchar_t));
2578 
2579                 /* if we got it then return it */
2580                 if (res == DDI_PROP_SUCCESS) {
2581                         *nelements = prop_len / sizeof (uchar_t);
2582                         *data = prop_val;
2583 
2584                         ddi_release_devi(dip);
2585                         return (res);
2586                 }
2587         }
2588 
2589         /* call the normal property interfaces */
2590         res = ddi_prop_lookup_byte_array(dev, dip, flags,
2591             name, data, nelements);
2592 
2593         if (dip != NULL)
2594                 ddi_release_devi(dip);
2595 
2596         return (res);
2597 }
2598 
2599 int
2600 ldi_prop_get_int(ldi_handle_t lh,
2601     uint_t flags, char *name, int defvalue)
2602 {
2603         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2604         dev_info_t              *dip;
2605         dev_t                   dev;
2606         int                     res;
2607         struct snode            *csp;
2608 
2609         if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2610                 return (defvalue);
2611 
2612         dev = handlep->lh_vp->v_rdev;
2613 
2614         csp = VTOCS(handlep->lh_vp);
2615         mutex_enter(&csp->s_lock);
2616         if ((dip = csp->s_dip) != NULL)
2617                 e_ddi_hold_devi(dip);
2618         mutex_exit(&csp->s_lock);
2619         if (dip == NULL)
2620                 dip = e_ddi_hold_devi_by_dev(dev, 0);
2621 
2622         if (dip == NULL) {
2623                 flags |= DDI_UNBND_DLPI2;
2624         } else if (flags & LDI_DEV_T_ANY) {
2625                 flags &= ~LDI_DEV_T_ANY;
2626                 dev = DDI_DEV_T_ANY;
2627         }
2628 
2629         if (dip != NULL) {
2630                 int     prop_val;
2631                 int     prop_len;
2632 
2633                 /*
2634                  * first call the drivers prop_op interface to allow it
2635                  * it to override default property values.
2636                  */
2637                 prop_len = sizeof (int);
2638                 res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
2639                     flags | DDI_PROP_DYNAMIC, name,
2640                     (caddr_t)&prop_val, &prop_len);
2641 
2642                 /* if we got it then return it */
2643                 if ((res == DDI_PROP_SUCCESS) &&
2644                     (prop_len == sizeof (int))) {
2645                         res = prop_val;
2646                         ddi_release_devi(dip);
2647                         return (res);
2648                 }
2649         }
2650 
2651         /* call the normal property interfaces */
2652         res = ddi_prop_get_int(dev, dip, flags, name, defvalue);
2653 
2654         if (dip != NULL)
2655                 ddi_release_devi(dip);
2656 
2657         return (res);
2658 }
2659 
2660 int64_t
2661 ldi_prop_get_int64(ldi_handle_t lh,
2662     uint_t flags, char *name, int64_t defvalue)
2663 {
2664         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2665         dev_info_t              *dip;
2666         dev_t                   dev;
2667         int64_t                 res;
2668         struct snode            *csp;
2669 
2670         if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2671                 return (defvalue);
2672 
2673         dev = handlep->lh_vp->v_rdev;
2674 
2675         csp = VTOCS(handlep->lh_vp);
2676         mutex_enter(&csp->s_lock);
2677         if ((dip = csp->s_dip) != NULL)
2678                 e_ddi_hold_devi(dip);
2679         mutex_exit(&csp->s_lock);
2680         if (dip == NULL)
2681                 dip = e_ddi_hold_devi_by_dev(dev, 0);
2682 
2683         if (dip == NULL) {
2684                 flags |= DDI_UNBND_DLPI2;
2685         } else if (flags & LDI_DEV_T_ANY) {
2686                 flags &= ~LDI_DEV_T_ANY;
2687                 dev = DDI_DEV_T_ANY;
2688         }
2689 
2690         if (dip != NULL) {
2691                 int64_t prop_val;
2692                 int     prop_len;
2693 
2694                 /*
2695                  * first call the drivers prop_op interface to allow it
2696                  * it to override default property values.
2697                  */
2698                 prop_len = sizeof (int64_t);
2699                 res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
2700                     flags | DDI_PROP_DYNAMIC, name,
2701                     (caddr_t)&prop_val, &prop_len);
2702 
2703                 /* if we got it then return it */
2704                 if ((res == DDI_PROP_SUCCESS) &&
2705                     (prop_len == sizeof (int64_t))) {
2706                         res = prop_val;
2707                         ddi_release_devi(dip);
2708                         return (res);
2709                 }
2710         }
2711 
2712         /* call the normal property interfaces */
2713         res = ddi_prop_get_int64(dev, dip, flags, name, defvalue);
2714 
2715         if (dip != NULL)
2716                 ddi_release_devi(dip);
2717 
2718         return (res);
2719 }
2720 
2721 int
2722 ldi_prop_exists(ldi_handle_t lh, uint_t flags, char *name)
2723 {
2724         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2725         dev_info_t              *dip;
2726         dev_t                   dev;
2727         int                     res, prop_len;
2728         struct snode            *csp;
2729 
2730         if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2731                 return (0);
2732 
2733         dev = handlep->lh_vp->v_rdev;
2734 
2735         csp = VTOCS(handlep->lh_vp);
2736         mutex_enter(&csp->s_lock);
2737         if ((dip = csp->s_dip) != NULL)
2738                 e_ddi_hold_devi(dip);
2739         mutex_exit(&csp->s_lock);
2740         if (dip == NULL)
2741                 dip = e_ddi_hold_devi_by_dev(dev, 0);
2742 
2743         /* if NULL dip, prop does NOT exist */
2744         if (dip == NULL)
2745                 return (0);
2746 
2747         if (flags & LDI_DEV_T_ANY) {
2748                 flags &= ~LDI_DEV_T_ANY;
2749                 dev = DDI_DEV_T_ANY;
2750         }
2751 
2752         /*
2753          * first call the drivers prop_op interface to allow it
2754          * it to override default property values.
2755          */
2756         res = i_ldi_prop_op(dev, dip, PROP_LEN,
2757             flags | DDI_PROP_DYNAMIC, name, NULL, &prop_len);
2758 
2759         if (res == DDI_PROP_SUCCESS) {
2760                 ddi_release_devi(dip);
2761                 return (1);
2762         }
2763 
2764         /* call the normal property interfaces */
2765         res = ddi_prop_exists(dev, dip, flags, name);
2766 
2767         ddi_release_devi(dip);
2768         return (res);
2769 }
2770 
2771 #ifdef  LDI_OBSOLETE_EVENT
2772 
2773 int
2774 ldi_get_eventcookie(ldi_handle_t lh, char *name, ddi_eventcookie_t *ecp)
2775 {
2776         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2777         dev_info_t              *dip;
2778         dev_t                   dev;
2779         int                     res;
2780         struct snode            *csp;
2781 
2782         if ((lh == NULL) || (name == NULL) ||
2783             (strlen(name) == 0) || (ecp == NULL)) {
2784                 return (DDI_FAILURE);
2785         }
2786 
2787         ASSERT(!servicing_interrupt());
2788 
2789         dev = handlep->lh_vp->v_rdev;
2790 
2791         csp = VTOCS(handlep->lh_vp);
2792         mutex_enter(&csp->s_lock);
2793         if ((dip = csp->s_dip) != NULL)
2794                 e_ddi_hold_devi(dip);
2795         mutex_exit(&csp->s_lock);
2796         if (dip == NULL)
2797                 dip = e_ddi_hold_devi_by_dev(dev, 0);
2798 
2799         if (dip == NULL)
2800                 return (DDI_FAILURE);
2801 
2802         LDI_EVENTCB((CE_NOTE, "%s: event_name=%s, "
2803             "dip=0x%p, event_cookiep=0x%p", "ldi_get_eventcookie",
2804             name, (void *)dip, (void *)ecp));
2805 
2806         res = ddi_get_eventcookie(dip, name, ecp);
2807 
2808         ddi_release_devi(dip);
2809         return (res);
2810 }
2811 
2812 int
2813 ldi_add_event_handler(ldi_handle_t lh, ddi_eventcookie_t ec,
2814     void (*handler)(ldi_handle_t, ddi_eventcookie_t, void *, void *),
2815     void *arg, ldi_callback_id_t *id)
2816 {
2817         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
2818         struct ldi_event        *lep;
2819         dev_info_t              *dip;
2820         dev_t                   dev;
2821         int                     res;
2822         struct snode            *csp;
2823 
2824         if ((lh == NULL) || (ec == NULL) || (handler == NULL) || (id == NULL))
2825                 return (DDI_FAILURE);
2826 
2827         ASSERT(!servicing_interrupt());
2828 
2829         dev = handlep->lh_vp->v_rdev;
2830 
2831         csp = VTOCS(handlep->lh_vp);
2832         mutex_enter(&csp->s_lock);
2833         if ((dip = csp->s_dip) != NULL)
2834                 e_ddi_hold_devi(dip);
2835         mutex_exit(&csp->s_lock);
2836         if (dip == NULL)
2837                 dip = e_ddi_hold_devi_by_dev(dev, 0);
2838 
2839         if (dip == NULL)
2840                 return (DDI_FAILURE);
2841 
2842         lep = kmem_zalloc(sizeof (struct ldi_event), KM_SLEEP);
2843         lep->le_lhp = handlep;
2844         lep->le_arg = arg;
2845         lep->le_handler = handler;
2846 
2847         if ((res = ddi_add_event_handler(dip, ec, i_ldi_callback,
2848             (void *)lep, &lep->le_id)) != DDI_SUCCESS) {
2849                 LDI_EVENTCB((CE_WARN, "%s: unable to add"
2850                     "event callback", "ldi_add_event_handler"));
2851                 ddi_release_devi(dip);
2852                 kmem_free(lep, sizeof (struct ldi_event));
2853                 return (res);
2854         }
2855 
2856         *id = (ldi_callback_id_t)lep;
2857 
2858         LDI_EVENTCB((CE_NOTE, "%s: dip=0x%p, event=0x%p, "
2859             "ldi_eventp=0x%p, cb_id=0x%p", "ldi_add_event_handler",
2860             (void *)dip, (void *)ec, (void *)lep, (void *)id));
2861 
2862         handle_event_add(lep);
2863         ddi_release_devi(dip);
2864         return (res);
2865 }
2866 
2867 int
2868 ldi_remove_event_handler(ldi_handle_t lh, ldi_callback_id_t id)
2869 {
2870         ldi_event_t             *lep = (ldi_event_t *)id;
2871         int                     res;
2872 
2873         if ((lh == NULL) || (id == NULL))
2874                 return (DDI_FAILURE);
2875 
2876         ASSERT(!servicing_interrupt());
2877 
2878         if ((res = ddi_remove_event_handler(lep->le_id))
2879             != DDI_SUCCESS) {
2880                 LDI_EVENTCB((CE_WARN, "%s: unable to remove "
2881                     "event callback", "ldi_remove_event_handler"));
2882                 return (res);
2883         }
2884 
2885         handle_event_remove(lep);
2886         kmem_free(lep, sizeof (struct ldi_event));
2887         return (res);
2888 }
2889 
2890 #endif
2891 
2892 /*
2893  * Here are some definitions of terms used in the following LDI events
2894  * code:
2895  *
2896  * "LDI events" AKA "native events": These are events defined by the
2897  * "new" LDI event framework. These events are serviced by the LDI event
2898  * framework itself and thus are native to it.
2899  *
2900  * "LDI contract events": These are contract events that correspond to the
2901  *  LDI events. This mapping of LDI events to contract events is defined by
2902  * the ldi_ev_cookies[] array above.
2903  *
2904  * NDI events: These are events which are serviced by the NDI event subsystem.
2905  * LDI subsystem just provides a thin wrapper around the NDI event interfaces
2906  * These events are therefore *not* native events.
2907  */
2908 
2909 static int
2910 ldi_native_event(const char *evname)
2911 {
2912         int i;
2913 
2914         LDI_EVTRC((CE_NOTE, "ldi_native_event: entered: ev=%s", evname));
2915 
2916         for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
2917                 if (strcmp(ldi_ev_cookies[i].ck_evname, evname) == 0)
2918                         return (1);
2919         }
2920 
2921         return (0);
2922 }
2923 
2924 static uint_t
2925 ldi_ev_sync_event(const char *evname)
2926 {
2927         int i;
2928 
2929         ASSERT(ldi_native_event(evname));
2930 
2931         LDI_EVTRC((CE_NOTE, "ldi_ev_sync_event: entered: %s", evname));
2932 
2933         for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
2934                 if (strcmp(ldi_ev_cookies[i].ck_evname, evname) == 0)
2935                         return (ldi_ev_cookies[i].ck_sync);
2936         }
2937 
2938         /*
2939          * This should never happen until non-contract based
2940          * LDI events are introduced. If that happens, we will
2941          * use a "special" token to indicate that there are no
2942          * contracts corresponding to this LDI event.
2943          */
2944         cmn_err(CE_PANIC, "Unknown LDI event: %s", evname);
2945 
2946         return (0);
2947 }
2948 
2949 static uint_t
2950 ldi_contract_event(const char *evname)
2951 {
2952         int i;
2953 
2954         ASSERT(ldi_native_event(evname));
2955 
2956         LDI_EVTRC((CE_NOTE, "ldi_contract_event: entered: %s", evname));
2957 
2958         for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
2959                 if (strcmp(ldi_ev_cookies[i].ck_evname, evname) == 0)
2960                         return (ldi_ev_cookies[i].ck_ctype);
2961         }
2962 
2963         /*
2964          * This should never happen until non-contract based
2965          * LDI events are introduced. If that happens, we will
2966          * use a "special" token to indicate that there are no
2967          * contracts corresponding to this LDI event.
2968          */
2969         cmn_err(CE_PANIC, "Unknown LDI event: %s", evname);
2970 
2971         return (0);
2972 }
2973 
2974 char *
2975 ldi_ev_get_type(ldi_ev_cookie_t cookie)
2976 {
2977         int i;
2978         struct ldi_ev_cookie *cookie_impl = (struct ldi_ev_cookie *)cookie;
2979 
2980         for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
2981                 if (&ldi_ev_cookies[i] == cookie_impl) {
2982                         LDI_EVTRC((CE_NOTE, "ldi_ev_get_type: LDI: %s",
2983                             ldi_ev_cookies[i].ck_evname));
2984                         return (ldi_ev_cookies[i].ck_evname);
2985                 }
2986         }
2987 
2988         /*
2989          * Not an LDI native event. Must be NDI event service.
2990          * Just return a generic string
2991          */
2992         LDI_EVTRC((CE_NOTE, "ldi_ev_get_type: is NDI"));
2993         return (NDI_EVENT_SERVICE);
2994 }
2995 
2996 static int
2997 ldi_native_cookie(ldi_ev_cookie_t cookie)
2998 {
2999         int i;
3000         struct ldi_ev_cookie *cookie_impl = (struct ldi_ev_cookie *)cookie;
3001 
3002         for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
3003                 if (&ldi_ev_cookies[i] == cookie_impl) {
3004                         LDI_EVTRC((CE_NOTE, "ldi_native_cookie: native LDI"));
3005                         return (1);
3006                 }
3007         }
3008 
3009         LDI_EVTRC((CE_NOTE, "ldi_native_cookie: is NDI"));
3010         return (0);
3011 }
3012 
3013 static ldi_ev_cookie_t
3014 ldi_get_native_cookie(const char *evname)
3015 {
3016         int i;
3017 
3018         for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
3019                 if (strcmp(ldi_ev_cookies[i].ck_evname, evname) == 0) {
3020                         LDI_EVTRC((CE_NOTE, "ldi_get_native_cookie: found"));
3021                         return ((ldi_ev_cookie_t)&ldi_ev_cookies[i]);
3022                 }
3023         }
3024 
3025         LDI_EVTRC((CE_NOTE, "ldi_get_native_cookie: NOT found"));
3026         return (NULL);
3027 }
3028 
3029 /*
3030  * ldi_ev_lock() needs to be recursive, since layered drivers may call
3031  * other LDI interfaces (such as ldi_close() from within the context of
3032  * a notify callback. Since the notify callback is called with the
3033  * ldi_ev_lock() held and ldi_close() also grabs ldi_ev_lock, the lock needs
3034  * to be recursive.
3035  */
3036 static void
3037 ldi_ev_lock(void)
3038 {
3039         LDI_EVTRC((CE_NOTE, "ldi_ev_lock: entered"));
3040 
3041         mutex_enter(&ldi_ev_callback_list.le_lock);
3042         if (ldi_ev_callback_list.le_thread == curthread) {
3043                 ASSERT(ldi_ev_callback_list.le_busy >= 1);
3044                 ldi_ev_callback_list.le_busy++;
3045         } else {
3046                 while (ldi_ev_callback_list.le_busy)
3047                         cv_wait(&ldi_ev_callback_list.le_cv,
3048                             &ldi_ev_callback_list.le_lock);
3049                 ASSERT(ldi_ev_callback_list.le_thread == NULL);
3050                 ldi_ev_callback_list.le_busy = 1;
3051                 ldi_ev_callback_list.le_thread = curthread;
3052         }
3053         mutex_exit(&ldi_ev_callback_list.le_lock);
3054 
3055         LDI_EVTRC((CE_NOTE, "ldi_ev_lock: exit"));
3056 }
3057 
3058 static void
3059 ldi_ev_unlock(void)
3060 {
3061         LDI_EVTRC((CE_NOTE, "ldi_ev_unlock: entered"));
3062         mutex_enter(&ldi_ev_callback_list.le_lock);
3063         ASSERT(ldi_ev_callback_list.le_thread == curthread);
3064         ASSERT(ldi_ev_callback_list.le_busy >= 1);
3065 
3066         ldi_ev_callback_list.le_busy--;
3067         if (ldi_ev_callback_list.le_busy == 0) {
3068                 ldi_ev_callback_list.le_thread = NULL;
3069                 cv_signal(&ldi_ev_callback_list.le_cv);
3070         }
3071         mutex_exit(&ldi_ev_callback_list.le_lock);
3072         LDI_EVTRC((CE_NOTE, "ldi_ev_unlock: exit"));
3073 }
3074 
3075 int
3076 ldi_ev_get_cookie(ldi_handle_t lh, char *evname, ldi_ev_cookie_t *cookiep)
3077 {
3078         struct ldi_handle       *handlep = (struct ldi_handle *)lh;
3079         dev_info_t              *dip;
3080         dev_t                   dev;
3081         int                     res;
3082         struct snode            *csp;
3083         ddi_eventcookie_t       ddi_cookie;
3084         ldi_ev_cookie_t         tcookie;
3085 
3086         LDI_EVDBG((CE_NOTE, "ldi_ev_get_cookie: entered: evname=%s",
3087             evname ? evname : "<NULL>"));
3088 
3089         if (lh == NULL || evname == NULL ||
3090             strlen(evname) == 0 || cookiep == NULL) {
3091                 LDI_EVDBG((CE_NOTE, "ldi_ev_get_cookie: invalid args"));
3092                 return (LDI_EV_FAILURE);
3093         }
3094 
3095         *cookiep = NULL;
3096 
3097         /*
3098          * First check if it is a LDI native event
3099          */
3100         tcookie = ldi_get_native_cookie(evname);
3101         if (tcookie) {
3102                 LDI_EVDBG((CE_NOTE, "ldi_ev_get_cookie: got native cookie"));
3103                 *cookiep = tcookie;
3104                 return (LDI_EV_SUCCESS);
3105         }
3106 
3107         /*
3108          * Not a LDI native event. Try NDI event services
3109          */
3110 
3111         dev = handlep->lh_vp->v_rdev;
3112 
3113         csp = VTOCS(handlep->lh_vp);
3114         mutex_enter(&csp->s_lock);
3115         if ((dip = csp->s_dip) != NULL)
3116                 e_ddi_hold_devi(dip);
3117         mutex_exit(&csp->s_lock);
3118         if (dip == NULL)
3119                 dip = e_ddi_hold_devi_by_dev(dev, 0);
3120 
3121         if (dip == NULL) {
3122                 cmn_err(CE_WARN, "ldi_ev_get_cookie: No devinfo node for LDI "
3123                     "handle: %p", (void *)handlep);
3124                 return (LDI_EV_FAILURE);
3125         }
3126 
3127         LDI_EVDBG((CE_NOTE, "Calling ddi_get_eventcookie: dip=%p, ev=%s",
3128             (void *)dip, evname));
3129 
3130         res = ddi_get_eventcookie(dip, evname, &ddi_cookie);
3131 
3132         ddi_release_devi(dip);
3133 
3134         if (res == DDI_SUCCESS) {
3135                 LDI_EVDBG((CE_NOTE, "ldi_ev_get_cookie: NDI cookie found"));
3136                 *cookiep = (ldi_ev_cookie_t)ddi_cookie;
3137                 return (LDI_EV_SUCCESS);
3138         } else {
3139                 LDI_EVDBG((CE_WARN, "ldi_ev_get_cookie: NDI cookie: failed"));
3140                 return (LDI_EV_FAILURE);
3141         }
3142 }
3143 
3144 /*ARGSUSED*/
3145 static void
3146 i_ldi_ev_callback(dev_info_t *dip, ddi_eventcookie_t event_cookie,
3147     void *arg, void *ev_data)
3148 {
3149         ldi_ev_callback_impl_t *lecp = (ldi_ev_callback_impl_t *)arg;
3150 
3151         ASSERT(lecp != NULL);
3152         ASSERT(!ldi_native_cookie(lecp->lec_cookie));
3153         ASSERT(lecp->lec_lhp);
3154         ASSERT(lecp->lec_notify == NULL);
3155         ASSERT(lecp->lec_finalize);
3156 
3157         LDI_EVDBG((CE_NOTE, "i_ldi_ev_callback: ldh=%p, cookie=%p, arg=%p, "
3158             "ev_data=%p", (void *)lecp->lec_lhp, (void *)event_cookie,
3159             (void *)lecp->lec_arg, (void *)ev_data));
3160 
3161         lecp->lec_finalize(lecp->lec_lhp, (ldi_ev_cookie_t)event_cookie,
3162             lecp->lec_arg, ev_data);
3163 }
3164 
3165 int
3166 ldi_ev_register_callbacks(ldi_handle_t lh, ldi_ev_cookie_t cookie,
3167     ldi_ev_callback_t *callb, void *arg, ldi_callback_id_t *id)
3168 {
3169         struct ldi_handle       *lhp = (struct ldi_handle *)lh;
3170         ldi_ev_callback_impl_t  *lecp;
3171         dev_t                   dev;
3172         struct snode            *csp;
3173         dev_info_t              *dip;
3174         int                     ddi_event;
3175 
3176         ASSERT(!servicing_interrupt());
3177 
3178         if (lh == NULL || cookie == NULL || callb == NULL || id == NULL) {
3179                 LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks: Invalid args"));
3180                 return (LDI_EV_FAILURE);
3181         }
3182 
3183         if (callb->cb_vers != LDI_EV_CB_VERS) {
3184                 LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks: Invalid vers"));
3185                 return (LDI_EV_FAILURE);
3186         }
3187 
3188         if (callb->cb_notify == NULL && callb->cb_finalize == NULL) {
3189                 LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks: NULL callb"));
3190                 return (LDI_EV_FAILURE);
3191         }
3192 
3193         *id = 0;
3194 
3195         dev = lhp->lh_vp->v_rdev;
3196         csp = VTOCS(lhp->lh_vp);
3197         mutex_enter(&csp->s_lock);
3198         if ((dip = csp->s_dip) != NULL)
3199                 e_ddi_hold_devi(dip);
3200         mutex_exit(&csp->s_lock);
3201         if (dip == NULL)
3202                 dip = e_ddi_hold_devi_by_dev(dev, 0);
3203 
3204         if (dip == NULL) {
3205                 cmn_err(CE_WARN, "ldi_ev_register: No devinfo node for "
3206                     "LDI handle: %p", (void *)lhp);
3207                 return (LDI_EV_FAILURE);
3208         }
3209 
3210         lecp = kmem_zalloc(sizeof (ldi_ev_callback_impl_t), KM_SLEEP);
3211 
3212         ddi_event = 0;
3213         if (!ldi_native_cookie(cookie)) {
3214                 if (callb->cb_notify || callb->cb_finalize == NULL) {
3215                         /*
3216                          * NDI event services only accept finalize
3217                          */
3218                         cmn_err(CE_WARN, "%s: module: %s: NDI event cookie. "
3219                             "Only finalize"
3220                             " callback supported with this cookie",
3221                             "ldi_ev_register_callbacks",
3222                             lhp->lh_ident->li_modname);
3223                         kmem_free(lecp, sizeof (ldi_ev_callback_impl_t));
3224                         ddi_release_devi(dip);
3225                         return (LDI_EV_FAILURE);
3226                 }
3227 
3228                 if (ddi_add_event_handler(dip, (ddi_eventcookie_t)cookie,
3229                     i_ldi_ev_callback, (void *)lecp,
3230                     (ddi_callback_id_t *)&lecp->lec_id)
3231                     != DDI_SUCCESS) {
3232                         kmem_free(lecp, sizeof (ldi_ev_callback_impl_t));
3233                         ddi_release_devi(dip);
3234                         LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks(): "
3235                             "ddi_add_event_handler failed"));
3236                         return (LDI_EV_FAILURE);
3237                 }
3238                 ddi_event = 1;
3239                 LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks(): "
3240                     "ddi_add_event_handler success"));
3241         }
3242 
3243 
3244 
3245         ldi_ev_lock();
3246 
3247         /*
3248          * Add the notify/finalize callback to the LDI's list of callbacks.
3249          */
3250         lecp->lec_lhp = lhp;
3251         lecp->lec_dev = lhp->lh_vp->v_rdev;
3252         lecp->lec_spec = VTYP_TO_STYP(lhp->lh_vp->v_type);
3253         lecp->lec_notify = callb->cb_notify;
3254         lecp->lec_finalize = callb->cb_finalize;
3255         lecp->lec_arg = arg;
3256         lecp->lec_cookie = cookie;
3257         if (!ddi_event)
3258                 lecp->lec_id = (void *)(uintptr_t)(++ldi_ev_id_pool);
3259         else
3260                 ASSERT(lecp->lec_id);
3261         lecp->lec_dip = dip;
3262         list_insert_tail(&ldi_ev_callback_list.le_head, lecp);
3263 
3264         *id = (ldi_callback_id_t)lecp->lec_id;
3265 
3266         ldi_ev_unlock();
3267 
3268         ddi_release_devi(dip);
3269 
3270         LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks: registered "
3271             "notify/finalize"));
3272 
3273         return (LDI_EV_SUCCESS);
3274 }
3275 
3276 static int
3277 ldi_ev_device_match(ldi_ev_callback_impl_t *lecp, dev_info_t *dip,
3278     dev_t dev, int spec_type)
3279 {
3280         ASSERT(lecp);
3281         ASSERT(dip);
3282         ASSERT(dev != DDI_DEV_T_NONE);
3283         ASSERT(dev != NODEV);
3284         ASSERT((dev == DDI_DEV_T_ANY && spec_type == 0) ||
3285             (spec_type == S_IFCHR || spec_type == S_IFBLK));
3286         ASSERT(lecp->lec_dip);
3287         ASSERT(lecp->lec_spec == S_IFCHR || lecp->lec_spec == S_IFBLK);
3288         ASSERT(lecp->lec_dev != DDI_DEV_T_ANY);
3289         ASSERT(lecp->lec_dev != DDI_DEV_T_NONE);
3290         ASSERT(lecp->lec_dev != NODEV);
3291 
3292         if (dip != lecp->lec_dip)
3293                 return (0);
3294 
3295         if (dev != DDI_DEV_T_ANY) {
3296                 if (dev != lecp->lec_dev || spec_type != lecp->lec_spec)
3297                         return (0);
3298         }
3299 
3300         LDI_EVTRC((CE_NOTE, "ldi_ev_device_match: MATCH dip=%p", (void *)dip));
3301 
3302         return (1);
3303 }
3304 
3305 /*
3306  * LDI framework function to post a "notify" event to all layered drivers
3307  * that have registered for that event
3308  *
3309  * Returns:
3310  *              LDI_EV_SUCCESS - registered callbacks allow event
3311  *              LDI_EV_FAILURE - registered callbacks block event
3312  *              LDI_EV_NONE    - No matching LDI callbacks
3313  *
3314  * This function is *not* to be called by layered drivers. It is for I/O
3315  * framework code in Solaris, such as the I/O retire code and DR code
3316  * to call while servicing a device event such as offline or degraded.
3317  */
3318 int
3319 ldi_invoke_notify(dev_info_t *dip, dev_t dev, int spec_type, char *event,
3320     void *ev_data)
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                 }
3367 
3368                 /*
3369                  * Check if matching event
3370                  */
3371                 lec_event = ldi_ev_get_type(lecp->lec_cookie);
3372                 if (strcmp(event, lec_event) != 0) {
3373                         LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): Not matching"
3374                             " event {%s,%s}. skipping", event, lec_event));
3375                         continue;
3376                 }
3377 
3378                 lecp->lec_lhp->lh_flags |= LH_FLAGS_NOTIFY;
3379                 if (lecp->lec_notify(lecp->lec_lhp, lecp->lec_cookie,
3380                     lecp->lec_arg, ev_data) != LDI_EV_SUCCESS) {
3381                         ret = LDI_EV_FAILURE;
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.
3425                  */
3426 
3427                 /* Check if matching event */
3428                 lec_event = ldi_ev_get_type(lecp->lec_cookie);
3429                 if (strcmp(event, lec_event) != 0) {
3430                         LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): not matching "
3431                             "event: %s,%s, skipping", event, lec_event));
3432                         continue;
3433                 }
3434 
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,
3477     ldi_ev_cookie_t cookie, void *ev_data)
3478 {
3479         char            *evname = ldi_ev_get_type(cookie);
3480         uint_t          ct_evtype;
3481         dev_t           dev;
3482         major_t         major;
3483         int             retc;
3484         int             retl;
3485 
3486         ASSERT(spec_type == S_IFBLK || spec_type == S_IFCHR);
3487         ASSERT(dip);
3488         ASSERT(ldi_native_cookie(cookie));
3489 
3490         LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): entered: event=%s, dip=%p",
3491             evname, (void *)dip));
3492 
3493         if (!ldi_ev_sync_event(evname)) {
3494                 cmn_err(CE_PANIC, "ldi_ev_notify(): %s not a "
3495                     "negotiatable event", evname);
3496                 return (LDI_EV_SUCCESS);
3497         }
3498 
3499         major = ddi_driver_major(dip);
3500         if (major == DDI_MAJOR_T_NONE) {
3501                 char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
3502                 (void) ddi_pathname(dip, path);
3503                 cmn_err(CE_WARN, "ldi_ev_notify: cannot derive major number "
3504                     "for device %s", path);
3505                 kmem_free(path, MAXPATHLEN);
3506                 return (LDI_EV_FAILURE);
3507         }
3508         dev = makedevice(major, minor);
3509 
3510         /*
3511          * Generate negotiation contract events on contracts (if any) associated
3512          * with this minor.
3513          */
3514         LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): calling contract nego."));
3515         ct_evtype = ldi_contract_event(evname);
3516         retc = contract_device_negotiate(dip, dev, spec_type, ct_evtype);
3517         if (retc == CT_NACK) {
3518                 LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): contract neg. NACK"));
3519                 return (LDI_EV_FAILURE);
3520         }
3521 
3522         LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): LDI invoke notify"));
3523         retl = ldi_invoke_notify(dip, dev, spec_type, evname, ev_data);
3524         if (retl == LDI_EV_FAILURE) {
3525                 LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): ldi_invoke_notify "
3526                     "returned FAILURE. Calling contract negend"));
3527                 contract_device_negend(dip, dev, spec_type, CT_EV_FAILURE);
3528                 return (LDI_EV_FAILURE);
3529         }
3530 
3531         /*
3532          * The very fact that we are here indicates that there is a
3533          * LDI callback (and hence a constraint) for the retire of the
3534          * HW device. So we just return success even if there are no
3535          * contracts or LDI callbacks against the minors layered on top
3536          * of the HW minors
3537          */
3538         LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): returning SUCCESS"));
3539         return (LDI_EV_SUCCESS);
3540 }
3541 
3542 /*
3543  * LDI framework function to invoke "finalize" callbacks for all layered
3544  * drivers that have registered callbacks for that event.
3545  *
3546  * This function is *not* to be called by layered drivers. It is for I/O
3547  * framework code in Solaris, such as the I/O retire code and DR code
3548  * to call while servicing a device event such as offline or degraded.
3549  */
3550 void
3551 ldi_invoke_finalize(dev_info_t *dip, dev_t dev, int spec_type, char *event,
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                 /*
3597                  * Check if matching event
3598                  */
3599                 lec_event = ldi_ev_get_type(lecp->lec_cookie);
3600                 if (strcmp(event, lec_event) != 0) {
3601                         LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): Not "
3602                             "matching event {%s,%s}. Skipping",
3603                             event, lec_event));
3604                         continue;
3605                 }
3606 
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 {
3648         dev_t dev;
3649         major_t major;
3650         char *evname;
3651         int ct_result = (ldi_result == LDI_EV_SUCCESS) ?
3652             CT_EV_SUCCESS : CT_EV_FAILURE;
3653         uint_t ct_evtype;
3654 
3655         ASSERT(dip);
3656         ASSERT(spec_type == S_IFBLK || spec_type == S_IFCHR);
3657         ASSERT(ldi_result == LDI_EV_SUCCESS || ldi_result == LDI_EV_FAILURE);
3658         ASSERT(ldi_native_cookie(cookie));
3659 
3660         LDI_EVDBG((CE_NOTE, "ldi_ev_finalize: entered: dip=%p", (void *)dip));
3661 
3662         major = ddi_driver_major(dip);
3663         if (major == DDI_MAJOR_T_NONE) {
3664                 char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
3665                 (void) ddi_pathname(dip, path);
3666                 cmn_err(CE_WARN, "ldi_ev_finalize: cannot derive major number "
3667                     "for device %s", path);
3668                 kmem_free(path, MAXPATHLEN);
3669                 return;
3670         }
3671         dev = makedevice(major, minor);
3672 
3673         evname = ldi_ev_get_type(cookie);
3674 
3675         LDI_EVDBG((CE_NOTE, "ldi_ev_finalize: calling contracts"));
3676         ct_evtype = ldi_contract_event(evname);
3677         contract_device_finalize(dip, dev, spec_type, ct_evtype, ct_result);
3678 
3679         LDI_EVDBG((CE_NOTE, "ldi_ev_finalize: calling ldi_invoke_finalize"));
3680         ldi_invoke_finalize(dip, dev, spec_type, evname, ldi_result, ev_data);
3681 }
3682 
3683 int
3684 ldi_ev_remove_callbacks(ldi_callback_id_t id)
3685 {
3686         ldi_ev_callback_impl_t  *lecp;
3687         ldi_ev_callback_impl_t  *next;
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);
3745                         ldi_ev_unlock();
3746                         return (LDI_EV_FAILURE);
3747                 }
3748                 LDI_EVDBG((CE_NOTE, "ldi_ev_remove_callbacks: NDI event "
3749                     "service removal succeeded"));
3750         } else {
3751                 LDI_EVDBG((CE_NOTE, "ldi_ev_remove_callbacks: removed "
3752                     "LDI native callbacks"));
3753         }
3754         kmem_free(found, sizeof (ldi_ev_callback_impl_t));
3755 
3756         return (LDI_EV_SUCCESS);
3757 }