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