xref: /titanic_41/usr/src/lib/libdiskmgt/common/cache.c (revision 3e1bd7a2aaeb6188caef90679b98088cfef1edc6)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*3e1bd7a2Ssjelinek  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <fcntl.h>
307c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <synch.h>
357c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
367c478bd9Sstevel@tonic-gate #include <sys/types.h>
377c478bd9Sstevel@tonic-gate #include <libgen.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #include "libdiskmgt.h"
407c478bd9Sstevel@tonic-gate #include "disks_private.h"
417c478bd9Sstevel@tonic-gate #include "partition.h"
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #define	ALIASES		0
447c478bd9Sstevel@tonic-gate #define	DEVPATHS	1
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate  * Set DM_LIBDISKMGT_DEBUG in the environment.  Two levels of debugging:
487c478bd9Sstevel@tonic-gate  *    1 - errors, warnings and minimal tracing information
497c478bd9Sstevel@tonic-gate  *    2 - verbose information
507c478bd9Sstevel@tonic-gate  * All output prints on stderr.
517c478bd9Sstevel@tonic-gate  */
527c478bd9Sstevel@tonic-gate int dm_debug = 0;
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /* Lock protecting the cached data */
557c478bd9Sstevel@tonic-gate static rwlock_t		cache_lock = DEFAULTRWLOCK;
567c478bd9Sstevel@tonic-gate static disk_t		*disk_listp = NULL;
577c478bd9Sstevel@tonic-gate static controller_t	*controller_listp = NULL;
587c478bd9Sstevel@tonic-gate static bus_t		*bus_listp = NULL;
597c478bd9Sstevel@tonic-gate static int		cache_loaded = 0;
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate descriptor_t		*desc_listp = NULL;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate static void		clear_descriptors(void *gp);
647c478bd9Sstevel@tonic-gate static void		clr_ctrl_disk_ptr(controller_t *cp, disk_t *dp);
657c478bd9Sstevel@tonic-gate static void		clr_path_disk_ptr(path_t *pp, disk_t *dp);
667c478bd9Sstevel@tonic-gate static void		del_drive(disk_t *dp);
677c478bd9Sstevel@tonic-gate static void		del_drive_by_name(char *name);
687c478bd9Sstevel@tonic-gate static descriptor_t	*have_desc(int type, void *gp, char *name, char *mname);
697c478bd9Sstevel@tonic-gate static int		initialize();
707c478bd9Sstevel@tonic-gate static int		make_descriptors(int type);
717c478bd9Sstevel@tonic-gate static int		match_disk(disk_t *oldp, disk_t *newp);
727c478bd9Sstevel@tonic-gate static int		match_aliases(disk_t *d1p, disk_t *d2p);
737c478bd9Sstevel@tonic-gate static int		match_alias(alias_t *ap, alias_t *listp);
747c478bd9Sstevel@tonic-gate static descriptor_t	*new_descriptor(dm_desc_type_t type, void *op,
757c478bd9Sstevel@tonic-gate 			    char *name, char *mname);
767c478bd9Sstevel@tonic-gate static void		rewalk_tree();
777c478bd9Sstevel@tonic-gate static void		update_desc(descriptor_t *descp, disk_t *newdisksp,
787c478bd9Sstevel@tonic-gate 			    controller_t *newctrlp, bus_t *newbusp);
797c478bd9Sstevel@tonic-gate static void		update_desc_busp(descriptor_t *descp, bus_t *busp);
807c478bd9Sstevel@tonic-gate static void		update_desc_ctrlp(descriptor_t *descp,
817c478bd9Sstevel@tonic-gate 			    controller_t *newstrlp);
827c478bd9Sstevel@tonic-gate static void		update_desc_diskp(descriptor_t *descp,
837c478bd9Sstevel@tonic-gate 			    disk_t *newdisksp);
847c478bd9Sstevel@tonic-gate static void		update_desc_pathp(descriptor_t *descp,
857c478bd9Sstevel@tonic-gate 			    controller_t *newctrlp);
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate  * We only cache some of the data that we can obtain.  For much of the data
897c478bd9Sstevel@tonic-gate  * (e.g. slices & disks getting repartitioned) there are no events which would
907c478bd9Sstevel@tonic-gate  * enable us to cache.  As more events are added we can cache more information.
917c478bd9Sstevel@tonic-gate  *
927c478bd9Sstevel@tonic-gate  * Currently we cache the information we get from the dev tree walk.  This is
937c478bd9Sstevel@tonic-gate  * basically the information about the drives, aliases, devpaths, controllers
947c478bd9Sstevel@tonic-gate  * and paths.  We do not cache any information related to media, partitions
957c478bd9Sstevel@tonic-gate  * or slices.
967c478bd9Sstevel@tonic-gate  *
977c478bd9Sstevel@tonic-gate  * A fundamental part of the API design is that the application can hold on
987c478bd9Sstevel@tonic-gate  * to a set of descriptors for an indeterminate amount of time.  Even if the
997c478bd9Sstevel@tonic-gate  * application does not hold descriptors there is a window of time between the
1007c478bd9Sstevel@tonic-gate  * call that gets the descriptor and the use of the descriptor to get more
1017c478bd9Sstevel@tonic-gate  * information.  Because of this, the cache design must work even if the object
1027c478bd9Sstevel@tonic-gate  * that the descriptor refers to no longer exists.
1037c478bd9Sstevel@tonic-gate  *
1047c478bd9Sstevel@tonic-gate  * Given this requirement, the code implements a two level cache.  The
1057c478bd9Sstevel@tonic-gate  * descriptors that the application gets are really pointers into the first
1067c478bd9Sstevel@tonic-gate  * level of the cache.  This first level contains the actual descriptors.
1077c478bd9Sstevel@tonic-gate  * These descriptors in turn refer to the objects we build from the dev tree
1087c478bd9Sstevel@tonic-gate  * walk which represent the drives and controllers.  This is the second level
1097c478bd9Sstevel@tonic-gate  * in the cache.
1107c478bd9Sstevel@tonic-gate  *
1117c478bd9Sstevel@tonic-gate  * When we update the second level of the cache (the drives and controllers)
1127c478bd9Sstevel@tonic-gate  * we go through the first level (the descriptors) and update the pointers
1137c478bd9Sstevel@tonic-gate  * in those descriptors to refer to the new objects in the second level.  If
1147c478bd9Sstevel@tonic-gate  * the object that the descriptor referred to is no longer in existence, we
1157c478bd9Sstevel@tonic-gate  * just null out the pointer in the descriptor.  In this way the code that
1167c478bd9Sstevel@tonic-gate  * uses the descriptors knows that the object referred to by the descriptor
1177c478bd9Sstevel@tonic-gate  * no longer exists.
1187c478bd9Sstevel@tonic-gate  *
1197c478bd9Sstevel@tonic-gate  * We keep a reference count in the descriptors.  This is incremented when
1207c478bd9Sstevel@tonic-gate  * we hand out a pointer to the descriptor and decremented when the application
1217c478bd9Sstevel@tonic-gate  * frees the descriptor it has.  When the reference count goes to 0 we garbage
1227c478bd9Sstevel@tonic-gate  * collect the descriptors.  In this way we only have to update active
1237c478bd9Sstevel@tonic-gate  * descriptors when we refresh the cache after an event.
1247c478bd9Sstevel@tonic-gate  *
1257c478bd9Sstevel@tonic-gate  * An example of the flow when we create descriptors:
1267c478bd9Sstevel@tonic-gate  *    dm_get_descriptors			libdiskmgt.c
1277c478bd9Sstevel@tonic-gate  *	drive_get_descriptors			drive.c
1287c478bd9Sstevel@tonic-gate  *	    cache_get_descriptors		cache.c
1297c478bd9Sstevel@tonic-gate  *		make_descriptors		cache.c
1307c478bd9Sstevel@tonic-gate  *		    drive_make_descriptors	drive.c
1317c478bd9Sstevel@tonic-gate  *			cache_load_desc		cache.c
1327c478bd9Sstevel@tonic-gate  *		{update refcnts on descriptors & return them}
1337c478bd9Sstevel@tonic-gate  *
1347c478bd9Sstevel@tonic-gate  * The idea behind cache_get_descriptors and cache_load_desc is that we
1357c478bd9Sstevel@tonic-gate  * seperate the act of making the descriptor within the cache (which requires
1367c478bd9Sstevel@tonic-gate  * us to call back out to one of the object functions - drive_make_descriptors)
1377c478bd9Sstevel@tonic-gate  * from the act of handing out the descriptor (which requires us to increment
1387c478bd9Sstevel@tonic-gate  * the refcnt).  In this way we keep all of the refcnt handling centralized
1397c478bd9Sstevel@tonic-gate  * in one function instead of forcing each object to ensure it replicates
1407c478bd9Sstevel@tonic-gate  * the refcnt handling correctly.
1417c478bd9Sstevel@tonic-gate  *
1427c478bd9Sstevel@tonic-gate  * Descriptors use two different kinds of indrection to refer to their
1437c478bd9Sstevel@tonic-gate  * corresponding object.  For objects we cache (controllers, paths & drives)
1447c478bd9Sstevel@tonic-gate  * the descriptor keeps a pointer to that object.  For objects that we
1457c478bd9Sstevel@tonic-gate  * dynamically build, the descriptor uses a combination of a pointer to the
1467c478bd9Sstevel@tonic-gate  * base object (usually the drive) along with a name (e.g. the media name or
1477c478bd9Sstevel@tonic-gate  * the alias).  For objects that are based on media (e.g. a slice) we actually
1487c478bd9Sstevel@tonic-gate  * have to maintain a pointer (to the disk) and two names (e.g. the slice name
1497c478bd9Sstevel@tonic-gate  * and the media name which is the secondary name).
1507c478bd9Sstevel@tonic-gate  */
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate void
1537c478bd9Sstevel@tonic-gate cache_free_alias(alias_t *aliasp)
1547c478bd9Sstevel@tonic-gate {
1557c478bd9Sstevel@tonic-gate 	slice_t	*dp;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	free(aliasp->alias);
1587c478bd9Sstevel@tonic-gate 	free(aliasp->kstat_name);
1597c478bd9Sstevel@tonic-gate 	free(aliasp->wwn);
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	/* free devpaths */
1627c478bd9Sstevel@tonic-gate 	dp = aliasp->devpaths;
1637c478bd9Sstevel@tonic-gate 	while (dp != NULL) {
1647c478bd9Sstevel@tonic-gate 	    slice_t	*nextp;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	    nextp = dp->next;
1677c478bd9Sstevel@tonic-gate 	    free(dp->devpath);
1687c478bd9Sstevel@tonic-gate 	    free(dp);
1697c478bd9Sstevel@tonic-gate 	    dp = nextp;
1707c478bd9Sstevel@tonic-gate 	}
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	/* free orig_paths */
1737c478bd9Sstevel@tonic-gate 	dp = aliasp->orig_paths;
1747c478bd9Sstevel@tonic-gate 	while (dp != NULL) {
1757c478bd9Sstevel@tonic-gate 	    slice_t	*nextp;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	    nextp = dp->next;
1787c478bd9Sstevel@tonic-gate 	    free(dp->devpath);
1797c478bd9Sstevel@tonic-gate 	    free(dp);
1807c478bd9Sstevel@tonic-gate 	    dp = nextp;
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	free(aliasp);
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate void
1877c478bd9Sstevel@tonic-gate cache_free_bus(bus_t *bp)
1887c478bd9Sstevel@tonic-gate {
1897c478bd9Sstevel@tonic-gate 	free(bp->name);
1907c478bd9Sstevel@tonic-gate 	free(bp->btype);
1917c478bd9Sstevel@tonic-gate 	free(bp->kstat_name);
1927c478bd9Sstevel@tonic-gate 	free(bp->pname);
1937c478bd9Sstevel@tonic-gate 	free(bp->controllers);
1947c478bd9Sstevel@tonic-gate 	free(bp);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate void
1987c478bd9Sstevel@tonic-gate cache_free_controller(controller_t *cp)
1997c478bd9Sstevel@tonic-gate {
2007c478bd9Sstevel@tonic-gate 	free(cp->name);
2017c478bd9Sstevel@tonic-gate 	free(cp->kstat_name);
2027c478bd9Sstevel@tonic-gate 	free(cp->disks);
2037c478bd9Sstevel@tonic-gate 	if (cp->paths != NULL) {
2047c478bd9Sstevel@tonic-gate 	    int i;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	    for (i = 0; cp->paths[i]; i++) {
2077c478bd9Sstevel@tonic-gate 		/* free the path since it can't exist w/o the controller */
2087c478bd9Sstevel@tonic-gate 		cache_free_path(cp->paths[i]);
2097c478bd9Sstevel@tonic-gate 	    }
2107c478bd9Sstevel@tonic-gate 	    free(cp->paths);
2117c478bd9Sstevel@tonic-gate 	}
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	free(cp);
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate void
2177c478bd9Sstevel@tonic-gate cache_free_descriptor(descriptor_t *desc)
2187c478bd9Sstevel@tonic-gate {
2197c478bd9Sstevel@tonic-gate 	if (!cache_is_valid_desc(desc)) {
2207c478bd9Sstevel@tonic-gate 	    return;
2217c478bd9Sstevel@tonic-gate 	}
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	desc->refcnt--;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	if (desc->refcnt <= 0) {
2267c478bd9Sstevel@tonic-gate 	    free(desc->name);
2277c478bd9Sstevel@tonic-gate 	    free(desc->secondary_name);
2287c478bd9Sstevel@tonic-gate 	    if (desc->prev == NULL) {
2297c478bd9Sstevel@tonic-gate 		/* this is the first descriptor, update head ptr */
2307c478bd9Sstevel@tonic-gate 		desc_listp = desc->next;
2317c478bd9Sstevel@tonic-gate 	    } else {
2327c478bd9Sstevel@tonic-gate 		desc->prev->next = desc->next;
2337c478bd9Sstevel@tonic-gate 	    }
2347c478bd9Sstevel@tonic-gate 	    if (desc->next != NULL) {
2357c478bd9Sstevel@tonic-gate 		desc->next->prev = desc->prev;
2367c478bd9Sstevel@tonic-gate 	    }
2377c478bd9Sstevel@tonic-gate 	    free(desc);
2387c478bd9Sstevel@tonic-gate 	}
2397c478bd9Sstevel@tonic-gate }
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate void
2427c478bd9Sstevel@tonic-gate cache_free_descriptors(descriptor_t **desc_list)
2437c478bd9Sstevel@tonic-gate {
2447c478bd9Sstevel@tonic-gate 	int i;
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	for (i = 0; desc_list[i]; i++) {
2477c478bd9Sstevel@tonic-gate 	    cache_free_descriptor(desc_list[i]);
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	free(desc_list);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate void
2547c478bd9Sstevel@tonic-gate cache_free_disk(disk_t *dp)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	alias_t	*ap;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	free(dp->device_id);
2597c478bd9Sstevel@tonic-gate 	if (dp->devid != NULL) {
2607c478bd9Sstevel@tonic-gate 	    devid_free(dp->devid);
2617c478bd9Sstevel@tonic-gate 	}
2627c478bd9Sstevel@tonic-gate 	free(dp->kernel_name);
2637c478bd9Sstevel@tonic-gate 	free(dp->product_id);
2647c478bd9Sstevel@tonic-gate 	free(dp->vendor_id);
2657c478bd9Sstevel@tonic-gate 	free(dp->controllers);
2667c478bd9Sstevel@tonic-gate 	/* the path objects are freed when we free the controller */
2677c478bd9Sstevel@tonic-gate 	free(dp->paths);
2687c478bd9Sstevel@tonic-gate 	ap = dp->aliases;
2697c478bd9Sstevel@tonic-gate 	while (ap != NULL) {
2707c478bd9Sstevel@tonic-gate 	    alias_t	*nextp;
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	    nextp = ap->next;
2737c478bd9Sstevel@tonic-gate 	    cache_free_alias(ap);
2747c478bd9Sstevel@tonic-gate 	    ap = nextp;
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	free(dp);
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate void
2817c478bd9Sstevel@tonic-gate cache_free_path(path_t *pp)
2827c478bd9Sstevel@tonic-gate {
2837c478bd9Sstevel@tonic-gate 	int i;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	free(pp->name);
2867c478bd9Sstevel@tonic-gate 	free(pp->disks);
2877c478bd9Sstevel@tonic-gate 	free(pp->states);
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	for (i = 0; pp->wwns[i]; i++) {
2907c478bd9Sstevel@tonic-gate 	    free(pp->wwns[i]);
2917c478bd9Sstevel@tonic-gate 	}
2927c478bd9Sstevel@tonic-gate 	free(pp->wwns);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	free(pp);
2957c478bd9Sstevel@tonic-gate }
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate bus_t *
2987c478bd9Sstevel@tonic-gate cache_get_buslist()
2997c478bd9Sstevel@tonic-gate {
3007c478bd9Sstevel@tonic-gate 	if (initialize() != 0) {
3017c478bd9Sstevel@tonic-gate 	    return (NULL);
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	return (bus_listp);
3057c478bd9Sstevel@tonic-gate }
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate controller_t *
3087c478bd9Sstevel@tonic-gate cache_get_controllerlist()
3097c478bd9Sstevel@tonic-gate {
3107c478bd9Sstevel@tonic-gate 	if (initialize() != 0) {
3117c478bd9Sstevel@tonic-gate 	    return (NULL);
3127c478bd9Sstevel@tonic-gate 	}
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	return (controller_listp);
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate /*
3187c478bd9Sstevel@tonic-gate  * This routine will either get the existing descriptor from the descriptor
3197c478bd9Sstevel@tonic-gate  * cache or make make a new descriptor and put it in the descriptor cache and
3207c478bd9Sstevel@tonic-gate  * return a pointer to that descriptor.  We increment the refcnt when we hand
3217c478bd9Sstevel@tonic-gate  * out the descriptor.
3227c478bd9Sstevel@tonic-gate  */
3237c478bd9Sstevel@tonic-gate descriptor_t *
3247c478bd9Sstevel@tonic-gate cache_get_desc(int type, void *gp, char *name, char *secondary_name, int *errp)
3257c478bd9Sstevel@tonic-gate {
3267c478bd9Sstevel@tonic-gate 	descriptor_t	*dp;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	*errp = 0;
3297c478bd9Sstevel@tonic-gate 	if ((dp = have_desc(type, gp, name, secondary_name)) == NULL) {
3307c478bd9Sstevel@tonic-gate 	    /* make a new desc */
3317c478bd9Sstevel@tonic-gate 	    if ((dp = new_descriptor(type, gp, name, secondary_name)) == NULL) {
3327c478bd9Sstevel@tonic-gate 		*errp = ENOMEM;
3337c478bd9Sstevel@tonic-gate 	    }
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	if (dp != NULL) {
3377c478bd9Sstevel@tonic-gate 	    dp->refcnt++;
3387c478bd9Sstevel@tonic-gate 	}
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	return (dp);
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate descriptor_t **
3447c478bd9Sstevel@tonic-gate cache_get_descriptors(int type, int *errp)
3457c478bd9Sstevel@tonic-gate {
3467c478bd9Sstevel@tonic-gate 	descriptor_t	**descs;
3477c478bd9Sstevel@tonic-gate 	descriptor_t	*descp;
3487c478bd9Sstevel@tonic-gate 	int		cnt = 0;
3497c478bd9Sstevel@tonic-gate 	int		pos;
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	if ((*errp = make_descriptors(type)) != 0) {
3527c478bd9Sstevel@tonic-gate 	    return (NULL);
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	/* count the number of active descriptors in the descriptor cache */
3567c478bd9Sstevel@tonic-gate 	descp = desc_listp;
3577c478bd9Sstevel@tonic-gate 	while (descp != NULL) {
3587c478bd9Sstevel@tonic-gate 	    if (descp->type == type && descp->p.generic != NULL) {
3597c478bd9Sstevel@tonic-gate 		cnt++;
3607c478bd9Sstevel@tonic-gate 	    }
3617c478bd9Sstevel@tonic-gate 	    descp = descp->next;
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	descs = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
3657c478bd9Sstevel@tonic-gate 	if (descs == NULL) {
3667c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
3677c478bd9Sstevel@tonic-gate 	    return (NULL);
3687c478bd9Sstevel@tonic-gate 	}
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	pos = 0;
3717c478bd9Sstevel@tonic-gate 	descp = desc_listp;
3727c478bd9Sstevel@tonic-gate 	while (descp != NULL) {
3737c478bd9Sstevel@tonic-gate 	    if (descp->type == type && descp->p.generic != NULL) {
3747c478bd9Sstevel@tonic-gate 		/* update refcnts before handing out the descriptors */
3757c478bd9Sstevel@tonic-gate 		descp->refcnt++;
3767c478bd9Sstevel@tonic-gate 		descs[pos++] = descp;
3777c478bd9Sstevel@tonic-gate 	    }
3787c478bd9Sstevel@tonic-gate 	    descp = descp->next;
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate 	descs[pos] = NULL;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	*errp = 0;
3837c478bd9Sstevel@tonic-gate 	return (descs);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate disk_t *
3877c478bd9Sstevel@tonic-gate cache_get_disklist()
3887c478bd9Sstevel@tonic-gate {
3897c478bd9Sstevel@tonic-gate 	if (initialize() != 0) {
3907c478bd9Sstevel@tonic-gate 	    return (NULL);
3917c478bd9Sstevel@tonic-gate 	}
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	return (disk_listp);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate int
3977c478bd9Sstevel@tonic-gate cache_is_valid_desc(descriptor_t *d)
3987c478bd9Sstevel@tonic-gate {
3997c478bd9Sstevel@tonic-gate 	descriptor_t	*descp;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	for (descp = desc_listp; descp != NULL; descp = descp->next) {
4027c478bd9Sstevel@tonic-gate 	    if (descp == d) {
4037c478bd9Sstevel@tonic-gate 		return (1);
4047c478bd9Sstevel@tonic-gate 	    }
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	return (0);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate /*
4117c478bd9Sstevel@tonic-gate  * This function is called by the *_make_descriptors function
4127c478bd9Sstevel@tonic-gate  * (e.g. drive_make_descriptors) within each of the objects.  This function
4137c478bd9Sstevel@tonic-gate  * makes sure that the descriptor is built in the descriptor cache but
4147c478bd9Sstevel@tonic-gate  * it does not hand out the descriptors, so the refcnt is never incremented.
4157c478bd9Sstevel@tonic-gate  */
4167c478bd9Sstevel@tonic-gate void
4177c478bd9Sstevel@tonic-gate cache_load_desc(int type, void *gp, char *name, char *secondary_name, int *errp)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate 	*errp = 0;
4207c478bd9Sstevel@tonic-gate 	if (have_desc(type, gp, name, secondary_name) == NULL) {
4217c478bd9Sstevel@tonic-gate 	    /* make a new desc */
4227c478bd9Sstevel@tonic-gate 	    if (new_descriptor(type, gp, name, secondary_name) == NULL) {
4237c478bd9Sstevel@tonic-gate 		*errp = ENOMEM;
4247c478bd9Sstevel@tonic-gate 	    }
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate }
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate void
4297c478bd9Sstevel@tonic-gate cache_rlock()
4307c478bd9Sstevel@tonic-gate {
4317c478bd9Sstevel@tonic-gate 	(void) rw_rdlock(&cache_lock);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate void
4357c478bd9Sstevel@tonic-gate cache_unlock()
4367c478bd9Sstevel@tonic-gate {
4377c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&cache_lock);
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate /*
4417c478bd9Sstevel@tonic-gate  * This function is called when we get a devtree event.  Type is either add
4427c478bd9Sstevel@tonic-gate  * or delete of a drive.
4437c478bd9Sstevel@tonic-gate  *
4447c478bd9Sstevel@tonic-gate  * For delete, we need to clean up the 2nd level structures and clean up
4457c478bd9Sstevel@tonic-gate  * the pointers between the them.  We also clear the descriptor ptr.
4467c478bd9Sstevel@tonic-gate  */
4477c478bd9Sstevel@tonic-gate void
4487c478bd9Sstevel@tonic-gate cache_update(dm_event_type_t ev_type, char *devname)
4497c478bd9Sstevel@tonic-gate {
4507c478bd9Sstevel@tonic-gate 	char *orig_name;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	cache_wlock();
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	/* update the cache */
4557c478bd9Sstevel@tonic-gate 	switch (ev_type) {
4567c478bd9Sstevel@tonic-gate 	case DM_EV_DISK_ADD:
4577c478bd9Sstevel@tonic-gate 	    rewalk_tree();
4587c478bd9Sstevel@tonic-gate 	    events_new_event(devname, DM_DRIVE, DM_EV_TADD);
4597c478bd9Sstevel@tonic-gate 	    break;
4607c478bd9Sstevel@tonic-gate 	case DM_EV_DISK_DELETE:
4617c478bd9Sstevel@tonic-gate 	    orig_name = devname;
4627c478bd9Sstevel@tonic-gate 	    devname = basename(devname);
4637c478bd9Sstevel@tonic-gate 	    del_drive_by_name(devname);
4647c478bd9Sstevel@tonic-gate 	    events_new_event(orig_name, DM_DRIVE, DM_EV_TREMOVE);
4657c478bd9Sstevel@tonic-gate 	    break;
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	cache_unlock();
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate void
4727c478bd9Sstevel@tonic-gate cache_wlock()
4737c478bd9Sstevel@tonic-gate {
4747c478bd9Sstevel@tonic-gate 	(void) rw_wrlock(&cache_lock);
4757c478bd9Sstevel@tonic-gate }
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate /*
4787c478bd9Sstevel@tonic-gate  * Clear any descriptors that point at the specified cached object.
4797c478bd9Sstevel@tonic-gate  * We must go through the whole list since there can be multiple descriptors
4807c478bd9Sstevel@tonic-gate  * referencing the same object (i.e. drive/media/slice descriptors all point
4817c478bd9Sstevel@tonic-gate  * to the same drive object).  The list is usually small (0 size) so this
4827c478bd9Sstevel@tonic-gate  * is not a big deal.
4837c478bd9Sstevel@tonic-gate  */
4847c478bd9Sstevel@tonic-gate static void
4857c478bd9Sstevel@tonic-gate clear_descriptors(void *gp)
4867c478bd9Sstevel@tonic-gate {
4877c478bd9Sstevel@tonic-gate 	descriptor_t	*descp;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	for (descp = desc_listp; descp != NULL; descp = descp->next) {
4907c478bd9Sstevel@tonic-gate 	    if (descp->p.generic == gp) {
4917c478bd9Sstevel@tonic-gate 		/* clear descriptor */
4927c478bd9Sstevel@tonic-gate 		descp->p.generic = NULL;
4937c478bd9Sstevel@tonic-gate 	    }
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate /* remove the ptr from the controller to the specified disk */
4987c478bd9Sstevel@tonic-gate static void
4997c478bd9Sstevel@tonic-gate clr_ctrl_disk_ptr(controller_t *cp, disk_t *dp)
5007c478bd9Sstevel@tonic-gate {
5017c478bd9Sstevel@tonic-gate 	int i;
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	for (i = 0; cp->disks[i]; i++) {
5047c478bd9Sstevel@tonic-gate 	    if (dp == cp->disks[i]) {
5057c478bd9Sstevel@tonic-gate 		int j;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 		for (j = i; cp->disks[j]; j++) {
5087c478bd9Sstevel@tonic-gate 		    cp->disks[j] = cp->disks[j + 1];
5097c478bd9Sstevel@tonic-gate 		}
5107c478bd9Sstevel@tonic-gate 		return;
5117c478bd9Sstevel@tonic-gate 	    }
5127c478bd9Sstevel@tonic-gate 	}
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate /* remove the ptr from the path to the specified disk */
5167c478bd9Sstevel@tonic-gate static void
5177c478bd9Sstevel@tonic-gate clr_path_disk_ptr(path_t *pp, disk_t *dp)
5187c478bd9Sstevel@tonic-gate {
5197c478bd9Sstevel@tonic-gate 	int i;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	for (i = 0; pp->disks[i]; i++) {
5227c478bd9Sstevel@tonic-gate 	    if (dp == pp->disks[i]) {
5237c478bd9Sstevel@tonic-gate 		int j;
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 		for (j = i; pp->disks[j]; j++) {
5267c478bd9Sstevel@tonic-gate 		    pp->disks[j] = pp->disks[j + 1];
5277c478bd9Sstevel@tonic-gate 		}
5287c478bd9Sstevel@tonic-gate 		return;
5297c478bd9Sstevel@tonic-gate 	    }
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate static void
5347c478bd9Sstevel@tonic-gate del_drive(disk_t *dp)
5357c478bd9Sstevel@tonic-gate {
5367c478bd9Sstevel@tonic-gate 	int	i;
5377c478bd9Sstevel@tonic-gate 	disk_t	*listp;
5387c478bd9Sstevel@tonic-gate 	disk_t	*prev = NULL;
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	clear_descriptors(dp);
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	/* clear any ptrs from controllers to this drive */
5437c478bd9Sstevel@tonic-gate 	if (dp->controllers != NULL) {
5447c478bd9Sstevel@tonic-gate 	    for (i = 0; dp->controllers[i]; i++) {
5457c478bd9Sstevel@tonic-gate 		clr_ctrl_disk_ptr(dp->controllers[i], dp);
5467c478bd9Sstevel@tonic-gate 	    }
5477c478bd9Sstevel@tonic-gate 	}
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	/* clear any ptrs from paths to this drive */
5507c478bd9Sstevel@tonic-gate 	if (dp->paths != NULL) {
5517c478bd9Sstevel@tonic-gate 	    for (i = 0; dp->paths[i]; i++) {
5527c478bd9Sstevel@tonic-gate 		clr_path_disk_ptr(dp->paths[i], dp);
5537c478bd9Sstevel@tonic-gate 	    }
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	/* clear drive from disk list */
5577c478bd9Sstevel@tonic-gate 	for (listp = disk_listp; listp != NULL; listp = listp->next) {
5587c478bd9Sstevel@tonic-gate 	    if (dp == listp) {
5597c478bd9Sstevel@tonic-gate 		if (prev == NULL) {
5607c478bd9Sstevel@tonic-gate 		    disk_listp = dp->next;
5617c478bd9Sstevel@tonic-gate 		} else {
5627c478bd9Sstevel@tonic-gate 		    prev->next = dp->next;
5637c478bd9Sstevel@tonic-gate 		}
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 		break;
5667c478bd9Sstevel@tonic-gate 	    }
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	    if (prev == NULL) {
5697c478bd9Sstevel@tonic-gate 		prev = disk_listp;
5707c478bd9Sstevel@tonic-gate 	    } else {
5717c478bd9Sstevel@tonic-gate 		prev = prev->next;
5727c478bd9Sstevel@tonic-gate 	    }
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	cache_free_disk(dp);
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate /*
5797c478bd9Sstevel@tonic-gate  * Delete cached drive info when we get a devtree drive delete event.
5807c478bd9Sstevel@tonic-gate  */
5817c478bd9Sstevel@tonic-gate static void
5827c478bd9Sstevel@tonic-gate del_drive_by_name(char *name)
5837c478bd9Sstevel@tonic-gate {
5847c478bd9Sstevel@tonic-gate 	disk_t	*listp;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	for (listp = disk_listp; listp != NULL; listp = listp->next) {
5877c478bd9Sstevel@tonic-gate 	    alias_t	*ap;
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	    for (ap = listp->aliases; ap; ap = ap->next) {
5907c478bd9Sstevel@tonic-gate 		if (libdiskmgt_str_eq(name, ap->alias)) {
5917c478bd9Sstevel@tonic-gate 		    del_drive(listp);
5927c478bd9Sstevel@tonic-gate 		    return;
5937c478bd9Sstevel@tonic-gate 		}
5947c478bd9Sstevel@tonic-gate 	    }
5957c478bd9Sstevel@tonic-gate 	}
5967c478bd9Sstevel@tonic-gate }
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate static descriptor_t *
5997c478bd9Sstevel@tonic-gate have_desc(int type, void *gp, char *name, char *secondary_name)
6007c478bd9Sstevel@tonic-gate {
6017c478bd9Sstevel@tonic-gate 	descriptor_t	*descp;
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	if (name != NULL && name[0] == 0) {
6047c478bd9Sstevel@tonic-gate 	    name = NULL;
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	if (secondary_name != NULL && secondary_name[0] == 0) {
6087c478bd9Sstevel@tonic-gate 	    secondary_name = NULL;
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	descp = desc_listp;
6127c478bd9Sstevel@tonic-gate 	while (descp != NULL) {
6137c478bd9Sstevel@tonic-gate 	    if (descp->type == type && descp->p.generic == gp &&
6147c478bd9Sstevel@tonic-gate 		libdiskmgt_str_eq(descp->name, name)) {
6157c478bd9Sstevel@tonic-gate 		if (type == DM_SLICE || type == DM_PARTITION ||
6167c478bd9Sstevel@tonic-gate 		    type == DM_PATH) {
6177c478bd9Sstevel@tonic-gate 		    if (libdiskmgt_str_eq(descp->secondary_name,
6187c478bd9Sstevel@tonic-gate 			secondary_name)) {
6197c478bd9Sstevel@tonic-gate 			return (descp);
6207c478bd9Sstevel@tonic-gate 		    }
6217c478bd9Sstevel@tonic-gate 		} else {
6227c478bd9Sstevel@tonic-gate 		    return (descp);
6237c478bd9Sstevel@tonic-gate 		}
6247c478bd9Sstevel@tonic-gate 	    }
6257c478bd9Sstevel@tonic-gate 	    descp = descp->next;
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	return (NULL);
6297c478bd9Sstevel@tonic-gate }
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate static int
6327c478bd9Sstevel@tonic-gate initialize()
6337c478bd9Sstevel@tonic-gate {
6347c478bd9Sstevel@tonic-gate 	struct search_args	args;
6357c478bd9Sstevel@tonic-gate 	int			status;
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	if (cache_loaded) {
6387c478bd9Sstevel@tonic-gate 	    return (0);
6397c478bd9Sstevel@tonic-gate 	}
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	libdiskmgt_init_debug();
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	findevs(&args);
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	if (args.dev_walk_status != 0) {
6467c478bd9Sstevel@tonic-gate 	    return (args.dev_walk_status);
6477c478bd9Sstevel@tonic-gate 	}
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	disk_listp = args.disk_listp;
6507c478bd9Sstevel@tonic-gate 	controller_listp = args.controller_listp;
6517c478bd9Sstevel@tonic-gate 	bus_listp = args.bus_listp;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	cache_loaded = 1;
6547c478bd9Sstevel@tonic-gate 
655*3e1bd7a2Ssjelinek 	/*
656*3e1bd7a2Ssjelinek 	 * Only start the event thread if we are not doing an install
657*3e1bd7a2Ssjelinek 	 */
658*3e1bd7a2Ssjelinek 	if (getenv("_LIBDISKMGT_INSTALL") == NULL) {
6597c478bd9Sstevel@tonic-gate 		if ((status = events_start_event_watcher()) != 0) {
6607c478bd9Sstevel@tonic-gate 			return (status);
6617c478bd9Sstevel@tonic-gate 		}
662*3e1bd7a2Ssjelinek 	}
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	return (0);
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate static int
6687c478bd9Sstevel@tonic-gate make_descriptors(int type)
6697c478bd9Sstevel@tonic-gate {
6707c478bd9Sstevel@tonic-gate 	int	error;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	if ((error = initialize()) != 0) {
6737c478bd9Sstevel@tonic-gate 	    return (error);
6747c478bd9Sstevel@tonic-gate 	}
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	switch (type) {
6777c478bd9Sstevel@tonic-gate 	case DM_DRIVE:
6787c478bd9Sstevel@tonic-gate 	    error = drive_make_descriptors();
6797c478bd9Sstevel@tonic-gate 	    break;
6807c478bd9Sstevel@tonic-gate 	case DM_BUS:
6817c478bd9Sstevel@tonic-gate 	    error = bus_make_descriptors();
6827c478bd9Sstevel@tonic-gate 	    break;
6837c478bd9Sstevel@tonic-gate 	case DM_CONTROLLER:
6847c478bd9Sstevel@tonic-gate 	    error = controller_make_descriptors();
6857c478bd9Sstevel@tonic-gate 	    break;
6867c478bd9Sstevel@tonic-gate 	case DM_PATH:
6877c478bd9Sstevel@tonic-gate 	    error = path_make_descriptors();
6887c478bd9Sstevel@tonic-gate 	    break;
6897c478bd9Sstevel@tonic-gate 	case DM_ALIAS:
6907c478bd9Sstevel@tonic-gate 	    error = alias_make_descriptors();
6917c478bd9Sstevel@tonic-gate 	    break;
6927c478bd9Sstevel@tonic-gate 	case DM_MEDIA:
6937c478bd9Sstevel@tonic-gate 	    error = media_make_descriptors();
6947c478bd9Sstevel@tonic-gate 	    break;
6957c478bd9Sstevel@tonic-gate 	case DM_PARTITION:
6967c478bd9Sstevel@tonic-gate 	    error = partition_make_descriptors();
6977c478bd9Sstevel@tonic-gate 	    break;
6987c478bd9Sstevel@tonic-gate 	case DM_SLICE:
6997c478bd9Sstevel@tonic-gate 	    error = slice_make_descriptors();
7007c478bd9Sstevel@tonic-gate 	    break;
7017c478bd9Sstevel@tonic-gate 	}
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	return (error);
7047c478bd9Sstevel@tonic-gate }
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate static int
7077c478bd9Sstevel@tonic-gate match_alias(alias_t *ap, alias_t *listp)
7087c478bd9Sstevel@tonic-gate {
7097c478bd9Sstevel@tonic-gate 	if (ap->alias == NULL) {
7107c478bd9Sstevel@tonic-gate 	    return (0);
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	while (listp != NULL) {
7147c478bd9Sstevel@tonic-gate 	    if (libdiskmgt_str_eq(ap->alias, listp->alias)) {
7157c478bd9Sstevel@tonic-gate 		return (1);
7167c478bd9Sstevel@tonic-gate 	    }
7177c478bd9Sstevel@tonic-gate 	    listp = listp->next;
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	return (0);
7217c478bd9Sstevel@tonic-gate }
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate static int
7247c478bd9Sstevel@tonic-gate match_aliases(disk_t *d1p, disk_t *d2p)
7257c478bd9Sstevel@tonic-gate {
7267c478bd9Sstevel@tonic-gate 	alias_t *ap;
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 	if (d1p->aliases == NULL || d2p->aliases == NULL) {
7297c478bd9Sstevel@tonic-gate 	    return (0);
7307c478bd9Sstevel@tonic-gate 	}
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	ap = d1p->aliases;
7337c478bd9Sstevel@tonic-gate 	while (ap != NULL) {
7347c478bd9Sstevel@tonic-gate 	    if (match_alias(ap, d2p->aliases)) {
7357c478bd9Sstevel@tonic-gate 		return (1);
7367c478bd9Sstevel@tonic-gate 	    }
7377c478bd9Sstevel@tonic-gate 	    ap = ap->next;
7387c478bd9Sstevel@tonic-gate 	}
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	return (0);
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate static int
7447c478bd9Sstevel@tonic-gate match_disk(disk_t *oldp, disk_t *newp)
7457c478bd9Sstevel@tonic-gate {
7467c478bd9Sstevel@tonic-gate 	if (oldp->devid != NULL) {
7477c478bd9Sstevel@tonic-gate 	    if (newp->devid != NULL &&
7487c478bd9Sstevel@tonic-gate 		devid_compare(oldp->devid, newp->devid) == 0) {
7497c478bd9Sstevel@tonic-gate 		return (1);
7507c478bd9Sstevel@tonic-gate 	    }
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	} else {
7537c478bd9Sstevel@tonic-gate 	    /* oldp device id is null */
7547c478bd9Sstevel@tonic-gate 	    if (newp->devid == NULL) {
7557c478bd9Sstevel@tonic-gate 		/* both disks have no device id, check aliases */
7567c478bd9Sstevel@tonic-gate 		if (match_aliases(oldp, newp)) {
7577c478bd9Sstevel@tonic-gate 		    return (1);
7587c478bd9Sstevel@tonic-gate 		}
7597c478bd9Sstevel@tonic-gate 	    }
7607c478bd9Sstevel@tonic-gate 	}
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	return (0);
7637c478bd9Sstevel@tonic-gate }
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate static descriptor_t *
7667c478bd9Sstevel@tonic-gate new_descriptor(dm_desc_type_t type, void *op, char *name, char *secondary_name)
7677c478bd9Sstevel@tonic-gate {
7687c478bd9Sstevel@tonic-gate 	descriptor_t	*d;
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	if (name != NULL && name[0] == 0) {
7717c478bd9Sstevel@tonic-gate 	    name = NULL;
7727c478bd9Sstevel@tonic-gate 	}
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	if (secondary_name != NULL && secondary_name[0] == 0) {
7757c478bd9Sstevel@tonic-gate 	    secondary_name = NULL;
7767c478bd9Sstevel@tonic-gate 	}
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	d = (descriptor_t *)malloc(sizeof (descriptor_t));
7797c478bd9Sstevel@tonic-gate 	if (d == NULL) {
7807c478bd9Sstevel@tonic-gate 	    return (NULL);
7817c478bd9Sstevel@tonic-gate 	}
7827c478bd9Sstevel@tonic-gate 	d->type = type;
7837c478bd9Sstevel@tonic-gate 	switch (type) {
7847c478bd9Sstevel@tonic-gate 	case DM_CONTROLLER:
7857c478bd9Sstevel@tonic-gate 	    d->p.controller = op;
7867c478bd9Sstevel@tonic-gate 	    break;
7877c478bd9Sstevel@tonic-gate 	case DM_BUS:
7887c478bd9Sstevel@tonic-gate 	    d->p.bus = op;
7897c478bd9Sstevel@tonic-gate 	    break;
7907c478bd9Sstevel@tonic-gate 	default:
7917c478bd9Sstevel@tonic-gate 	    d->p.disk = op;
7927c478bd9Sstevel@tonic-gate 	    break;
7937c478bd9Sstevel@tonic-gate 	}
7947c478bd9Sstevel@tonic-gate 	if (name != NULL) {
7957c478bd9Sstevel@tonic-gate 	    d->name = strdup(name);
7967c478bd9Sstevel@tonic-gate 	    if (d->name == NULL) {
7977c478bd9Sstevel@tonic-gate 		free(d);
7987c478bd9Sstevel@tonic-gate 		return (NULL);
7997c478bd9Sstevel@tonic-gate 	    }
8007c478bd9Sstevel@tonic-gate 	} else {
8017c478bd9Sstevel@tonic-gate 	    d->name = NULL;
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	if (type == DM_SLICE || type == DM_PARTITION) {
8057c478bd9Sstevel@tonic-gate 	    if (secondary_name != NULL) {
8067c478bd9Sstevel@tonic-gate 		d->secondary_name = strdup(secondary_name);
8077c478bd9Sstevel@tonic-gate 		if (d->secondary_name == NULL) {
8087c478bd9Sstevel@tonic-gate 		    free(d->name);
8097c478bd9Sstevel@tonic-gate 		    free(d);
8107c478bd9Sstevel@tonic-gate 		    return (NULL);
8117c478bd9Sstevel@tonic-gate 		}
8127c478bd9Sstevel@tonic-gate 	    } else {
8137c478bd9Sstevel@tonic-gate 		d->secondary_name = NULL;
8147c478bd9Sstevel@tonic-gate 	    }
8157c478bd9Sstevel@tonic-gate 	} else {
8167c478bd9Sstevel@tonic-gate 	    d->secondary_name = NULL;
8177c478bd9Sstevel@tonic-gate 	}
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	d->refcnt = 0;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	/* add this descriptor to the head of the list */
8227c478bd9Sstevel@tonic-gate 	if (desc_listp != NULL) {
8237c478bd9Sstevel@tonic-gate 	    desc_listp->prev = d;
8247c478bd9Sstevel@tonic-gate 	}
8257c478bd9Sstevel@tonic-gate 	d->prev = NULL;
8267c478bd9Sstevel@tonic-gate 	d->next = desc_listp;
8277c478bd9Sstevel@tonic-gate 	desc_listp = d;
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	return (d);
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate static void
8337c478bd9Sstevel@tonic-gate rewalk_tree()
8347c478bd9Sstevel@tonic-gate {
8357c478bd9Sstevel@tonic-gate 	struct search_args	args;
8367c478bd9Sstevel@tonic-gate 	disk_t			*free_disklistp;
8377c478bd9Sstevel@tonic-gate 	controller_t		*free_controllerlistp;
8387c478bd9Sstevel@tonic-gate 	bus_t			*free_buslistp;
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	findevs(&args);
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	if (args.dev_walk_status == 0) {
8437c478bd9Sstevel@tonic-gate 	    descriptor_t	*descp;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	    /* walk the existing descriptors and update the ptrs */
8467c478bd9Sstevel@tonic-gate 	    descp = desc_listp;
8477c478bd9Sstevel@tonic-gate 	    while (descp != NULL) {
8487c478bd9Sstevel@tonic-gate 		update_desc(descp, args.disk_listp, args.controller_listp,
8497c478bd9Sstevel@tonic-gate 		    args.bus_listp);
8507c478bd9Sstevel@tonic-gate 		descp = descp->next;
8517c478bd9Sstevel@tonic-gate 	    }
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	    /* update the cached object ptrs */
8547c478bd9Sstevel@tonic-gate 	    free_disklistp = disk_listp;
8557c478bd9Sstevel@tonic-gate 	    free_controllerlistp = controller_listp;
8567c478bd9Sstevel@tonic-gate 	    free_buslistp = bus_listp;
8577c478bd9Sstevel@tonic-gate 	    disk_listp = args.disk_listp;
8587c478bd9Sstevel@tonic-gate 	    controller_listp = args.controller_listp;
8597c478bd9Sstevel@tonic-gate 	    bus_listp = args.bus_listp;
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	} else {
8627c478bd9Sstevel@tonic-gate 	    free_disklistp = args.disk_listp;
8637c478bd9Sstevel@tonic-gate 	    free_controllerlistp = args.controller_listp;
8647c478bd9Sstevel@tonic-gate 	    free_buslistp = args.bus_listp;
8657c478bd9Sstevel@tonic-gate 	}
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	/*
8687c478bd9Sstevel@tonic-gate 	 * Free the memory from either the old cached objects or the failed
8697c478bd9Sstevel@tonic-gate 	 * update objects.
8707c478bd9Sstevel@tonic-gate 	 */
8717c478bd9Sstevel@tonic-gate 	while (free_disklistp != NULL) {
8727c478bd9Sstevel@tonic-gate 	    disk_t *nextp;
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	    nextp = free_disklistp->next;
8757c478bd9Sstevel@tonic-gate 	    cache_free_disk(free_disklistp);
8767c478bd9Sstevel@tonic-gate 	    free_disklistp = nextp;
8777c478bd9Sstevel@tonic-gate 	}
8787c478bd9Sstevel@tonic-gate 	while (free_controllerlistp != NULL) {
8797c478bd9Sstevel@tonic-gate 	    controller_t *nextp;
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	    nextp = free_controllerlistp->next;
8827c478bd9Sstevel@tonic-gate 	    cache_free_controller(free_controllerlistp);
8837c478bd9Sstevel@tonic-gate 	    free_controllerlistp = nextp;
8847c478bd9Sstevel@tonic-gate 	}
8857c478bd9Sstevel@tonic-gate 	while (free_buslistp != NULL) {
8867c478bd9Sstevel@tonic-gate 	    bus_t *nextp;
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	    nextp = free_buslistp->next;
8897c478bd9Sstevel@tonic-gate 	    cache_free_bus(free_buslistp);
8907c478bd9Sstevel@tonic-gate 	    free_buslistp = nextp;
8917c478bd9Sstevel@tonic-gate 	}
8927c478bd9Sstevel@tonic-gate }
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate /*
8957c478bd9Sstevel@tonic-gate  * Walk the new set of cached objects and update the descriptor ptr to point
8967c478bd9Sstevel@tonic-gate  * to the correct new object.  If there is no object any more, set the desc
8977c478bd9Sstevel@tonic-gate  * ptr to null.
8987c478bd9Sstevel@tonic-gate  */
8997c478bd9Sstevel@tonic-gate static void
9007c478bd9Sstevel@tonic-gate update_desc(descriptor_t *descp, disk_t *newdisksp, controller_t *newctrlp,
9017c478bd9Sstevel@tonic-gate 	bus_t *newbusp)
9027c478bd9Sstevel@tonic-gate {
9037c478bd9Sstevel@tonic-gate 	/* if the descriptor is already dead, we're done */
9047c478bd9Sstevel@tonic-gate 	if (descp->p.generic == NULL) {
9057c478bd9Sstevel@tonic-gate 	    return;
9067c478bd9Sstevel@tonic-gate 	}
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	/*
9097c478bd9Sstevel@tonic-gate 	 * All descriptors use a disk ptr except for controller descriptors
9107c478bd9Sstevel@tonic-gate 	 * and path descriptors.
9117c478bd9Sstevel@tonic-gate 	 */
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	switch (descp->type) {
9147c478bd9Sstevel@tonic-gate 	case DM_BUS:
9157c478bd9Sstevel@tonic-gate 	    update_desc_busp(descp, newbusp);
9167c478bd9Sstevel@tonic-gate 	    break;
9177c478bd9Sstevel@tonic-gate 	case DM_CONTROLLER:
9187c478bd9Sstevel@tonic-gate 	    update_desc_ctrlp(descp, newctrlp);
9197c478bd9Sstevel@tonic-gate 	    break;
9207c478bd9Sstevel@tonic-gate 	case DM_PATH:
9217c478bd9Sstevel@tonic-gate 	    update_desc_pathp(descp, newctrlp);
9227c478bd9Sstevel@tonic-gate 	    break;
9237c478bd9Sstevel@tonic-gate 	default:
9247c478bd9Sstevel@tonic-gate 	    update_desc_diskp(descp, newdisksp);
9257c478bd9Sstevel@tonic-gate 	    break;
9267c478bd9Sstevel@tonic-gate 	}
9277c478bd9Sstevel@tonic-gate }
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate static void
9307c478bd9Sstevel@tonic-gate update_desc_busp(descriptor_t *descp, bus_t *busp)
9317c478bd9Sstevel@tonic-gate {
9327c478bd9Sstevel@tonic-gate 	/* walk the new objects and find the correct bus */
9337c478bd9Sstevel@tonic-gate 	for (; busp; busp = busp->next) {
9347c478bd9Sstevel@tonic-gate 	    if (libdiskmgt_str_eq(descp->p.bus->name, busp->name)) {
9357c478bd9Sstevel@tonic-gate 		descp->p.bus = busp;
9367c478bd9Sstevel@tonic-gate 		return;
9377c478bd9Sstevel@tonic-gate 	    }
9387c478bd9Sstevel@tonic-gate 	}
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	/* we did not find the controller any more, clear the ptr in the desc */
9417c478bd9Sstevel@tonic-gate 	descp->p.bus = NULL;
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate static void
9457c478bd9Sstevel@tonic-gate update_desc_ctrlp(descriptor_t *descp, controller_t *newctrlp)
9467c478bd9Sstevel@tonic-gate {
9477c478bd9Sstevel@tonic-gate 	/* walk the new objects and find the correct controller */
9487c478bd9Sstevel@tonic-gate 	for (; newctrlp; newctrlp = newctrlp->next) {
9497c478bd9Sstevel@tonic-gate 	    if (libdiskmgt_str_eq(descp->p.controller->name, newctrlp->name)) {
9507c478bd9Sstevel@tonic-gate 		descp->p.controller = newctrlp;
9517c478bd9Sstevel@tonic-gate 		return;
9527c478bd9Sstevel@tonic-gate 	    }
9537c478bd9Sstevel@tonic-gate 	}
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	/* we did not find the controller any more, clear the ptr in the desc */
9567c478bd9Sstevel@tonic-gate 	descp->p.controller = NULL;
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate static void
9607c478bd9Sstevel@tonic-gate update_desc_diskp(descriptor_t *descp, disk_t *newdisksp)
9617c478bd9Sstevel@tonic-gate {
9627c478bd9Sstevel@tonic-gate 	/* walk the new objects and find the correct disk */
9637c478bd9Sstevel@tonic-gate 	for (; newdisksp; newdisksp = newdisksp->next) {
9647c478bd9Sstevel@tonic-gate 	    if (match_disk(descp->p.disk, newdisksp)) {
9657c478bd9Sstevel@tonic-gate 		descp->p.disk = newdisksp;
9667c478bd9Sstevel@tonic-gate 		return;
9677c478bd9Sstevel@tonic-gate 	    }
9687c478bd9Sstevel@tonic-gate 	}
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	/* we did not find the disk any more, clear the ptr in the descriptor */
9717c478bd9Sstevel@tonic-gate 	descp->p.disk = NULL;
9727c478bd9Sstevel@tonic-gate }
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate static void
9757c478bd9Sstevel@tonic-gate update_desc_pathp(descriptor_t *descp, controller_t *newctrlp)
9767c478bd9Sstevel@tonic-gate {
9777c478bd9Sstevel@tonic-gate 	/* walk the new objects and find the correct path */
9787c478bd9Sstevel@tonic-gate 	for (; newctrlp; newctrlp = newctrlp->next) {
9797c478bd9Sstevel@tonic-gate 	    path_t	**pp;
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	    pp = newctrlp->paths;
9827c478bd9Sstevel@tonic-gate 	    if (pp != NULL) {
9837c478bd9Sstevel@tonic-gate 		int i;
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 		for (i = 0; pp[i]; i++) {
9867c478bd9Sstevel@tonic-gate 		    if (libdiskmgt_str_eq(descp->p.path->name, pp[i]->name)) {
9877c478bd9Sstevel@tonic-gate 			descp->p.path = pp[i];
9887c478bd9Sstevel@tonic-gate 			return;
9897c478bd9Sstevel@tonic-gate 		    }
9907c478bd9Sstevel@tonic-gate 		}
9917c478bd9Sstevel@tonic-gate 	    }
9927c478bd9Sstevel@tonic-gate 	}
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 	/* we did not find the path any more, clear the ptr in the desc */
9957c478bd9Sstevel@tonic-gate 	descp->p.path = NULL;
9967c478bd9Sstevel@tonic-gate }
997