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) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  24  */
  25 
  26 #include <sys/note.h>
  27 #include <sys/t_lock.h>
  28 #include <sys/cmn_err.h>
  29 #include <sys/instance.h>
  30 #include <sys/conf.h>
  31 #include <sys/stat.h>
  32 #include <sys/ddi.h>
  33 #include <sys/hwconf.h>
  34 #include <sys/sunddi.h>
  35 #include <sys/sunndi.h>
  36 #include <sys/sunmdi.h>
  37 #include <sys/ddi_impldefs.h>
  38 #include <sys/ndi_impldefs.h>
  39 #include <sys/kobj.h>
  40 #include <sys/devcache.h>
  41 #include <sys/devid_cache.h>
  42 #include <sys/sysmacros.h>
  43 
  44 /*
  45  * Discovery refers to the heroic effort made to discover a device which
  46  * cannot be accessed at the physical path where it once resided.  Discovery
  47  * involves walking the entire device tree attaching all possible disk
  48  * instances, to search for the device referenced by a devid.  Obviously,
  49  * full device discovery is something to be avoided where possible.
  50  * Note that simply invoking devfsadm(1M) is equivalent to running full
  51  * discovery at the devid cache level.
  52  *
  53  * Reasons why a disk may not be accessible:
  54  *      disk powered off
  55  *      disk removed or cable disconnected
  56  *      disk or adapter broken
  57  *
  58  * Note that discovery is not needed and cannot succeed in any of these
  59  * cases.
  60  *
  61  * When discovery may succeed:
  62  *      Discovery will result in success when a device has been moved
  63  *      to a different address.  Note that it's recommended that
  64  *      devfsadm(1M) be invoked (no arguments required) whenever a system's
  65  *      h/w configuration has been updated.  Alternatively, a
  66  *      reconfiguration boot can be used to accomplish the same result.
  67  *
  68  * Note that discovery is not necessary to be able to correct an access
  69  * failure for a device which was powered off.  Assuming the cache has an
  70  * entry for such a device, simply powering it on should permit the system
  71  * to access it.  If problems persist after powering it on, invoke
  72  * devfsadm(1M).
  73  *
  74  * Discovery prior to mounting root is only of interest when booting
  75  * from a filesystem which accesses devices by device id, which of
  76  * not all do.
  77  *
  78  * Tunables
  79  *
  80  * devid_discovery_boot (default 1)
  81  *      Number of times discovery will be attempted prior to mounting root.
  82  *      Must be done at least once to recover from corrupted or missing
  83  *      devid cache backing store.  Probably there's no reason to ever
  84  *      set this to greater than one as a missing device will remain
  85  *      unavailable no matter how often the system searches for it.
  86  *
  87  * devid_discovery_postboot (default 1)
  88  *      Number of times discovery will be attempted after mounting root.
  89  *      This must be performed at least once to discover any devices
  90  *      needed after root is mounted which may have been powered
  91  *      off and moved before booting.
  92  *      Setting this to a larger positive number will introduce
  93  *      some inconsistency in system operation.  Searching for a device
  94  *      will take an indeterminate amount of time, sometimes slower,
  95  *      sometimes faster.  In addition, the system will sometimes
  96  *      discover a newly powered on device, sometimes it won't.
  97  *      Use of this option is not therefore recommended.
  98  *
  99  * devid_discovery_postboot_always (default 0)
 100  *      Set to 1, the system will always attempt full discovery.
 101  *
 102  * devid_discovery_secs (default 0)
 103  *      Set to a positive value, the system will attempt full discovery
 104  *      but with a minimum delay between attempts.  A device search
 105  *      within the period of time specified will result in failure.
 106  *
 107  * devid_cache_read_disable (default 0)
 108  *      Set to 1 to disable reading /etc/devices/devid_cache.
 109  *      Devid cache will continue to operate normally but
 110  *      at least one discovery attempt will be required.
 111  *
 112  * devid_cache_write_disable (default 0)
 113  *      Set to 1 to disable updates to /etc/devices/devid_cache.
 114  *      Any updates to the devid cache will not be preserved across a reboot.
 115  *
 116  * devid_report_error (default 0)
 117  *      Set to 1 to enable some error messages related to devid
 118  *      cache failures.
 119  *
 120  * The devid is packed in the cache file as a byte array.  For
 121  * portability, this could be done in the encoded string format.
 122  */
 123 
 124 
 125 int devid_discovery_boot = 1;
 126 int devid_discovery_postboot = 1;
 127 int devid_discovery_postboot_always = 0;
 128 int devid_discovery_secs = 0;
 129 
 130 int devid_cache_read_disable = 0;
 131 int devid_cache_write_disable = 0;
 132 
 133 int devid_report_error = 0;
 134 
 135 
 136 /*
 137  * State to manage discovery of devices providing a devid
 138  */
 139 static int              devid_discovery_busy = 0;
 140 static kmutex_t         devid_discovery_mutex;
 141 static kcondvar_t       devid_discovery_cv;
 142 static clock_t          devid_last_discovery = 0;
 143 
 144 
 145 #ifdef  DEBUG
 146 int nvp_devid_debug = 0;
 147 int devid_debug = 0;
 148 int devid_log_registers = 0;
 149 int devid_log_finds = 0;
 150 int devid_log_lookups = 0;
 151 int devid_log_discovery = 0;
 152 int devid_log_matches = 0;
 153 int devid_log_paths = 0;
 154 int devid_log_failures = 0;
 155 int devid_log_hold = 0;
 156 int devid_log_unregisters = 0;
 157 int devid_log_removes = 0;
 158 int devid_register_debug = 0;
 159 int devid_log_stale = 0;
 160 int devid_log_detaches = 0;
 161 #endif  /* DEBUG */
 162 
 163 /*
 164  * devid cache file registration for cache reads and updates
 165  */
 166 static nvf_ops_t devid_cache_ops = {
 167         "/etc/devices/devid_cache",             /* path to cache */
 168         devid_cache_unpack_nvlist,              /* read: nvlist to nvp */
 169         devid_cache_pack_list,                  /* write: nvp to nvlist */
 170         devid_list_free,                        /* free data list */
 171         NULL                                    /* write complete callback */
 172 };
 173 
 174 /*
 175  * handle to registered devid cache handlers
 176  */
 177 nvf_handle_t    dcfd_handle;
 178 
 179 
 180 /*
 181  * Initialize devid cache file management
 182  */
 183 void
 184 devid_cache_init(void)
 185 {
 186         dcfd_handle = nvf_register_file(&devid_cache_ops);
 187         ASSERT(dcfd_handle);
 188 
 189         list_create(nvf_list(dcfd_handle), sizeof (nvp_devid_t),
 190             offsetof(nvp_devid_t, nvp_link));
 191 
 192         mutex_init(&devid_discovery_mutex, NULL, MUTEX_DEFAULT, NULL);
 193         cv_init(&devid_discovery_cv, NULL, CV_DRIVER, NULL);
 194 }
 195 
 196 /*
 197  * Read and initialize the devid cache from the persistent store
 198  */
 199 void
 200 devid_cache_read(void)
 201 {
 202         if (!devid_cache_read_disable) {
 203                 rw_enter(nvf_lock(dcfd_handle), RW_WRITER);
 204                 ASSERT(list_head(nvf_list(dcfd_handle)) == NULL);
 205                 (void) nvf_read_file(dcfd_handle);
 206                 rw_exit(nvf_lock(dcfd_handle));
 207         }
 208 }
 209 
 210 static void
 211 devid_nvp_free(nvp_devid_t *dp)
 212 {
 213         if (dp->nvp_devpath)
 214                 kmem_free(dp->nvp_devpath, strlen(dp->nvp_devpath)+1);
 215         if (dp->nvp_devid)
 216                 kmem_free(dp->nvp_devid, ddi_devid_sizeof(dp->nvp_devid));
 217 
 218         kmem_free(dp, sizeof (nvp_devid_t));
 219 }
 220 
 221 static void
 222 devid_list_free(nvf_handle_t fd)
 223 {
 224         list_t          *listp;
 225         nvp_devid_t     *np;
 226 
 227         ASSERT(RW_WRITE_HELD(nvf_lock(dcfd_handle)));
 228 
 229         listp = nvf_list(fd);
 230         while (np = list_head(listp)) {
 231                 list_remove(listp, np);
 232                 devid_nvp_free(np);
 233         }
 234 }
 235 
 236 /*
 237  * Free an nvp element in a list
 238  */
 239 static void
 240 devid_nvp_unlink_and_free(nvf_handle_t fd, nvp_devid_t *np)
 241 {
 242         list_remove(nvf_list(fd), np);
 243         devid_nvp_free(np);
 244 }
 245 
 246 /*
 247  * Unpack a device path/nvlist pair to the list of devid cache elements.
 248  * Used to parse the nvlist format when reading
 249  * /etc/devices/devid_cache
 250  */
 251 static int
 252 devid_cache_unpack_nvlist(nvf_handle_t fd, nvlist_t *nvl, char *name)
 253 {
 254         nvp_devid_t *np;
 255         ddi_devid_t devidp;
 256         int rval;
 257         uint_t n;
 258 
 259         NVP_DEVID_DEBUG_PATH((name));
 260         ASSERT(RW_WRITE_HELD(nvf_lock(dcfd_handle)));
 261 
 262         /*
 263          * check path for a devid
 264          */
 265         rval = nvlist_lookup_byte_array(nvl,
 266             DP_DEVID_ID, (uchar_t **)&devidp, &n);
 267         if (rval == 0) {
 268                 if (ddi_devid_valid(devidp) == DDI_SUCCESS) {
 269                         ASSERT(n == ddi_devid_sizeof(devidp));
 270                         np = kmem_zalloc(sizeof (nvp_devid_t), KM_SLEEP);
 271                         np->nvp_devpath = i_ddi_strdup(name, KM_SLEEP);
 272                         np->nvp_devid = kmem_alloc(n, KM_SLEEP);
 273                         (void) bcopy(devidp, np->nvp_devid, n);
 274                         list_insert_tail(nvf_list(fd), np);
 275                         NVP_DEVID_DEBUG_DEVID((np->nvp_devid));
 276                 } else {
 277                         DEVIDERR((CE_CONT,
 278                             "%s: invalid devid\n", name));
 279                 }
 280         } else {
 281                 DEVIDERR((CE_CONT,
 282                     "%s: devid not available\n", name));
 283         }
 284 
 285         return (0);
 286 }
 287 
 288 /*
 289  * Pack the list of devid cache elements into a single nvlist
 290  * Used when writing the nvlist file.
 291  */
 292 static int
 293 devid_cache_pack_list(nvf_handle_t fd, nvlist_t **ret_nvl)
 294 {
 295         nvlist_t        *nvl, *sub_nvl;
 296         nvp_devid_t     *np;
 297         int             rval;
 298         list_t          *listp;
 299 
 300         ASSERT(RW_WRITE_HELD(nvf_lock(dcfd_handle)));
 301 
 302         rval = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
 303         if (rval != 0) {
 304                 nvf_error("%s: nvlist alloc error %d\n",
 305                     nvf_cache_name(fd), rval);
 306                 return (DDI_FAILURE);
 307         }
 308 
 309         listp = nvf_list(fd);
 310         for (np = list_head(listp); np; np = list_next(listp, np)) {
 311                 if (np->nvp_devid == NULL)
 312                         continue;
 313                 NVP_DEVID_DEBUG_PATH(np->nvp_devpath);
 314                 rval = nvlist_alloc(&sub_nvl, NV_UNIQUE_NAME, KM_SLEEP);
 315                 if (rval != 0) {
 316                         nvf_error("%s: nvlist alloc error %d\n",
 317                             nvf_cache_name(fd), rval);
 318                         sub_nvl = NULL;
 319                         goto err;
 320                 }
 321 
 322                 rval = nvlist_add_byte_array(sub_nvl, DP_DEVID_ID,
 323                     (uchar_t *)np->nvp_devid,
 324                     ddi_devid_sizeof(np->nvp_devid));
 325                 if (rval == 0) {
 326                         NVP_DEVID_DEBUG_DEVID(np->nvp_devid);
 327                 } else {
 328                         nvf_error(
 329                             "%s: nvlist add error %d (devid)\n",
 330                             nvf_cache_name(fd), rval);
 331                         goto err;
 332                 }
 333 
 334                 rval = nvlist_add_nvlist(nvl, np->nvp_devpath, sub_nvl);
 335                 if (rval != 0) {
 336                         nvf_error("%s: nvlist add error %d (sublist)\n",
 337                             nvf_cache_name(fd), rval);
 338                         goto err;
 339                 }
 340                 nvlist_free(sub_nvl);
 341         }
 342 
 343         *ret_nvl = nvl;
 344         return (DDI_SUCCESS);
 345 
 346 err:
 347         nvlist_free(sub_nvl);
 348         nvlist_free(nvl);
 349         *ret_nvl = NULL;
 350         return (DDI_FAILURE);
 351 }
 352 
 353 static int
 354 e_devid_do_discovery(void)
 355 {
 356         ASSERT(mutex_owned(&devid_discovery_mutex));
 357 
 358         if (i_ddi_io_initialized() == 0) {
 359                 if (devid_discovery_boot > 0) {
 360                         devid_discovery_boot--;
 361                         return (1);
 362                 }
 363         } else {
 364                 if (devid_discovery_postboot_always > 0)
 365                         return (1);
 366                 if (devid_discovery_postboot > 0) {
 367                         devid_discovery_postboot--;
 368                         return (1);
 369                 }
 370                 if (devid_discovery_secs > 0) {
 371                         if ((ddi_get_lbolt() - devid_last_discovery) >
 372                             drv_usectohz(devid_discovery_secs * MICROSEC)) {
 373                                 return (1);
 374                         }
 375                 }
 376         }
 377 
 378         DEVID_LOG_DISC((CE_CONT, "devid_discovery: no discovery\n"));
 379         return (0);
 380 }
 381 
 382 static void
 383 e_ddi_devid_hold_by_major(major_t major)
 384 {
 385         DEVID_LOG_DISC((CE_CONT,
 386             "devid_discovery: ddi_hold_installed_driver %d\n", major));
 387 
 388         if (ddi_hold_installed_driver(major) == NULL)
 389                 return;
 390 
 391         ddi_rele_driver(major);
 392 }
 393 
 394 /* legacy support - see below */
 395 static char *e_ddi_devid_hold_driver_list[] = { "sd", "ssd" };
 396 
 397 #define N_DRIVERS_TO_HOLD       \
 398         (sizeof (e_ddi_devid_hold_driver_list) / sizeof (char *))
 399 
 400 static void
 401 e_ddi_devid_hold_installed_driver(ddi_devid_t devid)
 402 {
 403         impl_devid_t    *id = (impl_devid_t *)devid;
 404         major_t         major, hint_major;
 405         char            hint[DEVID_HINT_SIZE + 1];
 406         struct devnames *dnp;
 407         char            **drvp;
 408         int             i;
 409 
 410         /* Count non-null bytes */
 411         for (i = 0; i < DEVID_HINT_SIZE; i++)
 412                 if (id->did_driver[i] == '\0')
 413                         break;
 414 
 415         /* Make a copy of the driver hint */
 416         bcopy(id->did_driver, hint, i);
 417         hint[i] = '\0';
 418 
 419         /* search for the devid using the hint driver */
 420         hint_major = ddi_name_to_major(hint);
 421         if (hint_major != DDI_MAJOR_T_NONE) {
 422                 e_ddi_devid_hold_by_major(hint_major);
 423         }
 424 
 425         /*
 426          * search for the devid with each driver declaring
 427          * itself as a devid registrant.
 428          */
 429         for (major = 0; major < devcnt; major++) {
 430                 if (major == hint_major)
 431                         continue;
 432                 dnp = &devnamesp[major];
 433                 if (dnp->dn_flags & DN_DEVID_REGISTRANT) {
 434                         e_ddi_devid_hold_by_major(major);
 435                 }
 436         }
 437 
 438         /*
 439          * Legacy support: may be removed once an upgrade mechanism
 440          * for driver conf files is available.
 441          */
 442         drvp = e_ddi_devid_hold_driver_list;
 443         for (i = 0; i < N_DRIVERS_TO_HOLD; i++, drvp++) {
 444                 major = ddi_name_to_major(*drvp);
 445                 if (major != DDI_MAJOR_T_NONE && major != hint_major) {
 446                         e_ddi_devid_hold_by_major(major);
 447                 }
 448         }
 449 }
 450 
 451 /*
 452  * Return success if discovery was attempted, to indicate
 453  * that the desired device may now be available.
 454  */
 455 int
 456 e_ddi_devid_discovery(ddi_devid_t devid)
 457 {
 458         int flags;
 459         int rval = DDI_SUCCESS;
 460 
 461         mutex_enter(&devid_discovery_mutex);
 462 
 463         if (devid_discovery_busy) {
 464                 DEVID_LOG_DISC((CE_CONT, "devid_discovery: busy\n"));
 465                 while (devid_discovery_busy) {
 466                         cv_wait(&devid_discovery_cv, &devid_discovery_mutex);
 467                 }
 468         } else if (e_devid_do_discovery()) {
 469                 devid_discovery_busy = 1;
 470                 mutex_exit(&devid_discovery_mutex);
 471 
 472                 if (i_ddi_io_initialized() == 0) {
 473                         e_ddi_devid_hold_installed_driver(devid);
 474                 } else {
 475                         DEVID_LOG_DISC((CE_CONT,
 476                             "devid_discovery: ndi_devi_config\n"));
 477                         flags = NDI_DEVI_PERSIST | NDI_CONFIG | NDI_NO_EVENT;
 478                         if (i_ddi_io_initialized())
 479                                 flags |= NDI_DRV_CONF_REPROBE;
 480                         (void) ndi_devi_config(ddi_root_node(), flags);
 481                 }
 482 
 483                 mutex_enter(&devid_discovery_mutex);
 484                 devid_discovery_busy = 0;
 485                 cv_broadcast(&devid_discovery_cv);
 486                 if (devid_discovery_secs > 0)
 487                         devid_last_discovery = ddi_get_lbolt();
 488                 DEVID_LOG_DISC((CE_CONT, "devid_discovery: done\n"));
 489         } else {
 490                 rval = DDI_FAILURE;
 491                 DEVID_LOG_DISC((CE_CONT, "no devid discovery\n"));
 492         }
 493 
 494         mutex_exit(&devid_discovery_mutex);
 495 
 496         return (rval);
 497 }
 498 
 499 /*
 500  * As part of registering a devid for a device,
 501  * update the devid cache with this device/devid pair
 502  * or note that this combination has registered.
 503  *
 504  * If a devpath is provided it will be used as the path to register the
 505  * devid against, otherwise we use ddi_pathname(dip).  In both cases
 506  * we duplicate the path string so that it can be cached/freed indepdently
 507  * of the original owner.
 508  */
 509 static int
 510 e_devid_cache_register_cmn(dev_info_t *dip, ddi_devid_t devid, char *devpath)
 511 {
 512         nvp_devid_t *np;
 513         nvp_devid_t *new_nvp;
 514         ddi_devid_t new_devid;
 515         int new_devid_size;
 516         char *path, *fullpath;
 517         ddi_devid_t free_devid = NULL;
 518         int pathlen;
 519         list_t *listp;
 520         int is_dirty = 0;
 521 
 522 
 523         ASSERT(ddi_devid_valid(devid) == DDI_SUCCESS);
 524 
 525         if (devpath) {
 526                 pathlen = strlen(devpath) + 1;
 527                 path = kmem_alloc(pathlen, KM_SLEEP);
 528                 bcopy(devpath, path, pathlen);
 529         } else {
 530                 /*
 531                  * We are willing to accept DS_BOUND nodes if we can form a full
 532                  * ddi_pathname (i.e. the node is part way to becomming
 533                  * DS_INITIALIZED and devi_addr/ddi_get_name_addr are non-NULL).
 534                  */
 535                 if (ddi_get_name_addr(dip) == NULL)
 536                         return (DDI_FAILURE);
 537 
 538                 fullpath = kmem_alloc(MAXPATHLEN, KM_SLEEP);
 539                 (void) ddi_pathname(dip, fullpath);
 540                 pathlen = strlen(fullpath) + 1;
 541                 path = kmem_alloc(pathlen, KM_SLEEP);
 542                 bcopy(fullpath, path, pathlen);
 543                 kmem_free(fullpath, MAXPATHLEN);
 544         }
 545 
 546         DEVID_LOG_REG(("register", devid, path));
 547 
 548         new_nvp = kmem_zalloc(sizeof (nvp_devid_t), KM_SLEEP);
 549         new_devid_size = ddi_devid_sizeof(devid);
 550         new_devid = kmem_alloc(new_devid_size, KM_SLEEP);
 551         (void) bcopy(devid, new_devid, new_devid_size);
 552 
 553         rw_enter(nvf_lock(dcfd_handle), RW_WRITER);
 554 
 555         listp = nvf_list(dcfd_handle);
 556         for (np = list_head(listp); np; np = list_next(listp, np)) {
 557                 if (strcmp(path, np->nvp_devpath) == 0) {
 558                         DEVID_DEBUG2((CE_CONT,
 559                             "register: %s path match\n", path));
 560                         if (np->nvp_devid == NULL) {
 561 replace:                        np->nvp_devid = new_devid;
 562                                 np->nvp_flags |=
 563                                     NVP_DEVID_DIP | NVP_DEVID_REGISTERED;
 564                                 np->nvp_dip = dip;
 565                                 if (!devid_cache_write_disable) {
 566                                         nvf_mark_dirty(dcfd_handle);
 567                                         is_dirty = 1;
 568                                 }
 569                                 rw_exit(nvf_lock(dcfd_handle));
 570                                 kmem_free(new_nvp, sizeof (nvp_devid_t));
 571                                 kmem_free(path, pathlen);
 572                                 goto exit;
 573                         }
 574                         if (ddi_devid_valid(np->nvp_devid) != DDI_SUCCESS) {
 575                                 /* replace invalid devid */
 576                                 free_devid = np->nvp_devid;
 577                                 goto replace;
 578                         }
 579                         /*
 580                          * We're registering an already-cached path
 581                          * Does the device's devid match the cache?
 582                          */
 583                         if (ddi_devid_compare(devid, np->nvp_devid) != 0) {
 584                                 DEVID_DEBUG((CE_CONT, "devid register: "
 585                                     "devid %s does not match\n", path));
 586                                 /*
 587                                  * Replace cached devid for this path
 588                                  * with newly registered devid.  A devid
 589                                  * may map to multiple paths but one path
 590                                  * should only map to one devid.
 591                                  */
 592                                 devid_nvp_unlink_and_free(dcfd_handle, np);
 593                                 np = NULL;
 594                                 break;
 595                         } else {
 596                                 DEVID_DEBUG2((CE_CONT,
 597                                     "devid register: %s devid match\n", path));
 598                                 np->nvp_flags |=
 599                                     NVP_DEVID_DIP | NVP_DEVID_REGISTERED;
 600                                 np->nvp_dip = dip;
 601                                 rw_exit(nvf_lock(dcfd_handle));
 602                                 kmem_free(new_nvp, sizeof (nvp_devid_t));
 603                                 kmem_free(path, pathlen);
 604                                 kmem_free(new_devid, new_devid_size);
 605                                 return (DDI_SUCCESS);
 606                         }
 607                 }
 608         }
 609 
 610         /*
 611          * Add newly registered devid to the cache
 612          */
 613         ASSERT(np == NULL);
 614 
 615         new_nvp->nvp_devpath = path;
 616         new_nvp->nvp_flags = NVP_DEVID_DIP | NVP_DEVID_REGISTERED;
 617         new_nvp->nvp_dip = dip;
 618         new_nvp->nvp_devid = new_devid;
 619 
 620         if (!devid_cache_write_disable) {
 621                 is_dirty = 1;
 622                 nvf_mark_dirty(dcfd_handle);
 623         }
 624         list_insert_tail(nvf_list(dcfd_handle), new_nvp);
 625 
 626         rw_exit(nvf_lock(dcfd_handle));
 627 
 628 exit:
 629         if (free_devid)
 630                 kmem_free(free_devid, ddi_devid_sizeof(free_devid));
 631 
 632         if (is_dirty)
 633                 nvf_wake_daemon();
 634 
 635         return (DDI_SUCCESS);
 636 }
 637 
 638 int
 639 e_devid_cache_register(dev_info_t *dip, ddi_devid_t devid)
 640 {
 641         return (e_devid_cache_register_cmn(dip, devid, NULL));
 642 }
 643 
 644 /*
 645  * Unregister a device's devid; the devinfo may hit on multiple entries
 646  * arising from both pHCI and vHCI paths.
 647  * Called as an instance detachs.
 648  * Invalidate the devid's devinfo reference.
 649  * Devid-path remains in the cache.
 650  */
 651 
 652 void
 653 e_devid_cache_unregister(dev_info_t *dip)
 654 {
 655         nvp_devid_t *np;
 656         list_t *listp;
 657 
 658         rw_enter(nvf_lock(dcfd_handle), RW_WRITER);
 659 
 660         listp = nvf_list(dcfd_handle);
 661         for (np = list_head(listp); np; np = list_next(listp, np)) {
 662                 if (np->nvp_devid == NULL)
 663                         continue;
 664                 if ((np->nvp_flags & NVP_DEVID_DIP) && np->nvp_dip == dip) {
 665                         DEVID_LOG_UNREG((CE_CONT,
 666                             "unregister: %s\n", np->nvp_devpath));
 667                         np->nvp_flags &= ~NVP_DEVID_DIP;
 668                         np->nvp_dip = NULL;
 669                 }
 670         }
 671 
 672         rw_exit(nvf_lock(dcfd_handle));
 673 }
 674 
 675 int
 676 e_devid_cache_pathinfo(mdi_pathinfo_t *pip, ddi_devid_t devid)
 677 {
 678         char *path = mdi_pi_pathname(pip);
 679 
 680         return (e_devid_cache_register_cmn(mdi_pi_get_client(pip), devid,
 681             path));
 682 }
 683 
 684 /*
 685  * Purge devid cache of stale devids
 686  */
 687 void
 688 devid_cache_cleanup(void)
 689 {
 690         nvp_devid_t *np, *next;
 691         list_t *listp;
 692         int is_dirty = 0;
 693 
 694         rw_enter(nvf_lock(dcfd_handle), RW_WRITER);
 695 
 696         listp = nvf_list(dcfd_handle);
 697         for (np = list_head(listp); np; np = next) {
 698                 next = list_next(listp, np);
 699                 if (np->nvp_devid == NULL)
 700                         continue;
 701                 if ((np->nvp_flags & NVP_DEVID_REGISTERED) == 0) {
 702                         DEVID_LOG_REMOVE((CE_CONT,
 703                             "cleanup: %s\n", np->nvp_devpath));
 704                         if (!devid_cache_write_disable) {
 705                                 nvf_mark_dirty(dcfd_handle);
 706                                 is_dirty = 0;
 707                         }
 708                         devid_nvp_unlink_and_free(dcfd_handle, np);
 709                 }
 710         }
 711 
 712         rw_exit(nvf_lock(dcfd_handle));
 713 
 714         if (is_dirty)
 715                 nvf_wake_daemon();
 716 }
 717 
 718 
 719 /*
 720  * Build a list of dev_t's for a device/devid
 721  *
 722  * The effect of this function is cumulative, adding dev_t's
 723  * for the device to the list of all dev_t's for a given
 724  * devid.
 725  */
 726 static void
 727 e_devid_minor_to_devlist(
 728         dev_info_t      *dip,
 729         char            *minor_name,
 730         int             ndevts_alloced,
 731         int             *devtcntp,
 732         dev_t           *devtsp)
 733 {
 734         int                     circ;
 735         struct ddi_minor_data   *dmdp;
 736         int                     minor_all = 0;
 737         int                     ndevts = *devtcntp;
 738 
 739         if (!i_ddi_devi_attached(dip)) {
 740                 return;
 741         }
 742 
 743         /* are we looking for a set of minor nodes? */
 744         if ((minor_name == DEVID_MINOR_NAME_ALL) ||
 745             (minor_name == DEVID_MINOR_NAME_ALL_CHR) ||
 746             (minor_name == DEVID_MINOR_NAME_ALL_BLK))
 747                 minor_all = 1;
 748 
 749         /* Find matching minor names */
 750         ndi_devi_enter(dip, &circ);
 751         for (dmdp = DEVI(dip)->devi_minor; dmdp; dmdp = dmdp->next) {
 752 
 753                 /* Skip non-minors, and non matching minor names */
 754                 if ((dmdp->type != DDM_MINOR) || ((minor_all == 0) &&
 755                     strcmp(dmdp->ddm_name, minor_name)))
 756                         continue;
 757 
 758                 /* filter out minor_all mismatches */
 759                 if (minor_all &&
 760                     (((minor_name == DEVID_MINOR_NAME_ALL_CHR) &&
 761                     (dmdp->ddm_spec_type != S_IFCHR)) ||
 762                     ((minor_name == DEVID_MINOR_NAME_ALL_BLK) &&
 763                     (dmdp->ddm_spec_type != S_IFBLK))))
 764                         continue;
 765 
 766                 if (ndevts < ndevts_alloced)
 767                         devtsp[ndevts] = dmdp->ddm_dev;
 768                 ndevts++;
 769         }
 770         ndi_devi_exit(dip, circ);
 771 
 772         *devtcntp = ndevts;
 773 }
 774 
 775 /*
 776  * Search for cached entries matching a devid
 777  * Return two lists:
 778  *      a list of dev_info nodes, for those devices in the attached state
 779  *      a list of pathnames whose instances registered the given devid
 780  * If the lists passed in are not sufficient to return the matching
 781  * references, return the size of lists required.
 782  * The dev_info nodes are returned with a hold that the caller must release.
 783  */
 784 static int
 785 e_devid_cache_devi_path_lists(ddi_devid_t devid, int retmax,
 786         int *retndevis, dev_info_t **retdevis, int *retnpaths, char **retpaths)
 787 {
 788         nvp_devid_t *np;
 789         int ndevis, npaths;
 790         dev_info_t *dip, *pdip;
 791         int circ;
 792         int maxdevis = 0;
 793         int maxpaths = 0;
 794         list_t *listp;
 795 
 796         ndevis = 0;
 797         npaths = 0;
 798         listp = nvf_list(dcfd_handle);
 799         for (np = list_head(listp); np; np = list_next(listp, np)) {
 800                 if (np->nvp_devid == NULL)
 801                         continue;
 802                 if (ddi_devid_valid(np->nvp_devid) != DDI_SUCCESS) {
 803                         DEVIDERR((CE_CONT,
 804                             "find: invalid devid %s\n",
 805                             np->nvp_devpath));
 806                         continue;
 807                 }
 808                 if (ddi_devid_compare(devid, np->nvp_devid) == 0) {
 809                         DEVID_DEBUG2((CE_CONT,
 810                             "find: devid match: %s 0x%x\n",
 811                             np->nvp_devpath, np->nvp_flags));
 812                         DEVID_LOG_MATCH(("find", devid, np->nvp_devpath));
 813                         DEVID_LOG_PATHS((CE_CONT, "%s\n", np->nvp_devpath));
 814 
 815                         /*
 816                          * Check if we have a cached devinfo reference for this
 817                          * devid.  Place a hold on it to prevent detach
 818                          * Otherwise, use the path instead.
 819                          * Note: returns with a hold on each dev_info
 820                          * node in the list.
 821                          */
 822                         dip = NULL;
 823                         if (np->nvp_flags & NVP_DEVID_DIP) {
 824                                 pdip = ddi_get_parent(np->nvp_dip);
 825                                 if (ndi_devi_tryenter(pdip, &circ)) {
 826                                         dip = np->nvp_dip;
 827                                         ndi_hold_devi(dip);
 828                                         ndi_devi_exit(pdip, circ);
 829                                         ASSERT(!DEVI_IS_ATTACHING(dip));
 830                                         ASSERT(!DEVI_IS_DETACHING(dip));
 831                                 } else {
 832                                         DEVID_LOG_DETACH((CE_CONT,
 833                                             "may be detaching: %s\n",
 834                                             np->nvp_devpath));
 835                                 }
 836                         }
 837 
 838                         if (dip) {
 839                                 if (ndevis < retmax) {
 840                                         retdevis[ndevis++] = dip;
 841                                 } else {
 842                                         ndi_rele_devi(dip);
 843                                 }
 844                                 maxdevis++;
 845                         } else {
 846                                 if (npaths < retmax)
 847                                         retpaths[npaths++] = np->nvp_devpath;
 848                                 maxpaths++;
 849                         }
 850                 }
 851         }
 852 
 853         *retndevis = ndevis;
 854         *retnpaths = npaths;
 855         return (maxdevis > maxpaths ? maxdevis : maxpaths);
 856 }
 857 
 858 
 859 /*
 860  * Search the devid cache, returning dev_t list for all
 861  * device paths mapping to the device identified by the
 862  * given devid.
 863  *
 864  * Primary interface used by ddi_lyr_devid_to_devlist()
 865  */
 866 int
 867 e_devid_cache_to_devt_list(ddi_devid_t devid, char *minor_name,
 868         int *retndevts, dev_t **retdevts)
 869 {
 870         char            *path, **paths;
 871         int             i, j, n;
 872         dev_t           *devts, *udevts;
 873         dev_t           tdevt;
 874         int             ndevts, undevts, ndevts_alloced;
 875         dev_info_t      *devi, **devis;
 876         int             ndevis, npaths, nalloced;
 877         ddi_devid_t     match_devid;
 878 
 879         DEVID_LOG_FIND(("find", devid, NULL));
 880 
 881         ASSERT(ddi_devid_valid(devid) == DDI_SUCCESS);
 882         if (ddi_devid_valid(devid) != DDI_SUCCESS) {
 883                 DEVID_LOG_ERR(("invalid devid", devid, NULL));
 884                 return (DDI_FAILURE);
 885         }
 886 
 887         nalloced = 128;
 888 
 889         for (;;) {
 890                 paths = kmem_zalloc(nalloced * sizeof (char *), KM_SLEEP);
 891                 devis = kmem_zalloc(nalloced * sizeof (dev_info_t *), KM_SLEEP);
 892 
 893                 rw_enter(nvf_lock(dcfd_handle), RW_READER);
 894                 n = e_devid_cache_devi_path_lists(devid, nalloced,
 895                     &ndevis, devis, &npaths, paths);
 896                 if (n <= nalloced)
 897                         break;
 898                 rw_exit(nvf_lock(dcfd_handle));
 899                 for (i = 0; i < ndevis; i++)
 900                         ndi_rele_devi(devis[i]);
 901                 kmem_free(paths, nalloced * sizeof (char *));
 902                 kmem_free(devis, nalloced * sizeof (dev_info_t *));
 903                 nalloced = n + 128;
 904         }
 905 
 906         for (i = 0; i < npaths; i++) {
 907                 path = i_ddi_strdup(paths[i], KM_SLEEP);
 908                 paths[i] = path;
 909         }
 910         rw_exit(nvf_lock(dcfd_handle));
 911 
 912         if (ndevis == 0 && npaths == 0) {
 913                 DEVID_LOG_ERR(("no devid found", devid, NULL));
 914                 kmem_free(paths, nalloced * sizeof (char *));
 915                 kmem_free(devis, nalloced * sizeof (dev_info_t *));
 916                 return (DDI_FAILURE);
 917         }
 918 
 919         ndevts_alloced = 128;
 920 restart:
 921         ndevts = 0;
 922         devts = kmem_alloc(ndevts_alloced * sizeof (dev_t), KM_SLEEP);
 923         for (i = 0; i < ndevis; i++) {
 924                 ASSERT(!DEVI_IS_ATTACHING(devis[i]));
 925                 ASSERT(!DEVI_IS_DETACHING(devis[i]));
 926                 e_devid_minor_to_devlist(devis[i], minor_name,
 927                     ndevts_alloced, &ndevts, devts);
 928                 if (ndevts > ndevts_alloced) {
 929                         kmem_free(devts, ndevts_alloced * sizeof (dev_t));
 930                         ndevts_alloced += 128;
 931                         goto restart;
 932                 }
 933         }
 934         for (i = 0; i < npaths; i++) {
 935                 DEVID_LOG_LOOKUP((CE_CONT, "lookup %s\n", paths[i]));
 936                 devi = e_ddi_hold_devi_by_path(paths[i], 0);
 937                 if (devi == NULL) {
 938                         DEVID_LOG_STALE(("stale device reference",
 939                             devid, paths[i]));
 940                         continue;
 941                 }
 942                 /*
 943                  * Verify the newly attached device registered a matching devid
 944                  */
 945                 if (i_ddi_devi_get_devid(DDI_DEV_T_ANY, devi,
 946                     &match_devid) != DDI_SUCCESS) {
 947                         DEVIDERR((CE_CONT,
 948                             "%s: no devid registered on attach\n",
 949                             paths[i]));
 950                         ddi_release_devi(devi);
 951                         continue;
 952                 }
 953 
 954                 if (ddi_devid_compare(devid, match_devid) != 0) {
 955                         DEVID_LOG_STALE(("new devid registered",
 956                             devid, paths[i]));
 957                         ddi_release_devi(devi);
 958                         ddi_devid_free(match_devid);
 959                         continue;
 960                 }
 961                 ddi_devid_free(match_devid);
 962 
 963                 e_devid_minor_to_devlist(devi, minor_name,
 964                     ndevts_alloced, &ndevts, devts);
 965                 ddi_release_devi(devi);
 966                 if (ndevts > ndevts_alloced) {
 967                         kmem_free(devts,
 968                             ndevts_alloced * sizeof (dev_t));
 969                         ndevts_alloced += 128;
 970                         goto restart;
 971                 }
 972         }
 973 
 974         /* drop hold from e_devid_cache_devi_path_lists */
 975         for (i = 0; i < ndevis; i++) {
 976                 ndi_rele_devi(devis[i]);
 977         }
 978         for (i = 0; i < npaths; i++) {
 979                 kmem_free(paths[i], strlen(paths[i]) + 1);
 980         }
 981         kmem_free(paths, nalloced * sizeof (char *));
 982         kmem_free(devis, nalloced * sizeof (dev_info_t *));
 983 
 984         if (ndevts == 0) {
 985                 DEVID_LOG_ERR(("no devid found", devid, NULL));
 986                 kmem_free(devts, ndevts_alloced * sizeof (dev_t));
 987                 return (DDI_FAILURE);
 988         }
 989 
 990         /*
 991          * Build the final list of sorted dev_t's with duplicates collapsed so
 992          * returned results are consistent. This prevents implementation
 993          * artifacts from causing unnecessary changes in SVM namespace.
 994          */
 995         /* bubble sort */
 996         for (i = 0; i < (ndevts - 1); i++) {
 997                 for (j = 0; j < ((ndevts - 1) - i); j++) {
 998                         if (devts[j + 1] < devts[j]) {
 999                                 tdevt = devts[j];
1000                                 devts[j] = devts[j + 1];
1001                                 devts[j + 1] = tdevt;
1002                         }
1003                 }
1004         }
1005 
1006         /* determine number of unique values */
1007         for (undevts = ndevts, i = 1; i < ndevts; i++) {
1008                 if (devts[i - 1] == devts[i])
1009                         undevts--;
1010         }
1011 
1012         /* allocate unique */
1013         udevts = kmem_alloc(undevts * sizeof (dev_t), KM_SLEEP);
1014 
1015         /* copy unique */
1016         udevts[0] = devts[0];
1017         for (i = 1, j = 1; i < ndevts; i++) {
1018                 if (devts[i - 1] != devts[i])
1019                         udevts[j++] = devts[i];
1020         }
1021         ASSERT(j == undevts);
1022 
1023         kmem_free(devts, ndevts_alloced * sizeof (dev_t));
1024 
1025         *retndevts = undevts;
1026         *retdevts = udevts;
1027 
1028         return (DDI_SUCCESS);
1029 }
1030 
1031 void
1032 e_devid_cache_free_devt_list(int ndevts, dev_t *devt_list)
1033 {
1034         kmem_free(devt_list, ndevts * sizeof (dev_t *));
1035 }
1036 
1037 /*
1038  * If given a full path and NULL ua, search for a cache entry
1039  * whose path matches the full path.  On a cache hit duplicate the
1040  * devid of the matched entry into the given devid (caller
1041  * must free);  nodenamebuf is not touched for this usage.
1042  *
1043  * Given a path and a non-NULL unit address, search the cache for any entry
1044  * matching "<path>/%@<unit-address>" where '%' is a wildcard meaning
1045  * any node name.  The path should not end a '/'.  On a cache hit
1046  * duplicate the devid as before (caller must free) and copy into
1047  * the caller-provided nodenamebuf (if not NULL) the nodename of the
1048  * matched entry.
1049  *
1050  * We must not make use of nvp_dip since that may be NULL for cached
1051  * entries that are not present in the current tree.
1052  */
1053 int
1054 e_devid_cache_path_to_devid(char *path, char *ua,
1055     char *nodenamebuf, ddi_devid_t *devidp)
1056 {
1057         size_t pathlen, ualen;
1058         int rv = DDI_FAILURE;
1059         nvp_devid_t *np;
1060         list_t *listp;
1061         char *cand;
1062 
1063         if (path == NULL || *path == '\0' || (ua && *ua == '\0') ||
1064             devidp == NULL)
1065                 return (DDI_FAILURE);
1066 
1067         *devidp = NULL;
1068 
1069         if (ua) {
1070                 pathlen = strlen(path);
1071                 ualen = strlen(ua);
1072         }
1073 
1074         rw_enter(nvf_lock(dcfd_handle), RW_READER);
1075 
1076         listp = nvf_list(dcfd_handle);
1077         for (np = list_head(listp); np; np = list_next(listp, np)) {
1078                 size_t nodelen, candlen, n;
1079                 ddi_devid_t devid_dup;
1080                 char *uasep, *node;
1081 
1082                 if (np->nvp_devid == NULL)
1083                         continue;
1084 
1085                 if (ddi_devid_valid(np->nvp_devid) != DDI_SUCCESS) {
1086                         DEVIDERR((CE_CONT,
1087                             "pathsearch: invalid devid %s\n",
1088                             np->nvp_devpath));
1089                         continue;
1090                 }
1091 
1092                 cand = np->nvp_devpath;              /* candidate path */
1093 
1094                 /* If a full pathname was provided the compare is easy */
1095                 if (ua == NULL) {
1096                         if (strcmp(cand, path) == 0)
1097                                 goto match;
1098                         else
1099                                 continue;
1100                 }
1101 
1102                 /*
1103                  * The compare for initial path plus ua and unknown nodename
1104                  * is trickier.
1105                  *
1106                  * Does the initial path component match 'path'?
1107                  */
1108                 if (strncmp(path, cand, pathlen) != 0)
1109                         continue;
1110 
1111                 candlen = strlen(cand);
1112 
1113                 /*
1114                  * The next character must be a '/' and there must be no
1115                  * further '/' thereafter.  Begin by checking that the
1116                  * candidate is long enough to include at mininum a
1117                  * "/<nodename>@<ua>" after the initial portion already
1118                  * matched assuming a nodename length of 1.
1119                  */
1120                 if (candlen < pathlen + 1 + 1 + 1 + ualen ||
1121                     cand[pathlen] != '/' ||
1122                     strchr(cand + pathlen + 1, '/') != NULL)
1123                         continue;
1124 
1125                 node = cand + pathlen + 1;      /* <node>@<ua> string */
1126 
1127                 /*
1128                  * Find the '@' before the unit address.  Check for
1129                  * unit address match.
1130                  */
1131                 if ((uasep = strchr(node, '@')) == NULL)
1132                         continue;
1133 
1134                 /*
1135                  * Check we still have enough length and that ua matches
1136                  */
1137                 nodelen = (uintptr_t)uasep - (uintptr_t)node;
1138                 if (candlen < pathlen + 1 + nodelen + 1 + ualen ||
1139                     strncmp(ua, uasep + 1, ualen) != 0)
1140                         continue;
1141 match:
1142                 n = ddi_devid_sizeof(np->nvp_devid);
1143                 devid_dup = kmem_alloc(n, KM_SLEEP);    /* caller must free */
1144                 (void) bcopy(np->nvp_devid, devid_dup, n);
1145                 *devidp = devid_dup;
1146 
1147                 if (ua && nodenamebuf) {
1148                         (void) strncpy(nodenamebuf, node, nodelen);
1149                         nodenamebuf[nodelen] = '\0';
1150                 }
1151 
1152                 rv = DDI_SUCCESS;
1153                 break;
1154         }
1155 
1156         rw_exit(nvf_lock(dcfd_handle));
1157 
1158         return (rv);
1159 }
1160 
1161 #ifdef  DEBUG
1162 static void
1163 devid_log(char *fmt, ddi_devid_t devid, char *path)
1164 {
1165         char *devidstr = ddi_devid_str_encode(devid, NULL);
1166         if (path) {
1167                 cmn_err(CE_CONT, "%s: %s %s\n", fmt, path, devidstr);
1168         } else {
1169                 cmn_err(CE_CONT, "%s: %s\n", fmt, devidstr);
1170         }
1171         ddi_devid_str_free(devidstr);
1172 }
1173 #endif  /* DEBUG */