xref: /illumos-gate/usr/src/uts/common/os/devid_cache.c (revision 8a8d276f)
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 2006 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 != (major_t)-1) {
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 != (major_t)-1 && 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:
527 				np->nvp_devid = new_devid;
528 				np->nvp_flags |=
529 					NVP_DEVID_DIP | NVP_DEVID_REGISTERED;
530 				np->nvp_dip = dip;
531 				if (!devid_cache_write_disable) {
532 					nvf_mark_dirty(dcfd_handle);
533 					is_dirty = 1;
534 				}
535 				rw_exit(nvf_lock(dcfd_handle));
536 				kmem_free(new_nvp, sizeof (nvp_devid_t));
537 				kmem_free(path, pathlen);
538 				goto exit;
539 			}
540 			if (ddi_devid_valid(np->nvp_devid) != DDI_SUCCESS) {
541 				/* replace invalid devid */
542 				free_devid = np->nvp_devid;
543 				goto replace;
544 			}
545 			/*
546 			 * We're registering an already-cached path
547 			 * Does the device's devid match the cache?
548 			 */
549 			if (ddi_devid_compare(devid, np->nvp_devid) != 0) {
550 				DEVID_DEBUG((CE_CONT, "devid register: "
551 				    "devid %s does not match\n", path));
552 				/*
553 				 * Replace cached devid for this path
554 				 * with newly registered devid.  A devid
555 				 * may map to multiple paths but one path
556 				 * should only map to one devid.
557 				 */
558 				devid_nvp_unlink_and_free(dcfd_handle, np);
559 				np = NULL;
560 				break;
561 			} else {
562 				DEVID_DEBUG2((CE_CONT,
563 				    "devid register: %s devid match\n", path));
564 				np->nvp_flags |=
565 					NVP_DEVID_DIP | NVP_DEVID_REGISTERED;
566 				np->nvp_dip = dip;
567 				rw_exit(nvf_lock(dcfd_handle));
568 				kmem_free(new_nvp, sizeof (nvp_devid_t));
569 				kmem_free(path, pathlen);
570 				kmem_free(new_devid, new_devid_size);
571 				return (DDI_SUCCESS);
572 			}
573 		}
574 	}
575 
576 	/*
577 	 * Add newly registered devid to the cache
578 	 */
579 	ASSERT(np == NULL);
580 
581 	new_nvp->nvp_devpath = path;
582 	new_nvp->nvp_flags = NVP_DEVID_DIP | NVP_DEVID_REGISTERED;
583 	new_nvp->nvp_dip = dip;
584 	new_nvp->nvp_devid = new_devid;
585 
586 	if (!devid_cache_write_disable) {
587 		is_dirty = 1;
588 		nvf_mark_dirty(dcfd_handle);
589 	}
590 	list_insert_tail(nvf_list(dcfd_handle), new_nvp);
591 
592 	rw_exit(nvf_lock(dcfd_handle));
593 
594 exit:
595 	if (free_devid)
596 		kmem_free(free_devid, ddi_devid_sizeof(free_devid));
597 
598 	if (is_dirty)
599 		nvf_wake_daemon();
600 
601 	return (DDI_SUCCESS);
602 }
603 
604 /*
605  * Unregister a device's devid
606  * Called as an instance detachs
607  * Invalidate the devid's devinfo reference
608  * Devid-path remains in the cache
609  */
610 void
611 e_devid_cache_unregister(dev_info_t *dip)
612 {
613 	nvp_devid_t *np;
614 	list_t *listp;
615 
616 	rw_enter(nvf_lock(dcfd_handle), RW_WRITER);
617 
618 	listp = nvf_list(dcfd_handle);
619 	for (np = list_head(listp); np; np = list_next(listp, np)) {
620 		if (np->nvp_devid == NULL)
621 			continue;
622 		if ((np->nvp_flags & NVP_DEVID_DIP) && np->nvp_dip == dip) {
623 			DEVID_LOG_UNREG((CE_CONT,
624 				"unregister: %s\n", np->nvp_devpath));
625 			np->nvp_flags &= ~NVP_DEVID_DIP;
626 			np->nvp_dip = NULL;
627 			break;
628 		}
629 	}
630 
631 	rw_exit(nvf_lock(dcfd_handle));
632 }
633 
634 /*
635  * Purge devid cache of stale devids
636  */
637 void
638 devid_cache_cleanup(void)
639 {
640 	nvp_devid_t *np, *next;
641 	list_t *listp;
642 	int is_dirty = 0;
643 
644 	rw_enter(nvf_lock(dcfd_handle), RW_WRITER);
645 
646 	listp = nvf_list(dcfd_handle);
647 	for (np = list_head(listp); np; np = next) {
648 		next = list_next(listp, np);
649 		if (np->nvp_devid == NULL)
650 			continue;
651 		if ((np->nvp_flags & NVP_DEVID_REGISTERED) == 0) {
652 			DEVID_LOG_REMOVE((CE_CONT,
653 				    "cleanup: %s\n", np->nvp_devpath));
654 			if (!devid_cache_write_disable) {
655 				nvf_mark_dirty(dcfd_handle);
656 				is_dirty = 0;
657 			}
658 			devid_nvp_unlink_and_free(dcfd_handle, np);
659 		}
660 	}
661 
662 	rw_exit(nvf_lock(dcfd_handle));
663 
664 	if (is_dirty)
665 		nvf_wake_daemon();
666 }
667 
668 
669 /*
670  * Build a list of dev_t's for a device/devid
671  *
672  * The effect of this function is cumulative, adding dev_t's
673  * for the device to the list of all dev_t's for a given
674  * devid.
675  */
676 static void
677 e_devid_minor_to_devlist(
678 	dev_info_t	*dip,
679 	char		*minor_name,
680 	int		ndevts_alloced,
681 	int		*devtcntp,
682 	dev_t		*devtsp)
683 {
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 	mutex_enter(&(DEVI(dip)->devi_lock));
697 
698 	/* Find matching minor names */
699 	for (dmdp = DEVI(dip)->devi_minor; dmdp; dmdp = dmdp->next) {
700 
701 		/* Skip non-minors, and non matching minor names */
702 		if ((dmdp->type != DDM_MINOR) || ((minor_all == 0) &&
703 		    strcmp(dmdp->ddm_name, minor_name)))
704 			continue;
705 
706 		/* filter out minor_all mismatches */
707 		if (minor_all &&
708 		    (((minor_name == DEVID_MINOR_NAME_ALL_CHR) &&
709 		    (dmdp->ddm_spec_type != S_IFCHR)) ||
710 		    ((minor_name == DEVID_MINOR_NAME_ALL_BLK) &&
711 		    (dmdp->ddm_spec_type != S_IFBLK))))
712 			continue;
713 
714 		if (ndevts < ndevts_alloced)
715 			devtsp[ndevts] = dmdp->ddm_dev;
716 		ndevts++;
717 	}
718 
719 	mutex_exit(&(DEVI(dip)->devi_lock));
720 
721 	*devtcntp = ndevts;
722 }
723 
724 /*
725  * Search for cached entries matching a devid
726  * Return two lists:
727  *	a list of dev_info nodes, for those devices in the attached state
728  *	a list of pathnames whose instances registered the given devid
729  * If the lists passed in are not sufficient to return the matching
730  * references, return the size of lists required.
731  * The dev_info nodes are returned with a hold that the caller must release.
732  */
733 static int
734 e_devid_cache_devi_path_lists(ddi_devid_t devid, int retmax,
735 	int *retndevis, dev_info_t **retdevis, int *retnpaths, char **retpaths)
736 {
737 	nvp_devid_t *np;
738 	int ndevis, npaths;
739 	dev_info_t *dip, *pdip;
740 	int circ;
741 	int maxdevis = 0;
742 	int maxpaths = 0;
743 	list_t *listp;
744 
745 	ndevis = 0;
746 	npaths = 0;
747 	listp = nvf_list(dcfd_handle);
748 	for (np = list_head(listp); np; np = list_next(listp, np)) {
749 		if (np->nvp_devid == NULL)
750 			continue;
751 		if (ddi_devid_valid(np->nvp_devid) != DDI_SUCCESS) {
752 			DEVIDERR((CE_CONT,
753 			    "find: invalid devid %s\n",
754 			    np->nvp_devpath));
755 			continue;
756 		}
757 		if (ddi_devid_compare(devid, np->nvp_devid) == 0) {
758 			DEVID_DEBUG2((CE_CONT,
759 			    "find: devid match: %s 0x%x\n",
760 			    np->nvp_devpath, np->nvp_flags));
761 			DEVID_LOG_MATCH(("find", devid, np->nvp_devpath));
762 			DEVID_LOG_PATHS((CE_CONT, "%s\n", np->nvp_devpath));
763 
764 			/*
765 			 * Check if we have a cached devinfo reference for this
766 			 * devid.  Place a hold on it to prevent detach
767 			 * Otherwise, use the path instead.
768 			 * Note: returns with a hold on each dev_info
769 			 * node in the list.
770 			 */
771 			dip = NULL;
772 			if (np->nvp_flags & NVP_DEVID_DIP) {
773 				pdip = ddi_get_parent(np->nvp_dip);
774 				if (ndi_devi_tryenter(pdip, &circ)) {
775 					dip = np->nvp_dip;
776 					ndi_hold_devi(dip);
777 					ndi_devi_exit(pdip, circ);
778 					ASSERT(!DEVI_IS_ATTACHING(dip));
779 					ASSERT(!DEVI_IS_DETACHING(dip));
780 				} else {
781 					DEVID_LOG_DETACH((CE_CONT,
782 					    "may be detaching: %s\n",
783 					    np->nvp_devpath));
784 				}
785 			}
786 
787 			if (dip) {
788 				if (ndevis < retmax) {
789 					retdevis[ndevis++] = dip;
790 				} else {
791 					ndi_rele_devi(dip);
792 				}
793 				maxdevis++;
794 			} else {
795 				if (npaths < retmax)
796 					retpaths[npaths++] = np->nvp_devpath;
797 				maxpaths++;
798 			}
799 		}
800 	}
801 
802 	*retndevis = ndevis;
803 	*retnpaths = npaths;
804 	return (maxdevis > maxpaths ? maxdevis : maxpaths);
805 }
806 
807 
808 /*
809  * Search the devid cache, returning dev_t list for all
810  * device paths mapping to the device identified by the
811  * given devid.
812  *
813  * Primary interface used by ddi_lyr_devid_to_devlist()
814  */
815 int
816 e_devid_cache_to_devt_list(ddi_devid_t devid, char *minor_name,
817 	int *retndevts, dev_t **retdevts)
818 {
819 	char		*path, **paths;
820 	int		i, j, n;
821 	dev_t		*devts, *udevts;
822 	dev_t		tdevt;
823 	int		ndevts, undevts, ndevts_alloced;
824 	dev_info_t	*devi, **devis;
825 	int		ndevis, npaths, nalloced;
826 	ddi_devid_t	match_devid;
827 
828 	DEVID_LOG_FIND(("find", devid, NULL));
829 
830 	ASSERT(ddi_devid_valid(devid) == DDI_SUCCESS);
831 	if (ddi_devid_valid(devid) != DDI_SUCCESS) {
832 		DEVID_LOG_ERR(("invalid devid", devid, NULL));
833 		return (DDI_FAILURE);
834 	}
835 
836 	nalloced = 128;
837 
838 	for (;;) {
839 		paths = kmem_zalloc(nalloced * sizeof (char *), KM_SLEEP);
840 		devis = kmem_zalloc(nalloced * sizeof (dev_info_t *), KM_SLEEP);
841 
842 		rw_enter(nvf_lock(dcfd_handle), RW_READER);
843 		n = e_devid_cache_devi_path_lists(devid, nalloced,
844 			&ndevis, devis, &npaths, paths);
845 		if (n <= nalloced)
846 			break;
847 		rw_exit(nvf_lock(dcfd_handle));
848 		for (i = 0; i < ndevis; i++)
849 			ndi_rele_devi(devis[i]);
850 		kmem_free(paths, nalloced * sizeof (char *));
851 		kmem_free(devis, nalloced * sizeof (dev_info_t *));
852 		nalloced = n + 128;
853 	}
854 
855 	for (i = 0; i < npaths; i++) {
856 		path = i_ddi_strdup(paths[i], KM_SLEEP);
857 		paths[i] = path;
858 	}
859 	rw_exit(nvf_lock(dcfd_handle));
860 
861 	if (ndevis == 0 && npaths == 0) {
862 		DEVID_LOG_ERR(("no devid found", devid, NULL));
863 		kmem_free(paths, nalloced * sizeof (char *));
864 		kmem_free(devis, nalloced * sizeof (dev_info_t *));
865 		return (DDI_FAILURE);
866 	}
867 
868 	ndevts_alloced = 128;
869 restart:
870 	ndevts = 0;
871 	devts = kmem_alloc(ndevts_alloced * sizeof (dev_t), KM_SLEEP);
872 	for (i = 0; i < ndevis; i++) {
873 		ASSERT(!DEVI_IS_ATTACHING(devis[i]));
874 		ASSERT(!DEVI_IS_DETACHING(devis[i]));
875 		e_devid_minor_to_devlist(devis[i], minor_name,
876 			ndevts_alloced, &ndevts, devts);
877 		if (ndevts > ndevts_alloced) {
878 			kmem_free(devts, ndevts_alloced * sizeof (dev_t));
879 			ndevts_alloced += 128;
880 			goto restart;
881 		}
882 	}
883 	for (i = 0; i < npaths; i++) {
884 		DEVID_LOG_LOOKUP((CE_CONT, "lookup %s\n", paths[i]));
885 		devi = e_ddi_hold_devi_by_path(paths[i], 0);
886 		if (devi == NULL) {
887 			DEVID_LOG_STALE(("stale device reference",
888 			    devid, paths[i]));
889 			continue;
890 		}
891 		/*
892 		 * Verify the newly attached device registered a matching devid
893 		 */
894 		if (i_ddi_devi_get_devid(DDI_DEV_T_ANY, devi,
895 		    &match_devid) != DDI_SUCCESS) {
896 			DEVIDERR((CE_CONT,
897 			    "%s: no devid registered on attach\n",
898 			    paths[i]));
899 			ddi_release_devi(devi);
900 			continue;
901 		}
902 
903 		if (ddi_devid_compare(devid, match_devid) != 0) {
904 			DEVID_LOG_STALE(("new devid registered",
905 			    devid, paths[i]));
906 			ddi_release_devi(devi);
907 			ddi_devid_free(match_devid);
908 			continue;
909 		}
910 		ddi_devid_free(match_devid);
911 
912 		e_devid_minor_to_devlist(devi, minor_name,
913 			ndevts_alloced, &ndevts, devts);
914 		ddi_release_devi(devi);
915 		if (ndevts > ndevts_alloced) {
916 			kmem_free(devts,
917 			    ndevts_alloced * sizeof (dev_t));
918 			ndevts_alloced += 128;
919 			goto restart;
920 		}
921 	}
922 
923 	/* drop hold from e_devid_cache_devi_path_lists */
924 	for (i = 0; i < ndevis; i++) {
925 		ndi_rele_devi(devis[i]);
926 	}
927 	for (i = 0; i < npaths; i++) {
928 		kmem_free(paths[i], strlen(paths[i]) + 1);
929 	}
930 	kmem_free(paths, nalloced * sizeof (char *));
931 	kmem_free(devis, nalloced * sizeof (dev_info_t *));
932 
933 	if (ndevts == 0) {
934 		DEVID_LOG_ERR(("no devid found", devid, NULL));
935 		kmem_free(devts, ndevts_alloced * sizeof (dev_t));
936 		return (DDI_FAILURE);
937 	}
938 
939 	/*
940 	 * Build the final list of sorted dev_t's with duplicates collapsed so
941 	 * returned results are consistent. This prevents implementation
942 	 * artifacts from causing unnecessary changes in SVM namespace.
943 	 */
944 	/* bubble sort */
945 	for (i = 0; i < (ndevts - 1); i++) {
946 		for (j = 0; j < ((ndevts - 1) - i); j++) {
947 			if (devts[j + 1] < devts[j]) {
948 				tdevt = devts[j];
949 				devts[j] = devts[j + 1];
950 				devts[j + 1] = tdevt;
951 			}
952 		}
953 	}
954 
955 	/* determine number of unique values */
956 	for (undevts = ndevts, i = 1; i < ndevts; i++) {
957 		if (devts[i - 1] == devts[i])
958 			undevts--;
959 	}
960 
961 	/* allocate unique */
962 	udevts = kmem_alloc(undevts * sizeof (dev_t), KM_SLEEP);
963 
964 	/* copy unique */
965 	udevts[0] = devts[0];
966 	for (i = 1, j = 1; i < ndevts; i++) {
967 		if (devts[i - 1] != devts[i])
968 			udevts[j++] = devts[i];
969 	}
970 	ASSERT(j == undevts);
971 
972 	kmem_free(devts, ndevts_alloced * sizeof (dev_t));
973 
974 	*retndevts = undevts;
975 	*retdevts = udevts;
976 
977 	return (DDI_SUCCESS);
978 }
979 
980 void
981 e_devid_cache_free_devt_list(int ndevts, dev_t *devt_list)
982 {
983 	kmem_free(devt_list, ndevts * sizeof (dev_t *));
984 }
985 
986 #ifdef	DEBUG
987 static void
988 devid_log(char *fmt, ddi_devid_t devid, char *path)
989 {
990 	char *devidstr = ddi_devid_str_encode(devid, NULL);
991 	if (path) {
992 		cmn_err(CE_CONT, "%s: %s %s\n", fmt, path, devidstr);
993 	} else {
994 		cmn_err(CE_CONT, "%s: %s\n", fmt, devidstr);
995 	}
996 	ddi_devid_str_free(devidstr);
997 }
998 #endif	/* DEBUG */
999