xref: /illumos-gate/usr/src/uts/common/os/devid_cache.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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