xref: /titanic_51/usr/src/lib/libcfgadm/common/config_admin.c (revision 269473047d747f7815af570197e4ef7322d3632c)
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
509fe1b16Sdnielsen  * Common Development and Distribution License (the "License").
609fe1b16Sdnielsen  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21d7fa3d4fSdmick 
22d7fa3d4fSdmick /* Portions Copyright 2005 Cyril Plisko */
23d7fa3d4fSdmick 
247c478bd9Sstevel@tonic-gate /*
25*26947304SEvan Yan  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
267c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <errno.h>
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <string.h>
337c478bd9Sstevel@tonic-gate #include <locale.h>
347c478bd9Sstevel@tonic-gate #include <langinfo.h>
357c478bd9Sstevel@tonic-gate #include <time.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #if	!defined(DEBUG)
387c478bd9Sstevel@tonic-gate #define	NDEBUG	1
397c478bd9Sstevel@tonic-gate #else
407c478bd9Sstevel@tonic-gate #undef	NDEBUG
417c478bd9Sstevel@tonic-gate #endif
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include <assert.h>
447c478bd9Sstevel@tonic-gate #include <sys/types.h>
457c478bd9Sstevel@tonic-gate #include <sys/stat.h>
467c478bd9Sstevel@tonic-gate #include <sys/param.h>
477c478bd9Sstevel@tonic-gate #include <dlfcn.h>
487c478bd9Sstevel@tonic-gate #include <synch.h>
497c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
507c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
517c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
527c478bd9Sstevel@tonic-gate #include <unistd.h>
537c478bd9Sstevel@tonic-gate #include <stdarg.h>
547c478bd9Sstevel@tonic-gate #include <limits.h>
557c478bd9Sstevel@tonic-gate #include <ftw.h>
567c478bd9Sstevel@tonic-gate #include <ctype.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #define	CFGA_PLUGIN_LIB
597c478bd9Sstevel@tonic-gate #include <config_admin.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /* Limit size of sysinfo return */
627c478bd9Sstevel@tonic-gate #define	SYSINFO_LENGTH	256
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  * Attachment point specifier types.
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate typedef enum {
687c478bd9Sstevel@tonic-gate 	UNKNOWN_AP,
697c478bd9Sstevel@tonic-gate 	LOGICAL_LINK_AP,
707c478bd9Sstevel@tonic-gate 	LOGICAL_DRV_AP,
717c478bd9Sstevel@tonic-gate 	PHYSICAL_AP,
727c478bd9Sstevel@tonic-gate 	AP_TYPE
737c478bd9Sstevel@tonic-gate } cfga_ap_types_t;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate static char *listopt_array[] = {
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate #define	LISTOPT_CLASS	0
787c478bd9Sstevel@tonic-gate 	"class",
797c478bd9Sstevel@tonic-gate 	NULL
807c478bd9Sstevel@tonic-gate };
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate typedef struct {
837c478bd9Sstevel@tonic-gate 	int v_min;	/* Min acceptable version */
847c478bd9Sstevel@tonic-gate 	int v_max;	/* Max acceptable version */
857c478bd9Sstevel@tonic-gate } vers_req_t;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate #define	INVALID_VERSION		-1
887c478bd9Sstevel@tonic-gate #define	VALID_HSL_VERS(v)	(((v) >= CFGA_HSL_V1) && \
897c478bd9Sstevel@tonic-gate 				((v) <= CFGA_HSL_VERS))
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /*
927c478bd9Sstevel@tonic-gate  * Incomplete definition
937c478bd9Sstevel@tonic-gate  */
947c478bd9Sstevel@tonic-gate struct cfga_vers_ops;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate  * Structure that contains plugin library information.
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate typedef struct plugin_lib {
1007c478bd9Sstevel@tonic-gate 	struct	plugin_lib *next;	/* pointer to next */
1017c478bd9Sstevel@tonic-gate 	mutex_t	lock;			/* protects refcnt */
1027c478bd9Sstevel@tonic-gate 	int	refcnt;			/* reference count */
1037c478bd9Sstevel@tonic-gate 	void	*handle;		/* handle from dlopen */
1047c478bd9Sstevel@tonic-gate 	cfga_err_t	(*cfga_change_state_p)();
1057c478bd9Sstevel@tonic-gate 	cfga_err_t	(*cfga_private_func_p)();
1067c478bd9Sstevel@tonic-gate 	cfga_err_t	(*cfga_test_p)();
1077c478bd9Sstevel@tonic-gate 	cfga_err_t	(*cfga_stat_p)();
1087c478bd9Sstevel@tonic-gate 	cfga_err_t	(*cfga_list_p)();
1097c478bd9Sstevel@tonic-gate 	cfga_err_t	(*cfga_help_p)();
1107c478bd9Sstevel@tonic-gate 	int		(*cfga_ap_id_cmp_p)();
1117c478bd9Sstevel@tonic-gate 	cfga_err_t	(*cfga_list_ext_p)();	/* For V2 plug-ins only */
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	int		plugin_vers;	/* actual plugin version */
1147c478bd9Sstevel@tonic-gate 	struct cfga_vers_ops *vers_ops;	/* version dependant routines */
1157c478bd9Sstevel@tonic-gate 	char	libpath[MAXPATHLEN];	/* full pathname to lib */
1167c478bd9Sstevel@tonic-gate } plugin_lib_t;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate static plugin_lib_t plugin_list;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate typedef struct lib_cache {
1217c478bd9Sstevel@tonic-gate 	struct lib_cache *lc_next;
1227c478bd9Sstevel@tonic-gate 	plugin_lib_t *lc_libp;
1237c478bd9Sstevel@tonic-gate 	char *lc_ap_id;
1247c478bd9Sstevel@tonic-gate 	char *lc_ap_physical;	/* physical ap_id */
1257c478bd9Sstevel@tonic-gate 	char *lc_ap_logical;	/* logical ap_id */
1267c478bd9Sstevel@tonic-gate } lib_cache_t;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate static lib_cache_t *lib_cache;
1297c478bd9Sstevel@tonic-gate static mutex_t lib_cache_lock;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate /*
1327c478bd9Sstevel@tonic-gate  * Library locator data struct - used to pass down through the device
1337c478bd9Sstevel@tonic-gate  * tree walking code.
1347c478bd9Sstevel@tonic-gate  */
1357c478bd9Sstevel@tonic-gate typedef struct lib_locator {
1367c478bd9Sstevel@tonic-gate 	char	ap_base[MAXPATHLEN];
1377c478bd9Sstevel@tonic-gate 	char	ap_logical[CFGA_LOG_EXT_LEN];
1387c478bd9Sstevel@tonic-gate 	char	ap_physical[CFGA_PHYS_EXT_LEN];
1397c478bd9Sstevel@tonic-gate 	char	ap_class[CFGA_CLASS_LEN];
1407c478bd9Sstevel@tonic-gate 	char	pathname[MAXPATHLEN];
1417c478bd9Sstevel@tonic-gate 	plugin_lib_t *libp;
1427c478bd9Sstevel@tonic-gate 	cfga_err_t status;
1437c478bd9Sstevel@tonic-gate 	vers_req_t vers_req;	/* plug-in version required */
1447c478bd9Sstevel@tonic-gate } lib_loc_t;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate /*
1477c478bd9Sstevel@tonic-gate  * linked list of cfga_stat_data structs - used for
1487c478bd9Sstevel@tonic-gate  * config_list
1497c478bd9Sstevel@tonic-gate  */
1507c478bd9Sstevel@tonic-gate typedef struct stat_data_list {
1517c478bd9Sstevel@tonic-gate 	struct stat_data_list	*next;
1527c478bd9Sstevel@tonic-gate 	cfga_stat_data_t	stat_data;
1537c478bd9Sstevel@tonic-gate } stat_data_list_t;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /*
1567c478bd9Sstevel@tonic-gate  * linked list of arrays. Each array represents a bunch
1577c478bd9Sstevel@tonic-gate  * of list_data_t structures returned by a single call
1587c478bd9Sstevel@tonic-gate  * to a plugin's cfga_list_ext() routine.
1597c478bd9Sstevel@tonic-gate  */
1607c478bd9Sstevel@tonic-gate typedef struct array_list {
1617c478bd9Sstevel@tonic-gate 	struct array_list	*next;
1627c478bd9Sstevel@tonic-gate 	cfga_list_data_t	*array;
1637c478bd9Sstevel@tonic-gate 	int			nelem;
1647c478bd9Sstevel@tonic-gate } array_list_t;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate  * encapsulate config_list args to get them through the tree
1687c478bd9Sstevel@tonic-gate  * walking code
1697c478bd9Sstevel@tonic-gate  */
1707c478bd9Sstevel@tonic-gate typedef struct list_stat {
1717c478bd9Sstevel@tonic-gate 	const char *opts;	/* Hardware specific options */
1727c478bd9Sstevel@tonic-gate 	char **errstr;
1737c478bd9Sstevel@tonic-gate 	cfga_flags_t flags;
1747c478bd9Sstevel@tonic-gate 	int	*countp;	/* Total number of list and stat structures */
1757c478bd9Sstevel@tonic-gate 	stat_data_list_t *sdl;	/* Linked list of stat structures */
1767c478bd9Sstevel@tonic-gate 	array_list_t *al;	/* Linked list of arrays of list structures */
1777c478bd9Sstevel@tonic-gate 	vers_req_t use_vers;	/* plugin versions to be stat'ed */
178*26947304SEvan Yan 	char *shp_errstr;	/* only for shp plugin */
1797c478bd9Sstevel@tonic-gate } list_stat_t;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate  * Internal operations for libcfgadm which are version dependant
1837c478bd9Sstevel@tonic-gate  */
1847c478bd9Sstevel@tonic-gate struct cfga_vers_ops {
1857c478bd9Sstevel@tonic-gate 	cfga_err_t (*resolve_lib)(plugin_lib_t *libp);
1867c478bd9Sstevel@tonic-gate 	cfga_err_t (*stat_plugin)(list_stat_t *, lib_loc_t *, char **errstring);
1877c478bd9Sstevel@tonic-gate 	cfga_err_t (*mklog)(di_node_t, di_minor_t, plugin_lib_t *,
1887c478bd9Sstevel@tonic-gate 	    lib_loc_t *liblocp);
1897c478bd9Sstevel@tonic-gate 	cfga_err_t (*get_cond)(lib_loc_t *, cfga_cond_t *, char **);
1907c478bd9Sstevel@tonic-gate };
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate /*
1947c478bd9Sstevel@tonic-gate  * Lock to protect list of libraries
1957c478bd9Sstevel@tonic-gate  */
1967c478bd9Sstevel@tonic-gate static mutex_t plugin_list_lock;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate /*
1997c478bd9Sstevel@tonic-gate  * Forward declarations
2007c478bd9Sstevel@tonic-gate  */
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate static const char *__config_strerror(cfga_err_t);
2037c478bd9Sstevel@tonic-gate static void *config_calloc_check(size_t, size_t, char **);
2047c478bd9Sstevel@tonic-gate static cfga_err_t resolve_lib_ref(plugin_lib_t *, lib_loc_t *);
2057c478bd9Sstevel@tonic-gate static cfga_err_t config_get_lib(const char *, lib_loc_t *, char **);
2067c478bd9Sstevel@tonic-gate static int check_ap(di_node_t, di_minor_t, void *);
207*26947304SEvan Yan static int check_ap_hp(di_node_t, di_hp_t, void *);
208*26947304SEvan Yan static int check_ap_impl(di_node_t, di_minor_t, di_hp_t, void *);
2097c478bd9Sstevel@tonic-gate static int check_ap_phys(di_node_t, di_minor_t, void *);
210*26947304SEvan Yan static int check_ap_phys_hp(di_node_t, di_hp_t, void *);
211*26947304SEvan Yan static int check_ap_phys_impl(di_node_t, di_minor_t, di_hp_t, void *);
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate static cfga_err_t find_ap_common(lib_loc_t *libloc_p, const char *rootpath,
214*26947304SEvan Yan     int (*fcn)(di_node_t node, di_minor_t minor, void *arg),
215*26947304SEvan Yan     int (*fcn_hp)(di_node_t node, di_hp_t hp, void *arg),
216*26947304SEvan Yan     char **errstring);
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate static plugin_lib_t *lib_in_list(char *);
219*26947304SEvan Yan static cfga_err_t find_lib(di_node_t, di_minor_t, lib_loc_t *);
220*26947304SEvan Yan static cfga_err_t find_lib_hp(di_node_t, di_hp_t, lib_loc_t *);
221*26947304SEvan Yan static cfga_err_t find_lib_impl(char *, lib_loc_t *);
2227c478bd9Sstevel@tonic-gate static cfga_err_t load_lib(di_node_t, di_minor_t, lib_loc_t *);
223*26947304SEvan Yan static cfga_err_t load_lib_hp(di_node_t, di_hp_t, lib_loc_t *);
224*26947304SEvan Yan static cfga_err_t load_lib_impl(di_node_t, di_minor_t, di_hp_t, lib_loc_t *);
2257c478bd9Sstevel@tonic-gate extern void bcopy(const void *, void *, size_t);
2267c478bd9Sstevel@tonic-gate static void config_err(int, int, char **);
2277c478bd9Sstevel@tonic-gate static void hold_lib(plugin_lib_t *);
2287c478bd9Sstevel@tonic-gate static void rele_lib(plugin_lib_t *);
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate static cfga_err_t parse_listopt(char *listopts, char **classpp,
2317c478bd9Sstevel@tonic-gate     char **errstring);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate static cfga_err_t list_common(list_stat_t *lstatp, const char *class);
2347c478bd9Sstevel@tonic-gate static int do_list_common(di_node_t node, di_minor_t minor, void *arg);
235*26947304SEvan Yan static int do_list_common_hp(di_node_t node, di_hp_t hp, void *arg);
236*26947304SEvan Yan static int do_list_common_impl(di_node_t node, di_minor_t minor,
237*26947304SEvan Yan     di_hp_t hp, void *arg);
2387c478bd9Sstevel@tonic-gate static cfga_err_t stat_common(int num_ap_ids, char *const *ap_ids,
2397c478bd9Sstevel@tonic-gate     const char *class, list_stat_t *lstatp);
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate static cfga_err_t null_resolve(plugin_lib_t *libp);
2427c478bd9Sstevel@tonic-gate static cfga_err_t resolve_v1(plugin_lib_t *libp);
2437c478bd9Sstevel@tonic-gate static cfga_err_t resolve_v2(plugin_lib_t *libp);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate static cfga_err_t mklog_common(di_node_t node, di_minor_t minor,
2467c478bd9Sstevel@tonic-gate     lib_loc_t *liblocp, size_t len);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate static cfga_err_t null_mklog(di_node_t node, di_minor_t minor,
2497c478bd9Sstevel@tonic-gate     plugin_lib_t *libp, lib_loc_t *liblocp);
2507c478bd9Sstevel@tonic-gate static cfga_err_t mklog_v1(di_node_t node, di_minor_t minor,
2517c478bd9Sstevel@tonic-gate     plugin_lib_t *libp, lib_loc_t *liblocp);
2527c478bd9Sstevel@tonic-gate static cfga_err_t mklog_v2(di_node_t node, di_minor_t minor,
2537c478bd9Sstevel@tonic-gate     plugin_lib_t *libp, lib_loc_t *liblocp);
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate static cfga_err_t null_stat_plugin(list_stat_t *lstatp, lib_loc_t *libloc_p,
2567c478bd9Sstevel@tonic-gate     char **errstring);
2577c478bd9Sstevel@tonic-gate static cfga_err_t stat_plugin_v2(list_stat_t *lstat, lib_loc_t *libloc_p,
2587c478bd9Sstevel@tonic-gate     char **errstring);
2597c478bd9Sstevel@tonic-gate static cfga_err_t stat_plugin_v1(list_stat_t *lstat, lib_loc_t *libloc_p,
2607c478bd9Sstevel@tonic-gate     char **errstring);
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate static cfga_err_t null_get_cond(lib_loc_t *liblocp, cfga_cond_t *condp,
2637c478bd9Sstevel@tonic-gate     char **errstring);
2647c478bd9Sstevel@tonic-gate static cfga_err_t get_cond_v1(lib_loc_t *liblocp, cfga_cond_t *condp,
2657c478bd9Sstevel@tonic-gate     char **errstring);
2667c478bd9Sstevel@tonic-gate static cfga_err_t get_cond_v2(lib_loc_t *liblocp, cfga_cond_t *condp,
2677c478bd9Sstevel@tonic-gate     char **errstring);
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate static cfga_err_t realloc_data(cfga_stat_data_t **ap_id_list,
2707c478bd9Sstevel@tonic-gate     int *nlistp, list_stat_t *lstatp);
2717c478bd9Sstevel@tonic-gate static cfga_err_t realloc_data_ext(cfga_list_data_t **ap_id_list,
2727c478bd9Sstevel@tonic-gate     int *nlistp, list_stat_t *lstatp);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate static void stat_to_list(cfga_list_data_t *lp, cfga_stat_data_t *statp);
2757c478bd9Sstevel@tonic-gate static void lstat_free(list_stat_t *lstatp);
2767c478bd9Sstevel@tonic-gate static cfga_ap_types_t find_arg_type(const char *ap_id);
2777c478bd9Sstevel@tonic-gate static int compat_plugin(vers_req_t *reqp, int plugin_vers);
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate static cfga_err_t check_flags(cfga_flags_t flags, cfga_flags_t mask,
2807c478bd9Sstevel@tonic-gate     char **errstring);
2817c478bd9Sstevel@tonic-gate static cfga_err_t check_apids(int num_ap_ids, char *const *ap_ids,
2827c478bd9Sstevel@tonic-gate     char **errstring);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate static char *get_class(di_minor_t minor);
2857c478bd9Sstevel@tonic-gate static cfga_err_t split_apid(char *ap_id, char **dyncompp, char **errstring);
2867c478bd9Sstevel@tonic-gate static void append_dyn(char *buf, const char *dyncomp, size_t blen);
2877c478bd9Sstevel@tonic-gate static int default_ap_id_cmp(const char *ap_id1, const char *ap_id2);
2887c478bd9Sstevel@tonic-gate static void destroy_cache();
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate /*
2917c478bd9Sstevel@tonic-gate  * Plugin library search path helpers
2927c478bd9Sstevel@tonic-gate  */
2937c478bd9Sstevel@tonic-gate #define	LIB_PATH_BASE1	"/usr/platform/"
2947c478bd9Sstevel@tonic-gate #define	LIB_PATH_BASE2	"/usr"
295d7fa3d4fSdmick #if defined(__sparcv9)
2967c478bd9Sstevel@tonic-gate #define	LIB_PATH_MIDDLE	"/lib/cfgadm/sparcv9/"
297d7fa3d4fSdmick #elif defined(__amd64)
298d7fa3d4fSdmick #define	LIB_PATH_MIDDLE "/lib/cfgadm/amd64/"
2997c478bd9Sstevel@tonic-gate #else
3007c478bd9Sstevel@tonic-gate #define	LIB_PATH_MIDDLE	"/lib/cfgadm/"
3017c478bd9Sstevel@tonic-gate #endif
3027c478bd9Sstevel@tonic-gate #define	LIB_PATH_TAIL	".so.1"
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
3067c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
3077c478bd9Sstevel@tonic-gate #endif
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate /*
3107c478bd9Sstevel@tonic-gate  * Defined constants
3117c478bd9Sstevel@tonic-gate  */
3127c478bd9Sstevel@tonic-gate #define	DEVICES_DIR		"/devices"
3137c478bd9Sstevel@tonic-gate #define	DOT_DOT_DEVICES		"../devices"
3147c478bd9Sstevel@tonic-gate #define	CFGA_DEV_DIR		"/dev/cfg"
3157c478bd9Sstevel@tonic-gate #define	SLASH			"/"
3167c478bd9Sstevel@tonic-gate #define	S_FREE(x)	(((x) != NULL) ? (free(x), (x) = NULL) : (void *)0)
3177c478bd9Sstevel@tonic-gate #define	GET_DYN(a)	(strstr((a), CFGA_DYN_SEP))
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate #define	CFGA_NO_CLASS		"none"
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate /*
3227c478bd9Sstevel@tonic-gate  * Error strings
3237c478bd9Sstevel@tonic-gate  */
3247c478bd9Sstevel@tonic-gate #define	DI_INIT_FAILED	1
3257c478bd9Sstevel@tonic-gate #define	ALLOC_FAILED	2
3267c478bd9Sstevel@tonic-gate #define	INVALID_ARGS	3
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate static char *
3297c478bd9Sstevel@tonic-gate err_strings[] = {
3307c478bd9Sstevel@tonic-gate 	NULL,
3317c478bd9Sstevel@tonic-gate 	"Device library initialize failed",
3327c478bd9Sstevel@tonic-gate 	"Memory allocation failed",
3337c478bd9Sstevel@tonic-gate 	"Invalid argument(s)"
3347c478bd9Sstevel@tonic-gate };
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate static const char err_sep[] = ": ";
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate /*
3407c478bd9Sstevel@tonic-gate  * Table of version dependant routines
3417c478bd9Sstevel@tonic-gate  */
3427c478bd9Sstevel@tonic-gate static struct cfga_vers_ops cfga_vers_ops[CFGA_HSL_VERS + 1] = {
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate {null_resolve,	null_stat_plugin,	null_mklog,	null_get_cond	},
3457c478bd9Sstevel@tonic-gate {resolve_v1,	stat_plugin_v1,		mklog_v1,	get_cond_v1	},
3467c478bd9Sstevel@tonic-gate {resolve_v2,	stat_plugin_v2,		mklog_v2,	get_cond_v2	}
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate };
3497c478bd9Sstevel@tonic-gate #define	VERS_ARRAY_SZ	(sizeof (cfga_vers_ops)/sizeof (cfga_vers_ops[0]))
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate /*
3537c478bd9Sstevel@tonic-gate  * Public interfaces for libcfgadm, as documented in config_admin.3x
3547c478bd9Sstevel@tonic-gate  */
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate /*
3577c478bd9Sstevel@tonic-gate  * config_change_state
3587c478bd9Sstevel@tonic-gate  */
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate cfga_err_t
3617c478bd9Sstevel@tonic-gate config_change_state(
3627c478bd9Sstevel@tonic-gate 	cfga_cmd_t state_change_cmd,
3637c478bd9Sstevel@tonic-gate 	int num_ap_ids,
3647c478bd9Sstevel@tonic-gate 	char *const *ap_id,
3657c478bd9Sstevel@tonic-gate 	const char *options,
3667c478bd9Sstevel@tonic-gate 	struct cfga_confirm *confp,
3677c478bd9Sstevel@tonic-gate 	struct cfga_msg *msgp,
3687c478bd9Sstevel@tonic-gate 	char **errstring,
3697c478bd9Sstevel@tonic-gate 	cfga_flags_t flags)
3707c478bd9Sstevel@tonic-gate {
3717c478bd9Sstevel@tonic-gate 	/*
3727c478bd9Sstevel@tonic-gate 	 * for each arg -
3737c478bd9Sstevel@tonic-gate 	 *  load hs library,
3747c478bd9Sstevel@tonic-gate 	 *  if force
3757c478bd9Sstevel@tonic-gate 	 *    call cfga_state_change_func
3767c478bd9Sstevel@tonic-gate 	 *    return status
3777c478bd9Sstevel@tonic-gate 	 *  else
3787c478bd9Sstevel@tonic-gate 	 *    call it's cfga_stat
3797c478bd9Sstevel@tonic-gate 	 *    check condition
3807c478bd9Sstevel@tonic-gate 	 *    call cfga_state_change_func
3817c478bd9Sstevel@tonic-gate 	 *    return status
3827c478bd9Sstevel@tonic-gate 	 */
3837c478bd9Sstevel@tonic-gate 	int i;
3847c478bd9Sstevel@tonic-gate 	lib_loc_t libloc;
3857c478bd9Sstevel@tonic-gate 	plugin_lib_t *libp;
3867c478bd9Sstevel@tonic-gate 	cfga_cond_t cond;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	cfga_err_t retval = CFGA_OK;
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	/* Sanity checks */
3917c478bd9Sstevel@tonic-gate 	if (state_change_cmd == CFGA_CMD_NONE)
3927c478bd9Sstevel@tonic-gate 		return (retval);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	if ((state_change_cmd < CFGA_CMD_NONE) ||
3957c478bd9Sstevel@tonic-gate 	    (state_change_cmd > CFGA_CMD_UNCONFIGURE))
3967c478bd9Sstevel@tonic-gate 		return (CFGA_INVAL);
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	if (errstring != NULL) {
3997c478bd9Sstevel@tonic-gate 		*errstring = NULL;
4007c478bd9Sstevel@tonic-gate 	}
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	if (check_flags(flags, CFGA_FLAG_FORCE | CFGA_FLAG_VERBOSE, errstring)
4037c478bd9Sstevel@tonic-gate 	    != CFGA_OK) {
4047c478bd9Sstevel@tonic-gate 		return (CFGA_ERROR);
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	if (check_apids(num_ap_ids, ap_id, errstring) != CFGA_OK) {
4087c478bd9Sstevel@tonic-gate 		return (CFGA_ERROR);
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	/*
4127c478bd9Sstevel@tonic-gate 	 * operate on each ap_id
4137c478bd9Sstevel@tonic-gate 	 */
4147c478bd9Sstevel@tonic-gate 	for (i = 0; (i < num_ap_ids) && (retval == CFGA_OK); i++) {
4157c478bd9Sstevel@tonic-gate 		libloc.libp = NULL;
4167c478bd9Sstevel@tonic-gate 		if ((retval = config_get_lib(ap_id[i], &libloc, errstring)) !=
4177c478bd9Sstevel@tonic-gate 		    CFGA_OK) {
4187c478bd9Sstevel@tonic-gate 			break;
4197c478bd9Sstevel@tonic-gate 		}
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 		libp = libloc.libp;
4227c478bd9Sstevel@tonic-gate 		if ((flags & CFGA_FLAG_FORCE) ||
4237c478bd9Sstevel@tonic-gate 		    (state_change_cmd == CFGA_CMD_UNLOAD) ||
4247c478bd9Sstevel@tonic-gate 		    (state_change_cmd == CFGA_CMD_DISCONNECT) ||
4257c478bd9Sstevel@tonic-gate 		    (state_change_cmd == CFGA_CMD_UNCONFIGURE)) {
4267c478bd9Sstevel@tonic-gate 			errno = 0;
4277c478bd9Sstevel@tonic-gate 			retval = (*libp->cfga_change_state_p)
4287c478bd9Sstevel@tonic-gate 			    (state_change_cmd, libloc.ap_physical, options,
4297c478bd9Sstevel@tonic-gate 			    confp, msgp, errstring, flags);
4307c478bd9Sstevel@tonic-gate 		} else {
4317c478bd9Sstevel@tonic-gate 			/*
4327c478bd9Sstevel@tonic-gate 			 * Need to check condition before proceeding in
4337c478bd9Sstevel@tonic-gate 			 * the "configure direction"
4347c478bd9Sstevel@tonic-gate 			 */
4357c478bd9Sstevel@tonic-gate 			if ((retval = libp->vers_ops->get_cond(&libloc, &cond,
4367c478bd9Sstevel@tonic-gate 			    errstring)) != CFGA_OK) {
4377c478bd9Sstevel@tonic-gate 				break;
4387c478bd9Sstevel@tonic-gate 			}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 			if (cond == CFGA_COND_OK || cond == CFGA_COND_UNKNOWN) {
4417c478bd9Sstevel@tonic-gate 				errno = 0;
4427c478bd9Sstevel@tonic-gate 				retval =
4437c478bd9Sstevel@tonic-gate 				    (*libp->cfga_change_state_p)(
4447c478bd9Sstevel@tonic-gate 				    state_change_cmd,
4457c478bd9Sstevel@tonic-gate 				    libloc.ap_physical, options,
4467c478bd9Sstevel@tonic-gate 				    confp, msgp, errstring,
4477c478bd9Sstevel@tonic-gate 				    flags);
4487c478bd9Sstevel@tonic-gate 			} else {
4497c478bd9Sstevel@tonic-gate 				retval = CFGA_INSUFFICENT_CONDITION;
4507c478bd9Sstevel@tonic-gate 			}
4517c478bd9Sstevel@tonic-gate 		}
4527c478bd9Sstevel@tonic-gate 		rele_lib(libp);
4537c478bd9Sstevel@tonic-gate 	}
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	return (retval);
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate /*
4597c478bd9Sstevel@tonic-gate  * config_private_func
4607c478bd9Sstevel@tonic-gate  */
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate cfga_err_t
4637c478bd9Sstevel@tonic-gate config_private_func(
4647c478bd9Sstevel@tonic-gate 	const char *function,
4657c478bd9Sstevel@tonic-gate 	int num_ap_ids,
4667c478bd9Sstevel@tonic-gate 	char *const *ap_ids,
4677c478bd9Sstevel@tonic-gate 	const char *options,
4687c478bd9Sstevel@tonic-gate 	struct cfga_confirm *confp,
4697c478bd9Sstevel@tonic-gate 	struct cfga_msg *msgp,
4707c478bd9Sstevel@tonic-gate 	char **errstring,
4717c478bd9Sstevel@tonic-gate 	cfga_flags_t flags)
4727c478bd9Sstevel@tonic-gate {
4737c478bd9Sstevel@tonic-gate 	int i;
4747c478bd9Sstevel@tonic-gate 	lib_loc_t libloc;
4757c478bd9Sstevel@tonic-gate 	cfga_err_t retval = CFGA_OK;
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	if (errstring != NULL) {
4797c478bd9Sstevel@tonic-gate 		*errstring = NULL;
4807c478bd9Sstevel@tonic-gate 	}
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	if (check_flags(flags, CFGA_FLAG_FORCE | CFGA_FLAG_VERBOSE, errstring)
4837c478bd9Sstevel@tonic-gate 	    != CFGA_OK) {
4847c478bd9Sstevel@tonic-gate 		return (CFGA_ERROR);
4857c478bd9Sstevel@tonic-gate 	}
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	if (check_apids(num_ap_ids, ap_ids, errstring) != CFGA_OK) {
4887c478bd9Sstevel@tonic-gate 		return (CFGA_ERROR);
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	/*
4927c478bd9Sstevel@tonic-gate 	 * operate on each ap_id
4937c478bd9Sstevel@tonic-gate 	 */
4947c478bd9Sstevel@tonic-gate 	for (i = 0; (i < num_ap_ids) && (retval == CFGA_OK); i++) {
4957c478bd9Sstevel@tonic-gate 		libloc.libp = NULL;
4967c478bd9Sstevel@tonic-gate 		if ((retval = config_get_lib(ap_ids[i], &libloc, errstring)) !=
4977c478bd9Sstevel@tonic-gate 		    CFGA_OK)  {
4987c478bd9Sstevel@tonic-gate 			return (retval);
4997c478bd9Sstevel@tonic-gate 		}
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 		errno = 0;
5027c478bd9Sstevel@tonic-gate 		retval = (*libloc.libp->cfga_private_func_p)(function,
5037c478bd9Sstevel@tonic-gate 		    libloc.ap_physical, options, confp, msgp, errstring,
5047c478bd9Sstevel@tonic-gate 		    flags);
5057c478bd9Sstevel@tonic-gate 		rele_lib(libloc.libp);
5067c478bd9Sstevel@tonic-gate 	}
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	return (retval);
5097c478bd9Sstevel@tonic-gate }
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate /*
5137c478bd9Sstevel@tonic-gate  * config_test
5147c478bd9Sstevel@tonic-gate  */
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate cfga_err_t
5177c478bd9Sstevel@tonic-gate config_test(
5187c478bd9Sstevel@tonic-gate 	int num_ap_ids,
5197c478bd9Sstevel@tonic-gate 	char *const *ap_ids,
5207c478bd9Sstevel@tonic-gate 	const char *options,
5217c478bd9Sstevel@tonic-gate 	struct cfga_msg *msgp,
5227c478bd9Sstevel@tonic-gate 	char **errstring,
5237c478bd9Sstevel@tonic-gate 	cfga_flags_t flags)
5247c478bd9Sstevel@tonic-gate {
5257c478bd9Sstevel@tonic-gate 	int i;
5267c478bd9Sstevel@tonic-gate 	lib_loc_t libloc;
5277c478bd9Sstevel@tonic-gate 	cfga_err_t retval = CFGA_OK;
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	if (errstring != NULL) {
5307c478bd9Sstevel@tonic-gate 		*errstring = NULL;
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	if (check_flags(flags, CFGA_FLAG_FORCE | CFGA_FLAG_VERBOSE, errstring)
5347c478bd9Sstevel@tonic-gate 	    != CFGA_OK) {
5357c478bd9Sstevel@tonic-gate 		return (CFGA_ERROR);
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	if (check_apids(num_ap_ids, ap_ids, errstring) != CFGA_OK) {
5397c478bd9Sstevel@tonic-gate 		return (CFGA_ERROR);
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	/*
5437c478bd9Sstevel@tonic-gate 	 * operate on each ap_id
5447c478bd9Sstevel@tonic-gate 	 */
5457c478bd9Sstevel@tonic-gate 	for (i = 0; (i < num_ap_ids) && (retval == CFGA_OK); i++) {
5467c478bd9Sstevel@tonic-gate 		libloc.libp = NULL;
5477c478bd9Sstevel@tonic-gate 		if ((retval = config_get_lib(ap_ids[i], &libloc, errstring)) !=
5487c478bd9Sstevel@tonic-gate 		    CFGA_OK) {
5497c478bd9Sstevel@tonic-gate 			return (retval);
5507c478bd9Sstevel@tonic-gate 		}
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 		errno = 0;
5537c478bd9Sstevel@tonic-gate 		retval = (*libloc.libp->cfga_test_p)(libloc.ap_physical,
5547c478bd9Sstevel@tonic-gate 		    options, msgp, errstring, flags);
5557c478bd9Sstevel@tonic-gate 		rele_lib(libloc.libp);
5567c478bd9Sstevel@tonic-gate 	}
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	return (retval);
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate cfga_err_t
5627c478bd9Sstevel@tonic-gate config_stat(
5637c478bd9Sstevel@tonic-gate 	int num_ap_ids,
5647c478bd9Sstevel@tonic-gate 	char *const *ap_ids,
5657c478bd9Sstevel@tonic-gate 	struct cfga_stat_data *buf,
5667c478bd9Sstevel@tonic-gate 	const char *options,
5677c478bd9Sstevel@tonic-gate 	char **errstring)
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate 	int nstat, n, i;
5707c478bd9Sstevel@tonic-gate 	list_stat_t lstat = {NULL};
5717c478bd9Sstevel@tonic-gate 	cfga_err_t rc = CFGA_OK;
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	if (check_apids(num_ap_ids, ap_ids, errstring) != CFGA_OK) {
5747c478bd9Sstevel@tonic-gate 		return (CFGA_ERROR);
5757c478bd9Sstevel@tonic-gate 	}
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	/*
5787c478bd9Sstevel@tonic-gate 	 * V1 entry points don't support dynamic attachment points
5797c478bd9Sstevel@tonic-gate 	 */
5807c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_ap_ids; i++) {
5817c478bd9Sstevel@tonic-gate 		if (GET_DYN(ap_ids[i]) != NULL) {
5827c478bd9Sstevel@tonic-gate 			return (CFGA_APID_NOEXIST);
5837c478bd9Sstevel@tonic-gate 		}
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	nstat = n = 0;
5887c478bd9Sstevel@tonic-gate 	lstat.countp = &nstat;
5897c478bd9Sstevel@tonic-gate 	lstat.opts = options;
5907c478bd9Sstevel@tonic-gate 	lstat.errstr = errstring;
591*26947304SEvan Yan 	lstat.shp_errstr = NULL;
5927c478bd9Sstevel@tonic-gate 	/*
5937c478bd9Sstevel@tonic-gate 	 * This is a V1 interface which can use only V1 plugins
5947c478bd9Sstevel@tonic-gate 	 */
5957c478bd9Sstevel@tonic-gate 	lstat.use_vers.v_max = lstat.use_vers.v_min = CFGA_HSL_V1;
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	rc = stat_common(num_ap_ids, ap_ids, NULL, &lstat);
5987c478bd9Sstevel@tonic-gate 	if (rc == CFGA_OK) {
5997c478bd9Sstevel@tonic-gate 		assert(*lstat.countp == num_ap_ids);
6007c478bd9Sstevel@tonic-gate 		rc = realloc_data(&buf, &n, &lstat);
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	return (rc);
6047c478bd9Sstevel@tonic-gate }
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate /*
6077c478bd9Sstevel@tonic-gate  * config_list
6087c478bd9Sstevel@tonic-gate  */
6097c478bd9Sstevel@tonic-gate cfga_err_t
6107c478bd9Sstevel@tonic-gate config_list(
6117c478bd9Sstevel@tonic-gate 	struct cfga_stat_data **ap_id_list,
6127c478bd9Sstevel@tonic-gate 	int *nlistp,
6137c478bd9Sstevel@tonic-gate 	const char *options,
6147c478bd9Sstevel@tonic-gate 	char **errstring)
6157c478bd9Sstevel@tonic-gate {
6167c478bd9Sstevel@tonic-gate 	int nstat;
6177c478bd9Sstevel@tonic-gate 	list_stat_t lstat = {NULL};
6187c478bd9Sstevel@tonic-gate 	cfga_err_t retval = CFGA_ERROR;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	if (errstring != NULL) {
6217c478bd9Sstevel@tonic-gate 		*errstring = NULL;
6227c478bd9Sstevel@tonic-gate 	}
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	nstat = 0;
6257c478bd9Sstevel@tonic-gate 	lstat.countp = &nstat;
6267c478bd9Sstevel@tonic-gate 	lstat.opts = options;
6277c478bd9Sstevel@tonic-gate 	lstat.errstr = errstring;
628*26947304SEvan Yan 	lstat.shp_errstr = NULL;
6297c478bd9Sstevel@tonic-gate 	/*
6307c478bd9Sstevel@tonic-gate 	 * This is a V1 interface which can use only V1 plugins
6317c478bd9Sstevel@tonic-gate 	 */
6327c478bd9Sstevel@tonic-gate 	lstat.use_vers.v_max = lstat.use_vers.v_min = CFGA_HSL_V1;
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	*ap_id_list = NULL;
6367c478bd9Sstevel@tonic-gate 	*nlistp = 0;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	/*
6397c478bd9Sstevel@tonic-gate 	 * V1 interfaces don't support prefiltering, no class
6407c478bd9Sstevel@tonic-gate 	 * specified.
6417c478bd9Sstevel@tonic-gate 	 */
6427c478bd9Sstevel@tonic-gate 	retval = list_common(&lstat, NULL);
6437c478bd9Sstevel@tonic-gate 	if (retval == CFGA_OK) {
6447c478bd9Sstevel@tonic-gate 		retval = realloc_data(ap_id_list, nlistp, &lstat);
6457c478bd9Sstevel@tonic-gate 	}
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	assert((ap_id_list != NULL && *nlistp != 0) ||
6487c478bd9Sstevel@tonic-gate 	    (ap_id_list == NULL && *nlistp == 0));
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	if (retval == CFGA_OK && *nlistp == 0) {
6517c478bd9Sstevel@tonic-gate 		return (CFGA_NOTSUPP);
6527c478bd9Sstevel@tonic-gate 	} else {
6537c478bd9Sstevel@tonic-gate 		return (retval);
6547c478bd9Sstevel@tonic-gate 	}
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate /*
6597c478bd9Sstevel@tonic-gate  * config_list_ext
6607c478bd9Sstevel@tonic-gate  */
6617c478bd9Sstevel@tonic-gate cfga_err_t
6627c478bd9Sstevel@tonic-gate config_list_ext(
6637c478bd9Sstevel@tonic-gate 	int num_ap_ids,
6647c478bd9Sstevel@tonic-gate 	char *const *ap_ids,
6657c478bd9Sstevel@tonic-gate 	struct cfga_list_data **ap_id_list,
6667c478bd9Sstevel@tonic-gate 	int *nlistp,
6677c478bd9Sstevel@tonic-gate 	const char *options,
6687c478bd9Sstevel@tonic-gate 	const char *listopts,
6697c478bd9Sstevel@tonic-gate 	char **errstring,
6707c478bd9Sstevel@tonic-gate 	cfga_flags_t flags)
6717c478bd9Sstevel@tonic-gate {
6727c478bd9Sstevel@tonic-gate 	int nstat, list, prefilter;
6737c478bd9Sstevel@tonic-gate 	list_stat_t lstat = {NULL};
6747c478bd9Sstevel@tonic-gate 	char *class;
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	cfga_err_t rc = CFGA_ERROR;
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	*nlistp = 0;
6797c478bd9Sstevel@tonic-gate 	*ap_id_list = NULL;
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	if (errstring != NULL) {
6827c478bd9Sstevel@tonic-gate 		*errstring = NULL;
6837c478bd9Sstevel@tonic-gate 	}
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	if (check_flags(flags, CFGA_FLAG_LIST_ALL, errstring) != CFGA_OK) {
6867c478bd9Sstevel@tonic-gate 		return (CFGA_ERROR);
6877c478bd9Sstevel@tonic-gate 	}
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	class = NULL;
6907c478bd9Sstevel@tonic-gate 	if ((rc = parse_listopt((char *)listopts, &class, errstring))
6917c478bd9Sstevel@tonic-gate 	    != CFGA_OK) {
6927c478bd9Sstevel@tonic-gate 		return (rc);
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	prefilter = (class == NULL) ? 0 : 1;
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	nstat = 0;
6987c478bd9Sstevel@tonic-gate 	lstat.countp = &nstat;
6997c478bd9Sstevel@tonic-gate 	lstat.opts = options;
7007c478bd9Sstevel@tonic-gate 	lstat.errstr = errstring;
701*26947304SEvan Yan 	lstat.shp_errstr = NULL;
7027c478bd9Sstevel@tonic-gate 	lstat.flags = flags;
7037c478bd9Sstevel@tonic-gate 	/*
7047c478bd9Sstevel@tonic-gate 	 * We support both V1 and V2 plugins through this entry
7057c478bd9Sstevel@tonic-gate 	 * point.
7067c478bd9Sstevel@tonic-gate 	 */
7077c478bd9Sstevel@tonic-gate 	lstat.use_vers.v_min = CFGA_HSL_V1;
7087c478bd9Sstevel@tonic-gate 	lstat.use_vers.v_max = CFGA_HSL_V2;
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	list = 0;
7117c478bd9Sstevel@tonic-gate 	if (num_ap_ids == 0 && ap_ids == NULL) {
7127c478bd9Sstevel@tonic-gate 		/*
7137c478bd9Sstevel@tonic-gate 		 * discover and stat all attachment points
7147c478bd9Sstevel@tonic-gate 		 */
7157c478bd9Sstevel@tonic-gate 		list = 1;
7167c478bd9Sstevel@tonic-gate 		rc = list_common(&lstat, class);
7177c478bd9Sstevel@tonic-gate 	} else if (num_ap_ids > 0 && ap_ids != NULL) {
7187c478bd9Sstevel@tonic-gate 		/*
7197c478bd9Sstevel@tonic-gate 		 * Stat specified attachment points. With dynamic expansion
7207c478bd9Sstevel@tonic-gate 		 * more data may be returned than was specified by user.
7217c478bd9Sstevel@tonic-gate 		 */
7227c478bd9Sstevel@tonic-gate 		rc = stat_common(num_ap_ids, ap_ids, class, &lstat);
7237c478bd9Sstevel@tonic-gate 	} else {
7247c478bd9Sstevel@tonic-gate 		rc = CFGA_ERROR;
7257c478bd9Sstevel@tonic-gate 	}
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 	S_FREE(class);
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	if (rc != CFGA_OK) {
7307c478bd9Sstevel@tonic-gate 		return (rc);
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	rc = realloc_data_ext(ap_id_list, nlistp, &lstat);
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	assert((ap_id_list != NULL && *nlistp != 0) ||
7367c478bd9Sstevel@tonic-gate 	    (ap_id_list == NULL && *nlistp == 0));
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	/*
7397c478bd9Sstevel@tonic-gate 	 * For the list command notify user if no attachment
7407c478bd9Sstevel@tonic-gate 	 * point is found in the system.
7417c478bd9Sstevel@tonic-gate 	 *
7427c478bd9Sstevel@tonic-gate 	 */
7437c478bd9Sstevel@tonic-gate 	if (list && rc == CFGA_OK && *nlistp == 0) {
7447c478bd9Sstevel@tonic-gate 		/*
7457c478bd9Sstevel@tonic-gate 		 * If attachment points are being prefiltered, absence of data
7467c478bd9Sstevel@tonic-gate 		 * does not imply that config. admin. is not
7477c478bd9Sstevel@tonic-gate 		 * supported by the system.
7487c478bd9Sstevel@tonic-gate 		 */
7497c478bd9Sstevel@tonic-gate 		if (prefilter) {
7507c478bd9Sstevel@tonic-gate 			/*
7517c478bd9Sstevel@tonic-gate 			 * Prefiltering: requested class is absent
7527c478bd9Sstevel@tonic-gate 			 */
7537c478bd9Sstevel@tonic-gate 			return (CFGA_APID_NOEXIST);
7547c478bd9Sstevel@tonic-gate 		} else {
7557c478bd9Sstevel@tonic-gate 			/*
7567c478bd9Sstevel@tonic-gate 			 * No attachment points in system
7577c478bd9Sstevel@tonic-gate 			 */
7587c478bd9Sstevel@tonic-gate 			return (CFGA_NOTSUPP);
7597c478bd9Sstevel@tonic-gate 		}
7607c478bd9Sstevel@tonic-gate 	} else {
7617c478bd9Sstevel@tonic-gate 		return (rc);
7627c478bd9Sstevel@tonic-gate 	}
7637c478bd9Sstevel@tonic-gate }
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate /*
7677c478bd9Sstevel@tonic-gate  * config_unload_libs
7687c478bd9Sstevel@tonic-gate  *
7697c478bd9Sstevel@tonic-gate  * Attempts to remove all libs on the plugin list.
7707c478bd9Sstevel@tonic-gate  */
7717c478bd9Sstevel@tonic-gate void
7727c478bd9Sstevel@tonic-gate config_unload_libs()
7737c478bd9Sstevel@tonic-gate {
7747c478bd9Sstevel@tonic-gate 	plugin_lib_t *libp, *prev = &plugin_list, *next = NULL;
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	/* destroy cache entries to remove refcnt agains plugins */
7777c478bd9Sstevel@tonic-gate 	destroy_cache();
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&plugin_list_lock);
7807c478bd9Sstevel@tonic-gate 	for (libp = plugin_list.next; libp != NULL; libp = next) {
7817c478bd9Sstevel@tonic-gate 		next = libp->next;
7827c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&libp->lock);
7837c478bd9Sstevel@tonic-gate 		if (libp->refcnt) {
7847c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&libp->lock);
7857c478bd9Sstevel@tonic-gate 			prev = libp;
7867c478bd9Sstevel@tonic-gate 			continue;
7877c478bd9Sstevel@tonic-gate 		}
7887c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&libp->lock);
7897c478bd9Sstevel@tonic-gate 		prev->next = next;
7907c478bd9Sstevel@tonic-gate 		(void) dlclose(libp->handle);
7917c478bd9Sstevel@tonic-gate 		(void) mutex_destroy(&libp->lock);
7927c478bd9Sstevel@tonic-gate 		free(libp);
7937c478bd9Sstevel@tonic-gate 	}
7947c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&plugin_list_lock);
7957c478bd9Sstevel@tonic-gate }
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate /*
7987c478bd9Sstevel@tonic-gate  * config_ap_id_cmp
7997c478bd9Sstevel@tonic-gate  */
8007c478bd9Sstevel@tonic-gate int
8017c478bd9Sstevel@tonic-gate config_ap_id_cmp(
8027c478bd9Sstevel@tonic-gate 	const cfga_ap_log_id_t ap1,
8037c478bd9Sstevel@tonic-gate 	const cfga_ap_log_id_t ap2)
8047c478bd9Sstevel@tonic-gate {
8057c478bd9Sstevel@tonic-gate 	int ret;
8067c478bd9Sstevel@tonic-gate 	lib_loc_t libloc;
8077c478bd9Sstevel@tonic-gate 	char apstat1[CFGA_PHYS_EXT_LEN];
8087c478bd9Sstevel@tonic-gate 	char apstat2[CFGA_PHYS_EXT_LEN];
8097c478bd9Sstevel@tonic-gate 	char *sep1, *sep2;
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	/*
8127c478bd9Sstevel@tonic-gate 	 * Extract static ap_ids
8137c478bd9Sstevel@tonic-gate 	 */
8147c478bd9Sstevel@tonic-gate 	(void) strlcpy(apstat1, ap1, sizeof (apstat1));
8157c478bd9Sstevel@tonic-gate 	(void) strlcpy(apstat2, ap2, sizeof (apstat2));
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	sep1 = GET_DYN(apstat1);
8187c478bd9Sstevel@tonic-gate 	sep2 = GET_DYN(apstat2);
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	if (sep1)
8217c478bd9Sstevel@tonic-gate 		*sep1 = '\0';
8227c478bd9Sstevel@tonic-gate 	if (sep2)
8237c478bd9Sstevel@tonic-gate 		*sep2 = '\0';
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	/*
8267c478bd9Sstevel@tonic-gate 	 * Use the default comparator for static ap_ids
8277c478bd9Sstevel@tonic-gate 	 */
8287c478bd9Sstevel@tonic-gate 	ret = default_ap_id_cmp(apstat1, apstat2);
8297c478bd9Sstevel@tonic-gate 	if (ret)
8307c478bd9Sstevel@tonic-gate 		return (ret);
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	/*
8337c478bd9Sstevel@tonic-gate 	 * static components match. They belong to
8347c478bd9Sstevel@tonic-gate 	 * the same static ap_id. Check if both are dynamic
8357c478bd9Sstevel@tonic-gate 	 * If not, static < dynamic.
8367c478bd9Sstevel@tonic-gate 	 */
8377c478bd9Sstevel@tonic-gate 	if ((sep1 == NULL) ^ (sep2 == NULL))
8387c478bd9Sstevel@tonic-gate 		return (sep1 ? 1 : -1);
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	/*
8417c478bd9Sstevel@tonic-gate 	 * If both are static, then ap1 = ap2
8427c478bd9Sstevel@tonic-gate 	 */
8437c478bd9Sstevel@tonic-gate 	if (sep1 == NULL)
8447c478bd9Sstevel@tonic-gate 		return (0);
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	/*
8477c478bd9Sstevel@tonic-gate 	 * Both are dynamic and belong to same static ap_id.
8487c478bd9Sstevel@tonic-gate 	 * Use the plugin comparator
8497c478bd9Sstevel@tonic-gate 	 */
8507c478bd9Sstevel@tonic-gate 	libloc.libp = NULL;
8517c478bd9Sstevel@tonic-gate 	if (config_get_lib(ap1, &libloc, NULL) != CFGA_OK) {
8527c478bd9Sstevel@tonic-gate 		return (strncmp(sep1, sep2, CFGA_PHYS_EXT_LEN));
8537c478bd9Sstevel@tonic-gate 	}
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 	ret = (*libloc.libp->cfga_ap_id_cmp_p)(ap1, ap2);
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	rele_lib(libloc.libp);
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	return (ret);
8607c478bd9Sstevel@tonic-gate }
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate /*
8637c478bd9Sstevel@tonic-gate  * config_strerror
8647c478bd9Sstevel@tonic-gate  */
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate const char *
8677c478bd9Sstevel@tonic-gate config_strerror(cfga_err_t cfgerrnum)
8687c478bd9Sstevel@tonic-gate {
8697c478bd9Sstevel@tonic-gate 	const char *ep = NULL;
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	if ((cfgerrnum < CFGA_OK) || (cfgerrnum > CFGA_ATTR_INVAL))
8727c478bd9Sstevel@tonic-gate 		return (NULL);
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	ep = __config_strerror(cfgerrnum);
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 	return ((ep != NULL) ? dgettext(TEXT_DOMAIN, ep) : NULL);
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate /*
8807c478bd9Sstevel@tonic-gate  * config_help
8817c478bd9Sstevel@tonic-gate  */
8827c478bd9Sstevel@tonic-gate cfga_err_t
8837c478bd9Sstevel@tonic-gate config_help(
8847c478bd9Sstevel@tonic-gate 	int num_ap_ids,
8857c478bd9Sstevel@tonic-gate 	char *const *ap_ids,
8867c478bd9Sstevel@tonic-gate 	struct cfga_msg *msgp,
8877c478bd9Sstevel@tonic-gate 	const char *options,
8887c478bd9Sstevel@tonic-gate 	cfga_flags_t flags)
8897c478bd9Sstevel@tonic-gate {
8907c478bd9Sstevel@tonic-gate 	int i;
8917c478bd9Sstevel@tonic-gate 	lib_loc_t libloc;
8927c478bd9Sstevel@tonic-gate 	cfga_err_t retval = CFGA_OK;
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	if (check_flags(flags, CFGA_FLAG_FORCE | CFGA_FLAG_VERBOSE, NULL)
8957c478bd9Sstevel@tonic-gate 	    != CFGA_OK) {
8967c478bd9Sstevel@tonic-gate 		return (CFGA_ERROR);
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	if (num_ap_ids < 0) {
9007c478bd9Sstevel@tonic-gate 		return (CFGA_ERROR);
9017c478bd9Sstevel@tonic-gate 	}
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	if (num_ap_ids > 0 && ap_ids == NULL) {
9047c478bd9Sstevel@tonic-gate 		return (CFGA_ERROR);
9057c478bd9Sstevel@tonic-gate 	}
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	/*
9087c478bd9Sstevel@tonic-gate 	 * operate on each ap_id
9097c478bd9Sstevel@tonic-gate 	 */
9107c478bd9Sstevel@tonic-gate 	for (i = 0; (i < num_ap_ids) && (retval == CFGA_OK); i++) {
9117c478bd9Sstevel@tonic-gate 		libloc.libp = NULL;
9127c478bd9Sstevel@tonic-gate 		if ((retval = config_get_lib(ap_ids[i], &libloc,
9137c478bd9Sstevel@tonic-gate 		    NULL)) != CFGA_OK) {
9147c478bd9Sstevel@tonic-gate 			return (retval);
9157c478bd9Sstevel@tonic-gate 		}
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 		errno = 0;
9187c478bd9Sstevel@tonic-gate 		retval = (*libloc.libp->cfga_help_p)(msgp, options, flags);
9197c478bd9Sstevel@tonic-gate 		rele_lib(libloc.libp);
9207c478bd9Sstevel@tonic-gate 	}
9217c478bd9Sstevel@tonic-gate 	return (retval);
9227c478bd9Sstevel@tonic-gate }
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate /*
9257c478bd9Sstevel@tonic-gate  * Private support routines for the public interfaces
9267c478bd9Sstevel@tonic-gate  */
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate static const char *
9297c478bd9Sstevel@tonic-gate __config_strerror(cfga_err_t cfgerrnum)
9307c478bd9Sstevel@tonic-gate {
9317c478bd9Sstevel@tonic-gate 	const char *ep = NULL;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	switch (cfgerrnum) {
9347c478bd9Sstevel@tonic-gate 	case CFGA_OK:
9357c478bd9Sstevel@tonic-gate 		ep = "Configuration operation succeeded";
9367c478bd9Sstevel@tonic-gate 		break;
9377c478bd9Sstevel@tonic-gate 	case CFGA_NACK:
9387c478bd9Sstevel@tonic-gate 		ep = "Configuration operation cancelled";
9397c478bd9Sstevel@tonic-gate 		break;
9407c478bd9Sstevel@tonic-gate 	case CFGA_INVAL:
9417c478bd9Sstevel@tonic-gate 		ep = "Configuration operation invalid";
9427c478bd9Sstevel@tonic-gate 		break;
9437c478bd9Sstevel@tonic-gate 	case CFGA_NOTSUPP:
9447c478bd9Sstevel@tonic-gate 		ep = "Configuration administration not supported";
9457c478bd9Sstevel@tonic-gate 		break;
9467c478bd9Sstevel@tonic-gate 	case CFGA_OPNOTSUPP:
9477c478bd9Sstevel@tonic-gate 		ep = "Configuration operation not supported";
9487c478bd9Sstevel@tonic-gate 		break;
9497c478bd9Sstevel@tonic-gate 	case CFGA_PRIV:
9507c478bd9Sstevel@tonic-gate 		ep = "Insufficient privileges";
9517c478bd9Sstevel@tonic-gate 		break;
9527c478bd9Sstevel@tonic-gate 	case CFGA_BUSY:
9537c478bd9Sstevel@tonic-gate 		ep = "Component system is busy, try again";
9547c478bd9Sstevel@tonic-gate 		break;
9557c478bd9Sstevel@tonic-gate 	case CFGA_SYSTEM_BUSY:
9567c478bd9Sstevel@tonic-gate 		ep = "System is busy, try again";
9577c478bd9Sstevel@tonic-gate 		break;
9587c478bd9Sstevel@tonic-gate 	case CFGA_DATA_ERROR:
9597c478bd9Sstevel@tonic-gate 		ep = "Data error";
9607c478bd9Sstevel@tonic-gate 		break;
9617c478bd9Sstevel@tonic-gate 	case CFGA_LIB_ERROR:
9627c478bd9Sstevel@tonic-gate 		ep = "Library error";
9637c478bd9Sstevel@tonic-gate 		break;
9647c478bd9Sstevel@tonic-gate 	case CFGA_NO_LIB:
9657c478bd9Sstevel@tonic-gate 		ep = "No Library found";
9667c478bd9Sstevel@tonic-gate 		break;
9677c478bd9Sstevel@tonic-gate 	case CFGA_INSUFFICENT_CONDITION:
9687c478bd9Sstevel@tonic-gate 		ep = "Insufficient condition";
9697c478bd9Sstevel@tonic-gate 		break;
9707c478bd9Sstevel@tonic-gate 	case CFGA_ERROR:
9717c478bd9Sstevel@tonic-gate 		ep = "Hardware specific failure";
9727c478bd9Sstevel@tonic-gate 		break;
9737c478bd9Sstevel@tonic-gate 	case CFGA_APID_NOEXIST:
9747c478bd9Sstevel@tonic-gate 		ep = "Attachment point not found";
9757c478bd9Sstevel@tonic-gate 		break;
9767c478bd9Sstevel@tonic-gate 	case CFGA_ATTR_INVAL:
9777c478bd9Sstevel@tonic-gate 		ep = "No attachment point with specified attributes found";
9787c478bd9Sstevel@tonic-gate 		break;
9797c478bd9Sstevel@tonic-gate 	default:
9807c478bd9Sstevel@tonic-gate 		ep = NULL;
9817c478bd9Sstevel@tonic-gate 		break;
9827c478bd9Sstevel@tonic-gate 	}
9837c478bd9Sstevel@tonic-gate 	return (ep);
9847c478bd9Sstevel@tonic-gate }
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate /*
9877c478bd9Sstevel@tonic-gate  * listopts is a string in the getsubopt(3C) style:
9887c478bd9Sstevel@tonic-gate  *	name1=value1,name2=value2,
9897c478bd9Sstevel@tonic-gate  */
9907c478bd9Sstevel@tonic-gate static cfga_err_t
9917c478bd9Sstevel@tonic-gate parse_listopt(char *listopts, char **classpp, char **errstring)
9927c478bd9Sstevel@tonic-gate {
9937c478bd9Sstevel@tonic-gate 	char *bufp, *optp, *val = NULL;
9947c478bd9Sstevel@tonic-gate 	cfga_err_t rc = CFGA_ERROR;
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	*classpp = NULL;
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 	/*
9997c478bd9Sstevel@tonic-gate 	 * NULL is a legal value for listopts
10007c478bd9Sstevel@tonic-gate 	 */
10017c478bd9Sstevel@tonic-gate 	if (listopts == NULL) {
10027c478bd9Sstevel@tonic-gate 		return (CFGA_OK);
10037c478bd9Sstevel@tonic-gate 	}
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 	if ((bufp = config_calloc_check(1, strlen(listopts) + 1, errstring))
10067c478bd9Sstevel@tonic-gate 	    == NULL) {
10077c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
10087c478bd9Sstevel@tonic-gate 	}
10097c478bd9Sstevel@tonic-gate 	(void) strcpy(bufp, listopts);
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 	optp = bufp; /* getsubopt() modifies its argument */
10127c478bd9Sstevel@tonic-gate 	while (*optp != '\0') {
10137c478bd9Sstevel@tonic-gate 		switch (getsubopt(&optp, listopt_array, &val)) {
10147c478bd9Sstevel@tonic-gate 		case LISTOPT_CLASS:
10157c478bd9Sstevel@tonic-gate 			if (val == NULL || *classpp != NULL) {
10167c478bd9Sstevel@tonic-gate 				rc = CFGA_ERROR;
10177c478bd9Sstevel@tonic-gate 				goto out;
10187c478bd9Sstevel@tonic-gate 			}
10197c478bd9Sstevel@tonic-gate 			if ((*classpp = config_calloc_check(1, strlen(val) + 1,
10207c478bd9Sstevel@tonic-gate 			    errstring)) == NULL) {
10217c478bd9Sstevel@tonic-gate 				rc = CFGA_LIB_ERROR;
10227c478bd9Sstevel@tonic-gate 				goto out;
10237c478bd9Sstevel@tonic-gate 			}
10247c478bd9Sstevel@tonic-gate 			(void) strcpy(*classpp, val);
10257c478bd9Sstevel@tonic-gate 			break;
10267c478bd9Sstevel@tonic-gate 		default:
10277c478bd9Sstevel@tonic-gate 			rc = CFGA_ERROR;
10287c478bd9Sstevel@tonic-gate 			goto out;
10297c478bd9Sstevel@tonic-gate 		}
10307c478bd9Sstevel@tonic-gate 	}
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	rc = CFGA_OK;
10337c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
10347c478bd9Sstevel@tonic-gate out:
10357c478bd9Sstevel@tonic-gate 	S_FREE(bufp);
10367c478bd9Sstevel@tonic-gate 	if (rc != CFGA_OK) {
10377c478bd9Sstevel@tonic-gate 		S_FREE(*classpp);
10387c478bd9Sstevel@tonic-gate 	}
10397c478bd9Sstevel@tonic-gate 	return (rc);
10407c478bd9Sstevel@tonic-gate }
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10437c478bd9Sstevel@tonic-gate static cfga_err_t
10447c478bd9Sstevel@tonic-gate null_mklog(
10457c478bd9Sstevel@tonic-gate 	di_node_t node,
10467c478bd9Sstevel@tonic-gate 	di_minor_t minor,
10477c478bd9Sstevel@tonic-gate 	plugin_lib_t *libp,
10487c478bd9Sstevel@tonic-gate 	lib_loc_t *liblocp)
10497c478bd9Sstevel@tonic-gate {
10507c478bd9Sstevel@tonic-gate 	return (CFGA_OK);
10517c478bd9Sstevel@tonic-gate }
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate static cfga_err_t
10547c478bd9Sstevel@tonic-gate mklog_v1(
10557c478bd9Sstevel@tonic-gate 	di_node_t node,
10567c478bd9Sstevel@tonic-gate 	di_minor_t minor,
10577c478bd9Sstevel@tonic-gate 	plugin_lib_t *libp,
10587c478bd9Sstevel@tonic-gate 	lib_loc_t *liblocp)
10597c478bd9Sstevel@tonic-gate {
10607c478bd9Sstevel@tonic-gate 	const size_t len = CFGA_AP_LOG_ID_LEN;
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	assert(len <=  sizeof (liblocp->ap_logical));
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 	if (libp->plugin_vers != CFGA_HSL_V1) {
10657c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
10667c478bd9Sstevel@tonic-gate 	}
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	return (mklog_common(node, minor, liblocp, len));
10697c478bd9Sstevel@tonic-gate }
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate /*
10737c478bd9Sstevel@tonic-gate  * Obtain the devlink from a /devices path
10747c478bd9Sstevel@tonic-gate  */
10757c478bd9Sstevel@tonic-gate static int
10767c478bd9Sstevel@tonic-gate get_link(di_devlink_t devlink, void *arg)
10777c478bd9Sstevel@tonic-gate {
10787c478bd9Sstevel@tonic-gate 	char *linkp = (char *)arg;
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 	(void) snprintf(linkp, CFGA_LOG_EXT_LEN, "%s",
10817c478bd9Sstevel@tonic-gate 	    di_devlink_path(devlink));
10827c478bd9Sstevel@tonic-gate 	return (DI_WALK_TERMINATE);
10837c478bd9Sstevel@tonic-gate }
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate static cfga_err_t
10867c478bd9Sstevel@tonic-gate mklog_v2(
10877c478bd9Sstevel@tonic-gate 	di_node_t node,
10887c478bd9Sstevel@tonic-gate 	di_minor_t minor,
10897c478bd9Sstevel@tonic-gate 	plugin_lib_t *libp,
10907c478bd9Sstevel@tonic-gate 	lib_loc_t *liblocp)
10917c478bd9Sstevel@tonic-gate {
10927c478bd9Sstevel@tonic-gate 	const size_t len = CFGA_LOG_EXT_LEN;
10937c478bd9Sstevel@tonic-gate 	di_devlink_handle_t hdl;
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	assert(len <=  sizeof (liblocp->ap_logical));
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 	if (libp->plugin_vers != CFGA_HSL_V2) {
10987c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
10997c478bd9Sstevel@tonic-gate 	}
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 	/* open devlink database */
11027c478bd9Sstevel@tonic-gate 	if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
11037c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
11047c478bd9Sstevel@tonic-gate 	}
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate 	liblocp->ap_logical[0] = '\0';
11077c478bd9Sstevel@tonic-gate 	(void) di_devlink_walk(hdl, NULL,
11087c478bd9Sstevel@tonic-gate 	    liblocp->ap_physical + strlen(DEVICES_DIR),
11097c478bd9Sstevel@tonic-gate 	    DI_PRIMARY_LINK, (void *)liblocp->ap_logical, get_link);
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	(void) di_devlink_fini(&hdl);
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 	if (liblocp->ap_logical[0] != '\0')
11147c478bd9Sstevel@tonic-gate 		return (CFGA_OK);
11157c478bd9Sstevel@tonic-gate 	return (mklog_common(node, minor, liblocp, len));
11167c478bd9Sstevel@tonic-gate }
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate /*
11197c478bd9Sstevel@tonic-gate  * mklog_common - make a logical name from the driver and instance
11207c478bd9Sstevel@tonic-gate  */
11217c478bd9Sstevel@tonic-gate static cfga_err_t
11227c478bd9Sstevel@tonic-gate mklog_common(
11237c478bd9Sstevel@tonic-gate 	di_node_t node,
11247c478bd9Sstevel@tonic-gate 	di_minor_t minor,
11257c478bd9Sstevel@tonic-gate 	lib_loc_t *libloc_p,
11267c478bd9Sstevel@tonic-gate 	size_t len)
11277c478bd9Sstevel@tonic-gate {
11287c478bd9Sstevel@tonic-gate 	int inst;
11297c478bd9Sstevel@tonic-gate 	char *drv, *minor_name;
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	drv = di_driver_name(node);
11327c478bd9Sstevel@tonic-gate 	inst = di_instance(node);
11337c478bd9Sstevel@tonic-gate 	minor_name = di_minor_name(minor);
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 	errno = 0;
11367c478bd9Sstevel@tonic-gate 	if (drv != NULL && inst != -1 && minor_name != NULL &&
11377c478bd9Sstevel@tonic-gate 	    snprintf(libloc_p->ap_logical, len, "%s%d:%s", drv, inst,
11387c478bd9Sstevel@tonic-gate 	    minor_name) < len) {	/* snprintf returns strlen */
11397c478bd9Sstevel@tonic-gate 		return (CFGA_OK);
11407c478bd9Sstevel@tonic-gate 	}
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	return (CFGA_LIB_ERROR);
11437c478bd9Sstevel@tonic-gate }
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate /*
1146*26947304SEvan Yan  * mklog_common - make a logical name from the driver and instance
1147*26947304SEvan Yan  */
1148*26947304SEvan Yan /*ARGSUSED*/
1149*26947304SEvan Yan static cfga_err_t
1150*26947304SEvan Yan mklog_hp(
1151*26947304SEvan Yan 	di_node_t node,
1152*26947304SEvan Yan 	di_hp_t hp,
1153*26947304SEvan Yan 	plugin_lib_t *libp,
1154*26947304SEvan Yan 	lib_loc_t *liblocp)
1155*26947304SEvan Yan {
1156*26947304SEvan Yan 	const size_t len = CFGA_LOG_EXT_LEN;
1157*26947304SEvan Yan 	int inst;
1158*26947304SEvan Yan 	char *drv, *hp_name;
1159*26947304SEvan Yan 
1160*26947304SEvan Yan 	drv = di_driver_name(node);
1161*26947304SEvan Yan 	inst = di_instance(node);
1162*26947304SEvan Yan 	hp_name = di_hp_name(hp);
1163*26947304SEvan Yan 
1164*26947304SEvan Yan 	errno = 0;
1165*26947304SEvan Yan 	if (drv != NULL && inst != -1 && hp_name != NULL &&
1166*26947304SEvan Yan 	    snprintf(liblocp->ap_logical, len, "%s%d:%s", drv, inst,
1167*26947304SEvan Yan 	    hp_name) < len) {	/* snprintf returns strlen */
1168*26947304SEvan Yan 		return (CFGA_OK);
1169*26947304SEvan Yan 	}
1170*26947304SEvan Yan 
1171*26947304SEvan Yan 	return (CFGA_LIB_ERROR);
1172*26947304SEvan Yan }
1173*26947304SEvan Yan 
1174*26947304SEvan Yan /*
11757c478bd9Sstevel@tonic-gate  * resolve_lib_ref - relocate to use plugin lib
11767c478bd9Sstevel@tonic-gate  */
11777c478bd9Sstevel@tonic-gate static cfga_err_t
11787c478bd9Sstevel@tonic-gate resolve_lib_ref(
11797c478bd9Sstevel@tonic-gate 	plugin_lib_t *libp,
11807c478bd9Sstevel@tonic-gate 	lib_loc_t *libloc_p)
11817c478bd9Sstevel@tonic-gate {
11827c478bd9Sstevel@tonic-gate 	void *sym;
11837c478bd9Sstevel@tonic-gate 	void *libhdlp = libp->handle;
11847c478bd9Sstevel@tonic-gate 	int plug_vers;
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 	if ((sym = dlsym(libhdlp, "cfga_version")) == NULL) {
11877c478bd9Sstevel@tonic-gate 		/*
11887c478bd9Sstevel@tonic-gate 		 * Version symbol not defined, must be the first version
11897c478bd9Sstevel@tonic-gate 		 */
11907c478bd9Sstevel@tonic-gate 		plug_vers = CFGA_HSL_V1;
11917c478bd9Sstevel@tonic-gate 	} else {
11927c478bd9Sstevel@tonic-gate 		plug_vers =   *((int *)sym);
11937c478bd9Sstevel@tonic-gate 	}
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 	/*
11967c478bd9Sstevel@tonic-gate 	 * Check if plugin version matches request.
11977c478bd9Sstevel@tonic-gate 	 */
11987c478bd9Sstevel@tonic-gate 	if (!compat_plugin(&libloc_p->vers_req, plug_vers)) {
11997c478bd9Sstevel@tonic-gate 		return (CFGA_NO_LIB);
12007c478bd9Sstevel@tonic-gate 	}
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 	/*
12037c478bd9Sstevel@tonic-gate 	 * Record the plugin version and setup version dependant routines
12047c478bd9Sstevel@tonic-gate 	 */
12057c478bd9Sstevel@tonic-gate 	assert(plug_vers < VERS_ARRAY_SZ);
12067c478bd9Sstevel@tonic-gate 	libp->plugin_vers = plug_vers;
12077c478bd9Sstevel@tonic-gate 	libp->vers_ops = &cfga_vers_ops[plug_vers];
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 	/* resolve symbols common to all versions */
12107c478bd9Sstevel@tonic-gate 	if ((sym = dlsym(libhdlp, "cfga_change_state")) == NULL) {
12117c478bd9Sstevel@tonic-gate 		perror("dlsym: cfga_change_state");
12127c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
12137c478bd9Sstevel@tonic-gate 	} else
12147c478bd9Sstevel@tonic-gate 		libp->cfga_change_state_p = (cfga_err_t (*)(cfga_cmd_t,
12157c478bd9Sstevel@tonic-gate 		    const char *, const char *, struct cfga_confirm *,
12167c478bd9Sstevel@tonic-gate 		    struct cfga_msg *, char **, cfga_flags_t)) sym;
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	if ((sym = dlsym(libhdlp, "cfga_private_func")) == NULL) {
12197c478bd9Sstevel@tonic-gate 		perror("dlsym: cfga_private_func");
12207c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
12217c478bd9Sstevel@tonic-gate 	} else
12227c478bd9Sstevel@tonic-gate 		libp->cfga_private_func_p = (cfga_err_t (*)(const char *,
12237c478bd9Sstevel@tonic-gate 		    const char *, const char *, struct cfga_confirm *,
12247c478bd9Sstevel@tonic-gate 		    struct cfga_msg *, char **, cfga_flags_t))sym;
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 	if ((sym = dlsym(libhdlp, "cfga_test")) == NULL) {
12277c478bd9Sstevel@tonic-gate 		perror("dlsym: cfga_test");
12287c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
12297c478bd9Sstevel@tonic-gate 	} else
12307c478bd9Sstevel@tonic-gate 		libp->cfga_test_p = (cfga_err_t (*)(const char *, const char *,
12317c478bd9Sstevel@tonic-gate 		    struct cfga_msg *, char **, cfga_flags_t))sym;
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	if ((sym = dlsym(libhdlp, "cfga_help")) == NULL) {
12347c478bd9Sstevel@tonic-gate 		perror("dlsym: cfga_help");
12357c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
12367c478bd9Sstevel@tonic-gate 	} else
12377c478bd9Sstevel@tonic-gate 		libp->cfga_help_p = (cfga_err_t (*)(struct cfga_msg *,
12387c478bd9Sstevel@tonic-gate 		    const char *, cfga_flags_t))sym;
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	if ((sym = dlsym(libhdlp, "cfga_ap_id_cmp")) == NULL) {
12417c478bd9Sstevel@tonic-gate 		libp->cfga_ap_id_cmp_p = default_ap_id_cmp;
12427c478bd9Sstevel@tonic-gate 	} else
12437c478bd9Sstevel@tonic-gate 		libp->cfga_ap_id_cmp_p = (int (*)(const
12447c478bd9Sstevel@tonic-gate 		    cfga_ap_log_id_t, const cfga_ap_log_id_t))sym;
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	/* Resolve version specific symbols */
12477c478bd9Sstevel@tonic-gate 	return (libp->vers_ops->resolve_lib(libp));
12487c478bd9Sstevel@tonic-gate }
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12517c478bd9Sstevel@tonic-gate static cfga_err_t
12527c478bd9Sstevel@tonic-gate null_resolve(plugin_lib_t *libp)
12537c478bd9Sstevel@tonic-gate {
12547c478bd9Sstevel@tonic-gate 	return (CFGA_OK);
12557c478bd9Sstevel@tonic-gate }
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate static cfga_err_t
12587c478bd9Sstevel@tonic-gate resolve_v1(plugin_lib_t *libp)
12597c478bd9Sstevel@tonic-gate {
12607c478bd9Sstevel@tonic-gate 	void *sym, *libhdlp = libp->handle;
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate 	if (libp->plugin_vers != CFGA_HSL_V1) {
12647c478bd9Sstevel@tonic-gate 		return (CFGA_NO_LIB);
12657c478bd9Sstevel@tonic-gate 	}
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	if ((sym = dlsym(libhdlp, "cfga_stat")) == NULL) {
12687c478bd9Sstevel@tonic-gate 		perror("dlsym: cfga_stat");
12697c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
12707c478bd9Sstevel@tonic-gate 	} else
12717c478bd9Sstevel@tonic-gate 		libp->cfga_stat_p = (cfga_err_t (*)(const char *,
12727c478bd9Sstevel@tonic-gate 		    struct cfga_stat_data *, const char *,
12737c478bd9Sstevel@tonic-gate 		    char **))sym;
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 	if ((sym = dlsym(libhdlp, "cfga_list")) == NULL) {
12767c478bd9Sstevel@tonic-gate 		perror("dlsym: cfga_list");
12777c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
12787c478bd9Sstevel@tonic-gate 	} else
12797c478bd9Sstevel@tonic-gate 		libp->cfga_list_p = (cfga_err_t (*)(struct cfga_stat_data **,
12807c478bd9Sstevel@tonic-gate 		    int *, const char *, char **))sym;
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 	return (CFGA_OK);
12837c478bd9Sstevel@tonic-gate }
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate static cfga_err_t
12867c478bd9Sstevel@tonic-gate resolve_v2(plugin_lib_t *libp)
12877c478bd9Sstevel@tonic-gate {
12887c478bd9Sstevel@tonic-gate 	void *sym;
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 	if (libp->plugin_vers != CFGA_HSL_V2) {
12927c478bd9Sstevel@tonic-gate 		return (CFGA_NO_LIB);
12937c478bd9Sstevel@tonic-gate 	}
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 	if ((sym = dlsym(libp->handle, "cfga_list_ext")) == NULL) {
12967c478bd9Sstevel@tonic-gate 		perror("dlsym: cfga_list_ext");
12977c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
12987c478bd9Sstevel@tonic-gate 	} else {
12997c478bd9Sstevel@tonic-gate 		libp->cfga_list_ext_p = (cfga_err_t (*)(const char *,
13007c478bd9Sstevel@tonic-gate 		    struct cfga_list_data **, int *, const char *,
13017c478bd9Sstevel@tonic-gate 		    const char *, char **, cfga_flags_t))sym;
13027c478bd9Sstevel@tonic-gate 		return (CFGA_OK);
13037c478bd9Sstevel@tonic-gate 	}
13047c478bd9Sstevel@tonic-gate }
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate /*
13077c478bd9Sstevel@tonic-gate  * config_calloc_check - perform allocation, check result and
13087c478bd9Sstevel@tonic-gate  * set error string
13097c478bd9Sstevel@tonic-gate  */
13107c478bd9Sstevel@tonic-gate static void *
13117c478bd9Sstevel@tonic-gate config_calloc_check(
13127c478bd9Sstevel@tonic-gate 	size_t nelem,
13137c478bd9Sstevel@tonic-gate 	size_t elsize,
13147c478bd9Sstevel@tonic-gate 	char **errstring)
13157c478bd9Sstevel@tonic-gate {
13167c478bd9Sstevel@tonic-gate 	void *p;
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	p = calloc(nelem, elsize);
13197c478bd9Sstevel@tonic-gate 	if (p == NULL) {
13207c478bd9Sstevel@tonic-gate 		config_err(0, ALLOC_FAILED, errstring);
13217c478bd9Sstevel@tonic-gate 	}
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 	return (p);
13247c478bd9Sstevel@tonic-gate }
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate /*
13287c478bd9Sstevel@tonic-gate  * config_get_lib - given an ap_id find the library name
13297c478bd9Sstevel@tonic-gate  *	If successful, the plugin library is held.
13307c478bd9Sstevel@tonic-gate  */
13317c478bd9Sstevel@tonic-gate static cfga_err_t
13327c478bd9Sstevel@tonic-gate config_get_lib(
13337c478bd9Sstevel@tonic-gate 	const char *ap_id,
13347c478bd9Sstevel@tonic-gate 	lib_loc_t *lib_loc_p,
13357c478bd9Sstevel@tonic-gate 	char **errstring)
13367c478bd9Sstevel@tonic-gate {
13377c478bd9Sstevel@tonic-gate 	char *dyncomp, path[PATH_MAX];
13387c478bd9Sstevel@tonic-gate 	char *apdup;
13397c478bd9Sstevel@tonic-gate 	cfga_ap_types_t type = UNKNOWN_AP;
13407c478bd9Sstevel@tonic-gate 	cfga_err_t ret = CFGA_ERROR;
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 	if (ap_id == NULL) {
13437c478bd9Sstevel@tonic-gate 		config_err(0, INVALID_ARGS, errstring);
13447c478bd9Sstevel@tonic-gate 		return (ret);
13457c478bd9Sstevel@tonic-gate 	}
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	lib_loc_p->libp = NULL;
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 	if ((apdup = config_calloc_check(1, strlen(ap_id) + 1, errstring))
13507c478bd9Sstevel@tonic-gate 	    == NULL) {
13517c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
13527c478bd9Sstevel@tonic-gate 	}
13537c478bd9Sstevel@tonic-gate 	(void) strcpy(apdup, ap_id);
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	/*
13567c478bd9Sstevel@tonic-gate 	 * Separate into base and dynamic components
13577c478bd9Sstevel@tonic-gate 	 */
13587c478bd9Sstevel@tonic-gate 	if ((ret = split_apid(apdup, &dyncomp, errstring)) != CFGA_OK) {
13597c478bd9Sstevel@tonic-gate 		goto out;
13607c478bd9Sstevel@tonic-gate 	}
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate 	/*
13637c478bd9Sstevel@tonic-gate 	 * No upper limit on version
13647c478bd9Sstevel@tonic-gate 	 */
13657c478bd9Sstevel@tonic-gate 	lib_loc_p->vers_req.v_max = CFGA_HSL_VERS;
13667c478bd9Sstevel@tonic-gate 	if (dyncomp != NULL) {
13677c478bd9Sstevel@tonic-gate 		/*
13687c478bd9Sstevel@tonic-gate 		 * We need atleast version 2 of the plug-in library
13697c478bd9Sstevel@tonic-gate 		 * interface since the ap_id has a dynamic component.
13707c478bd9Sstevel@tonic-gate 		 */
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 		lib_loc_p->vers_req.v_min = CFGA_HSL_V2;
13737c478bd9Sstevel@tonic-gate 	} else {
13747c478bd9Sstevel@tonic-gate 		lib_loc_p->vers_req.v_min = CFGA_HSL_V1;
13757c478bd9Sstevel@tonic-gate 	}
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 	/*
13787c478bd9Sstevel@tonic-gate 	 * If the ap_id is a devlink in CFGA_DEV_DIR, follow link
13797c478bd9Sstevel@tonic-gate 	 * to get the physical ap_id.
13807c478bd9Sstevel@tonic-gate 	 */
13817c478bd9Sstevel@tonic-gate 	if ((type = find_arg_type(apdup)) == LOGICAL_LINK_AP) {
13827c478bd9Sstevel@tonic-gate 		(void) snprintf(lib_loc_p->ap_base, sizeof (lib_loc_p->ap_base),
13837c478bd9Sstevel@tonic-gate 		    "%s%s", CFGA_DEV_DIR SLASH, apdup);
13847c478bd9Sstevel@tonic-gate 	}
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	path[sizeof (path) - 1] = '\0';
13877c478bd9Sstevel@tonic-gate 	if (type == LOGICAL_LINK_AP && realpath(lib_loc_p->ap_base, path)
13887c478bd9Sstevel@tonic-gate 	    != NULL) {
13897c478bd9Sstevel@tonic-gate 		(void) snprintf(lib_loc_p->ap_base, sizeof (lib_loc_p->ap_base),
13907c478bd9Sstevel@tonic-gate 		    "%s", path);
13917c478bd9Sstevel@tonic-gate 	} else {
13927c478bd9Sstevel@tonic-gate 		(void) snprintf(lib_loc_p->ap_base, sizeof (lib_loc_p->ap_base),
13937c478bd9Sstevel@tonic-gate 		    "%s", apdup);
13947c478bd9Sstevel@tonic-gate 	}
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 
13977c478bd9Sstevel@tonic-gate 	/*
13987c478bd9Sstevel@tonic-gate 	 * find and load the library
13997c478bd9Sstevel@tonic-gate 	 * The base component of the ap_id is used to locate the plug-in
1400*26947304SEvan Yan 	 *
1401*26947304SEvan Yan 	 * NOTE that PCIE/PCISHPC connectors also have minor nodes &
1402*26947304SEvan Yan 	 * dev links created for now.
14037c478bd9Sstevel@tonic-gate 	 */
14047c478bd9Sstevel@tonic-gate 	if ((type = find_arg_type(lib_loc_p->ap_base)) == PHYSICAL_AP) {
14057c478bd9Sstevel@tonic-gate 		/*
14067c478bd9Sstevel@tonic-gate 		 * physical ap_id: Use ap_base as root for tree walk
14077c478bd9Sstevel@tonic-gate 		 * A link based apid (logical) will resolve to a physical
14087c478bd9Sstevel@tonic-gate 		 * ap_id.
14097c478bd9Sstevel@tonic-gate 		 */
14107c478bd9Sstevel@tonic-gate 		ret = find_ap_common(lib_loc_p, lib_loc_p->ap_base,
1411*26947304SEvan Yan 		    check_ap_phys, check_ap_phys_hp, errstring);
14127c478bd9Sstevel@tonic-gate 	} else if ((type == LOGICAL_DRV_AP) ||
14137c478bd9Sstevel@tonic-gate 	    (type == AP_TYPE && dyncomp == NULL)) {
14147c478bd9Sstevel@tonic-gate 		/*
14157c478bd9Sstevel@tonic-gate 		 * logical ap_id or ap_type: Use "/" as root for tree walk
14167c478bd9Sstevel@tonic-gate 		 * Note: an aptype cannot have a dynamic component
14177c478bd9Sstevel@tonic-gate 		 */
1418*26947304SEvan Yan 		ret = find_ap_common(lib_loc_p, "/", check_ap,
1419*26947304SEvan Yan 		    check_ap_hp, errstring);
14207c478bd9Sstevel@tonic-gate 	} else {
14217c478bd9Sstevel@tonic-gate 		ret = CFGA_APID_NOEXIST;
14227c478bd9Sstevel@tonic-gate 	}
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 	if (ret == CFGA_OK) {
14257c478bd9Sstevel@tonic-gate #ifndef	NDEBUG
14267c478bd9Sstevel@tonic-gate 		/*
14277c478bd9Sstevel@tonic-gate 		 * variables used by assert() only which is disabled
14287c478bd9Sstevel@tonic-gate 		 * by defining NDEBUG (see top of this file)
14297c478bd9Sstevel@tonic-gate 		 */
14307c478bd9Sstevel@tonic-gate 		plugin_lib_t *libp;
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate 		libp = lib_loc_p->libp;
14337c478bd9Sstevel@tonic-gate #endif	/* NDEBUG */
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 		assert(strcmp(libp->libpath, lib_loc_p->pathname) == 0);
14367c478bd9Sstevel@tonic-gate 		assert(VALID_HSL_VERS(libp->plugin_vers));
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 		/*
14397c478bd9Sstevel@tonic-gate 		 * If a dynamic component was present, v1 plug-ins are not
14407c478bd9Sstevel@tonic-gate 		 * acceptable.
14417c478bd9Sstevel@tonic-gate 		 */
14427c478bd9Sstevel@tonic-gate 		assert(dyncomp == NULL || libp->plugin_vers >= CFGA_HSL_V2);
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 		/*
14457c478bd9Sstevel@tonic-gate 		 * ap_physical is passed to plugins as their ap_id argument.
14467c478bd9Sstevel@tonic-gate 		 * Append dynamic component if any.
14477c478bd9Sstevel@tonic-gate 		 */
14487c478bd9Sstevel@tonic-gate 		append_dyn(lib_loc_p->ap_physical, dyncomp,
14497c478bd9Sstevel@tonic-gate 		    sizeof (lib_loc_p->ap_physical));
14507c478bd9Sstevel@tonic-gate 	}
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate 	/* cleanup */
14537c478bd9Sstevel@tonic-gate 	lib_loc_p->vers_req.v_min = INVALID_VERSION;
14547c478bd9Sstevel@tonic-gate 	lib_loc_p->vers_req.v_max = INVALID_VERSION;
14557c478bd9Sstevel@tonic-gate 	*lib_loc_p->ap_base = '\0';
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
14587c478bd9Sstevel@tonic-gate out:
14597c478bd9Sstevel@tonic-gate 	S_FREE(apdup);
14607c478bd9Sstevel@tonic-gate 	S_FREE(dyncomp);
14617c478bd9Sstevel@tonic-gate 	if (ret != CFGA_OK) {
14627c478bd9Sstevel@tonic-gate 		lib_loc_p->libp = NULL;
14637c478bd9Sstevel@tonic-gate 	}
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 	assert(ret != CFGA_OK || lib_loc_p->libp != NULL);
14667c478bd9Sstevel@tonic-gate 
14677c478bd9Sstevel@tonic-gate 	return (ret);
14687c478bd9Sstevel@tonic-gate }
14697c478bd9Sstevel@tonic-gate 
1470*26947304SEvan Yan /* load_lib - load library for non-SHP attachment point node */
14717c478bd9Sstevel@tonic-gate static cfga_err_t
14727c478bd9Sstevel@tonic-gate load_lib(
14737c478bd9Sstevel@tonic-gate 	di_node_t node,
14747c478bd9Sstevel@tonic-gate 	di_minor_t minor,
14757c478bd9Sstevel@tonic-gate 	lib_loc_t *libloc_p)
14767c478bd9Sstevel@tonic-gate {
1477*26947304SEvan Yan 	return (load_lib_impl(node, minor, NULL, libloc_p));
1478*26947304SEvan Yan }
1479*26947304SEvan Yan 
1480*26947304SEvan Yan /* load_lib_hp - load library for SHP attachment point node */
1481*26947304SEvan Yan static cfga_err_t
1482*26947304SEvan Yan load_lib_hp(
1483*26947304SEvan Yan 	di_node_t node,
1484*26947304SEvan Yan 	di_hp_t hp,
1485*26947304SEvan Yan 	lib_loc_t *libloc_p)
1486*26947304SEvan Yan {
1487*26947304SEvan Yan 	return (load_lib_impl(node, NULL, hp, libloc_p));
1488*26947304SEvan Yan }
1489*26947304SEvan Yan 
1490*26947304SEvan Yan /*
1491*26947304SEvan Yan  * load_lib_impl - Given a library pathname, create a entry for it
1492*26947304SEvan Yan  * in the library list, * if one does not already exist, and read
1493*26947304SEvan Yan  * lock it to keep it there.
1494*26947304SEvan Yan  */
1495*26947304SEvan Yan static cfga_err_t
1496*26947304SEvan Yan load_lib_impl(
1497*26947304SEvan Yan 	di_node_t node,
1498*26947304SEvan Yan 	di_minor_t minor,
1499*26947304SEvan Yan 	di_hp_t hp,
1500*26947304SEvan Yan 	lib_loc_t *libloc_p)
1501*26947304SEvan Yan {
15027c478bd9Sstevel@tonic-gate 	plugin_lib_t *libp, *list_libp;
15037c478bd9Sstevel@tonic-gate 	char *devfs_path;
1504*26947304SEvan Yan 	char *name;
1505*26947304SEvan Yan 
1506*26947304SEvan Yan 	if (minor != DI_MINOR_NIL && hp != DI_HP_NIL)
1507*26947304SEvan Yan 		return (CFGA_LIB_ERROR);
1508*26947304SEvan Yan 
1509*26947304SEvan Yan 	if (minor != DI_MINOR_NIL)
1510*26947304SEvan Yan 		name = di_minor_name(minor);
1511*26947304SEvan Yan 	else
1512*26947304SEvan Yan 		name = di_hp_name(hp);
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate 	/*
15157c478bd9Sstevel@tonic-gate 	 * lock the library list
15167c478bd9Sstevel@tonic-gate 	 */
15177c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&plugin_list_lock);
15187c478bd9Sstevel@tonic-gate 
15197c478bd9Sstevel@tonic-gate 	/*
15207c478bd9Sstevel@tonic-gate 	 * see if lib exist in list, if not, allocate a new one
15217c478bd9Sstevel@tonic-gate 	 */
15227c478bd9Sstevel@tonic-gate 	list_libp = lib_in_list(libloc_p->pathname);
15237c478bd9Sstevel@tonic-gate 	if (list_libp != NULL) {
15247c478bd9Sstevel@tonic-gate 		hold_lib(list_libp);
15257c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&plugin_list_lock);
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 		/* fill in logical and physical name in libloc_p */
15287c478bd9Sstevel@tonic-gate 		libloc_p->libp = libp = list_libp;
1529*26947304SEvan Yan 		if (minor != DI_MINOR_NIL) {
15307c478bd9Sstevel@tonic-gate 			if (libp->vers_ops->mklog(node, minor, libp, libloc_p)
15317c478bd9Sstevel@tonic-gate 			    != CFGA_OK) {
15327c478bd9Sstevel@tonic-gate 				rele_lib(list_libp);
15337c478bd9Sstevel@tonic-gate 				return (CFGA_LIB_ERROR);
15347c478bd9Sstevel@tonic-gate 			}
1535*26947304SEvan Yan 		} else {
1536*26947304SEvan Yan 			if (mklog_hp(node, hp, libp, libloc_p) != CFGA_OK) {
1537*26947304SEvan Yan 				rele_lib(list_libp);
1538*26947304SEvan Yan 				return (CFGA_LIB_ERROR);
1539*26947304SEvan Yan 			}
1540*26947304SEvan Yan 		}
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 		devfs_path = di_devfs_path(node);
15437c478bd9Sstevel@tonic-gate 		(void) snprintf(libloc_p->ap_physical, MAXPATHLEN, "%s%s:%s",
1544*26947304SEvan Yan 		    DEVICES_DIR, devfs_path, name);
15457c478bd9Sstevel@tonic-gate 		di_devfs_path_free(devfs_path);
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate 		return (CFGA_OK);
15487c478bd9Sstevel@tonic-gate 	}
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	/* allocate a new plugin_lib_t structure */
15517c478bd9Sstevel@tonic-gate 	libp = config_calloc_check(1, sizeof (plugin_lib_t), NULL);
15527c478bd9Sstevel@tonic-gate 	if (libp == NULL) {
15537c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&plugin_list_lock);
15547c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
15557c478bd9Sstevel@tonic-gate 	}
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 	(void) snprintf(libp->libpath, sizeof (libp->libpath), "%s",
15587c478bd9Sstevel@tonic-gate 	    libloc_p->pathname);
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 	/*
15617c478bd9Sstevel@tonic-gate 	 * ensure that the lib is open and linked in
15627c478bd9Sstevel@tonic-gate 	 */
15637c478bd9Sstevel@tonic-gate 	libp->handle = dlopen(libp->libpath, RTLD_NOW);
15647c478bd9Sstevel@tonic-gate 	if (libp->handle == NULL) {
15657c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&plugin_list_lock);
15667c478bd9Sstevel@tonic-gate 		free(libp);
15677c478bd9Sstevel@tonic-gate 		return (CFGA_NO_LIB);
15687c478bd9Sstevel@tonic-gate 	}
15697c478bd9Sstevel@tonic-gate 
1570*26947304SEvan Yan 	if (minor != DI_MINOR_NIL) {
15717c478bd9Sstevel@tonic-gate 		if (resolve_lib_ref(libp, libloc_p) != CFGA_OK ||
1572*26947304SEvan Yan 		    libp->vers_ops->mklog(node, minor, libp, libloc_p)
1573*26947304SEvan Yan 		    != CFGA_OK) {
15747c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&plugin_list_lock);
15757c478bd9Sstevel@tonic-gate 			(void) dlclose(libp->handle);
15767c478bd9Sstevel@tonic-gate 			free(libp);
15777c478bd9Sstevel@tonic-gate 			return (CFGA_NO_LIB);
15787c478bd9Sstevel@tonic-gate 		}
1579*26947304SEvan Yan 	} else {
1580*26947304SEvan Yan 		if (resolve_lib_ref(libp, libloc_p) != CFGA_OK ||
1581*26947304SEvan Yan 		    mklog_hp(node, hp, libp, libloc_p) != CFGA_OK) {
1582*26947304SEvan Yan 			(void) mutex_unlock(&plugin_list_lock);
1583*26947304SEvan Yan 			(void) dlclose(libp->handle);
1584*26947304SEvan Yan 			free(libp);
1585*26947304SEvan Yan 			return (CFGA_NO_LIB);
1586*26947304SEvan Yan 		}
1587*26947304SEvan Yan 	}
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 	/*
15907c478bd9Sstevel@tonic-gate 	 * link in new entry to the end of list
15917c478bd9Sstevel@tonic-gate 	 */
15927c478bd9Sstevel@tonic-gate 	list_libp = &plugin_list;
15937c478bd9Sstevel@tonic-gate 	while (list_libp->next != NULL)
15947c478bd9Sstevel@tonic-gate 		list_libp = list_libp->next;
15957c478bd9Sstevel@tonic-gate 	libp->next = list_libp->next;
15967c478bd9Sstevel@tonic-gate 	list_libp->next = libp;
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate 	/* Initialize refcnt to 1 */
15997c478bd9Sstevel@tonic-gate 	libp->refcnt = 1;
16007c478bd9Sstevel@tonic-gate 	(void) mutex_init(&libp->lock, USYNC_THREAD, NULL);
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&plugin_list_lock);
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate 	/*
16057c478bd9Sstevel@tonic-gate 	 * record libp and physical node name in the libloc struct
16067c478bd9Sstevel@tonic-gate 	 */
16077c478bd9Sstevel@tonic-gate 	libloc_p->libp = libp;
16087c478bd9Sstevel@tonic-gate 	devfs_path = di_devfs_path(node);
16097c478bd9Sstevel@tonic-gate 	(void) snprintf(libloc_p->ap_physical, MAXPATHLEN, "%s%s:%s",
1610*26947304SEvan Yan 	    DEVICES_DIR, devfs_path, name);
16117c478bd9Sstevel@tonic-gate 	di_devfs_path_free(devfs_path);
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 	return (CFGA_OK);
16147c478bd9Sstevel@tonic-gate }
16157c478bd9Sstevel@tonic-gate 
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate #define	NUM_LIB_NAMES   2
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate /*
1620*26947304SEvan Yan  * find_lib - find library for non-SHP attachment point node
16217c478bd9Sstevel@tonic-gate  */
16227c478bd9Sstevel@tonic-gate static cfga_err_t
16237c478bd9Sstevel@tonic-gate find_lib(
16247c478bd9Sstevel@tonic-gate 	di_node_t node,
16257c478bd9Sstevel@tonic-gate 	di_minor_t minor,
16267c478bd9Sstevel@tonic-gate 	lib_loc_t *libloc_p)
16277c478bd9Sstevel@tonic-gate {
16287c478bd9Sstevel@tonic-gate 	char name[NUM_LIB_NAMES][MAXPATHLEN];
16297c478bd9Sstevel@tonic-gate 	char *class = NULL, *drv = NULL;
1630*26947304SEvan Yan 	int i;
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 	/* Make sure pathname and class is null if we fail */
1634*26947304SEvan Yan 	*libloc_p->ap_class = *libloc_p->pathname = '\0';
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 	/*
16377c478bd9Sstevel@tonic-gate 	 * Initialize possible library tags.
16387c478bd9Sstevel@tonic-gate 	 */
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 	drv = di_driver_name(node);
16417c478bd9Sstevel@tonic-gate 	class = get_class(minor);
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 	if (drv == NULL || class == NULL) {
16447c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
16457c478bd9Sstevel@tonic-gate 	}
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 	i = 0;
16487c478bd9Sstevel@tonic-gate 	(void) snprintf(&name[i++][0], sizeof (name[0]), "%s", drv);
16497c478bd9Sstevel@tonic-gate 	(void) snprintf(&name[i++][0], sizeof (name[0]), "%s", class);
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	/*
16527c478bd9Sstevel@tonic-gate 	 * Cycle through the array of names to find the library.
16537c478bd9Sstevel@tonic-gate 	 */
16547c478bd9Sstevel@tonic-gate 	for (i = 0; i < NUM_LIB_NAMES; i++) {
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 		/* Attachment points may not have a class (i.e. are generic) */
16577c478bd9Sstevel@tonic-gate 		if (name[i][0] == '\0') {
16587c478bd9Sstevel@tonic-gate 			continue;
16597c478bd9Sstevel@tonic-gate 		}
16607c478bd9Sstevel@tonic-gate 
1661*26947304SEvan Yan 		if (find_lib_impl(name[i], libloc_p) == CFGA_OK)
1662*26947304SEvan Yan 			goto found;
1663*26947304SEvan Yan 	}
1664*26947304SEvan Yan 
1665*26947304SEvan Yan 	return (CFGA_NO_LIB);
1666*26947304SEvan Yan 
1667*26947304SEvan Yan found:
1668*26947304SEvan Yan 
1669*26947304SEvan Yan 	/* Record class name (if any) */
1670*26947304SEvan Yan 	(void) snprintf(libloc_p->ap_class, sizeof (libloc_p->ap_class), "%s",
1671*26947304SEvan Yan 	    class);
1672*26947304SEvan Yan 
1673*26947304SEvan Yan 	return (CFGA_OK);
1674*26947304SEvan Yan }
1675*26947304SEvan Yan 
1676*26947304SEvan Yan /*
1677*26947304SEvan Yan  * find_lib_hp - find library for SHP attachment point
1678*26947304SEvan Yan  */
1679*26947304SEvan Yan /*ARGSUSED*/
1680*26947304SEvan Yan static cfga_err_t
1681*26947304SEvan Yan find_lib_hp(
1682*26947304SEvan Yan 	di_node_t node,
1683*26947304SEvan Yan 	di_hp_t hp,
1684*26947304SEvan Yan 	lib_loc_t *libloc_p)
1685*26947304SEvan Yan {
1686*26947304SEvan Yan 	char name[MAXPATHLEN];
1687*26947304SEvan Yan 	char *class = NULL;
1688*26947304SEvan Yan 
1689*26947304SEvan Yan 
1690*26947304SEvan Yan 	/* Make sure pathname and class is null if we fail */
1691*26947304SEvan Yan 	*libloc_p->ap_class = *libloc_p->pathname = '\0';
1692*26947304SEvan Yan 
1693*26947304SEvan Yan 	/*
1694*26947304SEvan Yan 	 * Initialize possible library tags.
1695*26947304SEvan Yan 	 *
1696*26947304SEvan Yan 	 * Only support PCI class for now, this will need to be
1697*26947304SEvan Yan 	 * changed as other plugins are migrated to SHP plugin.
1698*26947304SEvan Yan 	 */
1699*26947304SEvan Yan 	class = "pci";
1700*26947304SEvan Yan #if 0
1701*26947304SEvan Yan 	/*
1702*26947304SEvan Yan 	 * No type check for now as PCI is the only class SHP plugin
1703*26947304SEvan Yan 	 * supports. In the future we'll need to enable the type check
1704*26947304SEvan Yan 	 * and set class accordingly, when non PCI plugins are migrated
1705*26947304SEvan Yan 	 * to SHP. In that case we'll probably need to add an additional
1706*26947304SEvan Yan 	 * interface between libcfgadm and the plugins, and SHP plugin will
1707*26947304SEvan Yan 	 * implement this interface which will translate the bus specific
1708*26947304SEvan Yan 	 * strings to standard classes that libcfgadm can recognize, for
1709*26947304SEvan Yan 	 * all the buses it supports, e.g. for pci/pcie it will translate
1710*26947304SEvan Yan 	 * PCIE_NATIVE_HP_TYPE to string "pci". We'll also need to bump up
1711*26947304SEvan Yan 	 * SHP plugin version to 3 to use the new interface.
1712*26947304SEvan Yan 	 */
1713*26947304SEvan Yan 	class = di_hp_type(hp);
1714*26947304SEvan Yan 	if ((strcmp(class, PCIE_NATIVE_HP_TYPE) == 0) ||
1715*26947304SEvan Yan 	    (strcmp(class, PCIE_ACPI_HP_TYPE) == 0) ||
1716*26947304SEvan Yan 	    (strcmp(class, PCIE_PCI_HP_TYPE) == 0)) {
1717*26947304SEvan Yan 		class = "pci";
1718*26947304SEvan Yan 	} else {
1719*26947304SEvan Yan 		goto fail;
1720*26947304SEvan Yan 	}
1721*26947304SEvan Yan #endif
1722*26947304SEvan Yan 	(void) snprintf(&name[0], sizeof (name), "%s", "shp");
1723*26947304SEvan Yan 
1724*26947304SEvan Yan 	if (find_lib_impl(name, libloc_p) == CFGA_OK)
1725*26947304SEvan Yan 		goto found;
1726*26947304SEvan Yan fail:
1727*26947304SEvan Yan 	return (CFGA_NO_LIB);
1728*26947304SEvan Yan 
1729*26947304SEvan Yan found:
1730*26947304SEvan Yan 
1731*26947304SEvan Yan 	/* Record class name (if any) */
1732*26947304SEvan Yan 	(void) snprintf(libloc_p->ap_class, sizeof (libloc_p->ap_class), "%s",
1733*26947304SEvan Yan 	    class);
1734*26947304SEvan Yan 
1735*26947304SEvan Yan 	return (CFGA_OK);
1736*26947304SEvan Yan }
1737*26947304SEvan Yan 
1738*26947304SEvan Yan /*
1739*26947304SEvan Yan  * find_lib_impl - Given an attachment point node find it's library
1740*26947304SEvan Yan  */
1741*26947304SEvan Yan static cfga_err_t
1742*26947304SEvan Yan find_lib_impl(
1743*26947304SEvan Yan 	char *name,
1744*26947304SEvan Yan 	lib_loc_t *libloc_p)
1745*26947304SEvan Yan {
1746*26947304SEvan Yan 	char lib[MAXPATHLEN];
1747*26947304SEvan Yan 	struct stat lib_stat;
1748*26947304SEvan Yan 	void *dlhandle = NULL;
1749*26947304SEvan Yan 	static char plat_name[SYSINFO_LENGTH];
1750*26947304SEvan Yan 	static char machine_name[SYSINFO_LENGTH];
1751*26947304SEvan Yan 	static char arch_name[SYSINFO_LENGTH];
1752*26947304SEvan Yan 
1753*26947304SEvan Yan 	/*
1754*26947304SEvan Yan 	 * Initialize machine name and arch name
1755*26947304SEvan Yan 	 */
1756*26947304SEvan Yan 	if (strncmp("", machine_name, MAXPATHLEN) == 0) {
1757*26947304SEvan Yan 		if (sysinfo(SI_PLATFORM, plat_name, SYSINFO_LENGTH) == -1) {
1758*26947304SEvan Yan 			return (CFGA_ERROR);
1759*26947304SEvan Yan 		}
1760*26947304SEvan Yan 		if (sysinfo(SI_ARCHITECTURE, arch_name, SYSINFO_LENGTH) == -1) {
1761*26947304SEvan Yan 			return (CFGA_ERROR);
1762*26947304SEvan Yan 		}
1763*26947304SEvan Yan 		if (sysinfo(SI_MACHINE, machine_name, SYSINFO_LENGTH) == -1) {
1764*26947304SEvan Yan 			return (CFGA_ERROR);
1765*26947304SEvan Yan 		}
1766*26947304SEvan Yan 	}
1767*26947304SEvan Yan 
17687c478bd9Sstevel@tonic-gate 	/*
176909fe1b16Sdnielsen 	 * Try path based upon platform name
177009fe1b16Sdnielsen 	 */
177109fe1b16Sdnielsen 	(void) snprintf(lib, sizeof (lib), "%s%s%s%s%s",
177209fe1b16Sdnielsen 	    LIB_PATH_BASE1, plat_name, LIB_PATH_MIDDLE,
1773*26947304SEvan Yan 	    name, LIB_PATH_TAIL);
177409fe1b16Sdnielsen 
177509fe1b16Sdnielsen 	if (stat(lib, &lib_stat) == 0) {
177609fe1b16Sdnielsen 		/* file exists, is it a lib */
177709fe1b16Sdnielsen 		dlhandle = dlopen(lib, RTLD_LAZY);
177809fe1b16Sdnielsen 		if (dlhandle != NULL) {
177909fe1b16Sdnielsen 			goto found;
178009fe1b16Sdnielsen 		}
178109fe1b16Sdnielsen 	}
178209fe1b16Sdnielsen 
178309fe1b16Sdnielsen 	/*
17847c478bd9Sstevel@tonic-gate 	 * Try path based upon machine name
17857c478bd9Sstevel@tonic-gate 	 */
17867c478bd9Sstevel@tonic-gate 	(void) snprintf(lib, sizeof (lib), "%s%s%s%s%s",
17877c478bd9Sstevel@tonic-gate 	    LIB_PATH_BASE1, machine_name, LIB_PATH_MIDDLE,
1788*26947304SEvan Yan 	    name, LIB_PATH_TAIL);
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	if (stat(lib, &lib_stat) == 0) {
17927c478bd9Sstevel@tonic-gate 		/* file exists, is it a lib */
17937c478bd9Sstevel@tonic-gate 		dlhandle = dlopen(lib, RTLD_LAZY);
17947c478bd9Sstevel@tonic-gate 		if (dlhandle != NULL) {
17957c478bd9Sstevel@tonic-gate 			goto found;
17967c478bd9Sstevel@tonic-gate 		}
17977c478bd9Sstevel@tonic-gate 	}
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate 	/*
18007c478bd9Sstevel@tonic-gate 	 * Try path based upon arch name
18017c478bd9Sstevel@tonic-gate 	 */
18027c478bd9Sstevel@tonic-gate 	(void) snprintf(lib, sizeof (lib), "%s%s%s%s%s",
18037c478bd9Sstevel@tonic-gate 	    LIB_PATH_BASE1, arch_name, LIB_PATH_MIDDLE,
1804*26947304SEvan Yan 	    name, LIB_PATH_TAIL);
18057c478bd9Sstevel@tonic-gate 
18067c478bd9Sstevel@tonic-gate 	if (stat(lib, &lib_stat) == 0) {
18077c478bd9Sstevel@tonic-gate 		/* file exists, is it a lib */
18087c478bd9Sstevel@tonic-gate 		dlhandle = dlopen(lib, RTLD_LAZY);
18097c478bd9Sstevel@tonic-gate 		if (dlhandle != NULL) {
18107c478bd9Sstevel@tonic-gate 			goto found;
18117c478bd9Sstevel@tonic-gate 		}
18127c478bd9Sstevel@tonic-gate 
18137c478bd9Sstevel@tonic-gate 	}
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 	/*
18167c478bd9Sstevel@tonic-gate 	 * Try generic location
18177c478bd9Sstevel@tonic-gate 	 */
18187c478bd9Sstevel@tonic-gate 	(void) snprintf(lib, sizeof (lib), "%s%s%s%s",
1819*26947304SEvan Yan 	    LIB_PATH_BASE2, LIB_PATH_MIDDLE, name, LIB_PATH_TAIL);
18207c478bd9Sstevel@tonic-gate 
18217c478bd9Sstevel@tonic-gate 	if (stat(lib, &lib_stat) == 0) {
18227c478bd9Sstevel@tonic-gate 		/* file exists, is it a lib */
18237c478bd9Sstevel@tonic-gate 		dlhandle = dlopen(lib, RTLD_LAZY);
18247c478bd9Sstevel@tonic-gate 		if (dlhandle != NULL) {
18257c478bd9Sstevel@tonic-gate 			goto found;
18267c478bd9Sstevel@tonic-gate 		}
18277c478bd9Sstevel@tonic-gate 
18287c478bd9Sstevel@tonic-gate 	}
18297c478bd9Sstevel@tonic-gate 	return (CFGA_NO_LIB);
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate found:
18327c478bd9Sstevel@tonic-gate 	/* we got one! */
18337c478bd9Sstevel@tonic-gate 	(void) snprintf(libloc_p->pathname, sizeof (libloc_p->pathname), "%s",
18347c478bd9Sstevel@tonic-gate 	    lib);
18357c478bd9Sstevel@tonic-gate 
18367c478bd9Sstevel@tonic-gate 	(void) dlclose(dlhandle);
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 	return (CFGA_OK);
18397c478bd9Sstevel@tonic-gate }
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate static cfga_err_t
18427c478bd9Sstevel@tonic-gate lookup_cache(lib_loc_t *libloc_p)
18437c478bd9Sstevel@tonic-gate {
18447c478bd9Sstevel@tonic-gate 	lib_cache_t *entry;
18457c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&lib_cache_lock);
18467c478bd9Sstevel@tonic-gate 	entry = lib_cache;
18477c478bd9Sstevel@tonic-gate 	while (entry) {
18487c478bd9Sstevel@tonic-gate 		if (strcmp(entry->lc_ap_id, libloc_p->ap_base) == 0) {
18497c478bd9Sstevel@tonic-gate 			plugin_lib_t *libp = entry->lc_libp;
18507c478bd9Sstevel@tonic-gate 			libloc_p->libp = libp;
18517c478bd9Sstevel@tonic-gate 			hold_lib(libp);
18527c478bd9Sstevel@tonic-gate 			(void) strcpy(libloc_p->pathname, libp->libpath);
18537c478bd9Sstevel@tonic-gate 			(void) strcpy(libloc_p->ap_physical,
18547c478bd9Sstevel@tonic-gate 			    entry->lc_ap_physical);
18557c478bd9Sstevel@tonic-gate 			(void) strcpy(libloc_p->ap_logical,
18567c478bd9Sstevel@tonic-gate 			    entry->lc_ap_logical);
18577c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&lib_cache_lock);
18587c478bd9Sstevel@tonic-gate 			return (CFGA_OK);
18597c478bd9Sstevel@tonic-gate 		}
18607c478bd9Sstevel@tonic-gate 		entry = entry->lc_next;
18617c478bd9Sstevel@tonic-gate 	}
18627c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&lib_cache_lock);
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate 	return (CFGA_ERROR);
18657c478bd9Sstevel@tonic-gate }
18667c478bd9Sstevel@tonic-gate 
18677c478bd9Sstevel@tonic-gate static void
18687c478bd9Sstevel@tonic-gate update_cache(lib_loc_t *libloc_p)
18697c478bd9Sstevel@tonic-gate {
18707c478bd9Sstevel@tonic-gate 	lib_cache_t *entry;
18717c478bd9Sstevel@tonic-gate 	entry = config_calloc_check(1, sizeof (lib_cache_t), NULL);
18727c478bd9Sstevel@tonic-gate 	if (entry == NULL)
18737c478bd9Sstevel@tonic-gate 		return;
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate 	entry->lc_ap_id = strdup(libloc_p->ap_base);
18767c478bd9Sstevel@tonic-gate 	entry->lc_ap_physical = strdup(libloc_p->ap_physical);
18777c478bd9Sstevel@tonic-gate 	entry->lc_ap_logical = strdup(libloc_p->ap_logical);
18787c478bd9Sstevel@tonic-gate 	if ((entry->lc_ap_id == NULL) || (entry->lc_ap_physical == NULL) ||
18797c478bd9Sstevel@tonic-gate 	    (entry->lc_ap_logical == NULL)) {
18807c478bd9Sstevel@tonic-gate 		free(entry->lc_ap_id);
18817c478bd9Sstevel@tonic-gate 		free(entry->lc_ap_physical);
18827c478bd9Sstevel@tonic-gate 		free(entry->lc_ap_logical);
18837c478bd9Sstevel@tonic-gate 		free(entry);
18847c478bd9Sstevel@tonic-gate 		return;
18857c478bd9Sstevel@tonic-gate 	}
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&lib_cache_lock);
18887c478bd9Sstevel@tonic-gate 	entry->lc_libp = libloc_p->libp;
18897c478bd9Sstevel@tonic-gate 	entry->lc_next = lib_cache;
18907c478bd9Sstevel@tonic-gate 	lib_cache = entry;
18917c478bd9Sstevel@tonic-gate 	hold_lib(entry->lc_libp);	/* prevent stale cache */
18927c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&lib_cache_lock);
18937c478bd9Sstevel@tonic-gate }
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate static void
18967c478bd9Sstevel@tonic-gate destroy_cache()
18977c478bd9Sstevel@tonic-gate {
18987c478bd9Sstevel@tonic-gate 	lib_cache_t *entry, *next;
18997c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&lib_cache_lock);
19007c478bd9Sstevel@tonic-gate 	entry = lib_cache;
19017c478bd9Sstevel@tonic-gate 	while (entry) {
19027c478bd9Sstevel@tonic-gate 		next = entry->lc_next;
19037c478bd9Sstevel@tonic-gate 		rele_lib(entry->lc_libp);
19047c478bd9Sstevel@tonic-gate 		free(entry->lc_ap_id);
19057c478bd9Sstevel@tonic-gate 		free(entry->lc_ap_physical);
19067c478bd9Sstevel@tonic-gate 		free(entry->lc_ap_logical);
19077c478bd9Sstevel@tonic-gate 		free(entry);
19087c478bd9Sstevel@tonic-gate 		entry = next;
19097c478bd9Sstevel@tonic-gate 	}
19107c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&lib_cache_lock);
19117c478bd9Sstevel@tonic-gate }
19127c478bd9Sstevel@tonic-gate 
19137c478bd9Sstevel@tonic-gate /*
19147c478bd9Sstevel@tonic-gate  * find_ap_common - locate a particular attachment point
19157c478bd9Sstevel@tonic-gate  */
19167c478bd9Sstevel@tonic-gate static cfga_err_t
19177c478bd9Sstevel@tonic-gate find_ap_common(
19187c478bd9Sstevel@tonic-gate 	lib_loc_t *libloc_p,
19197c478bd9Sstevel@tonic-gate 	const char *physpath,
19207c478bd9Sstevel@tonic-gate 	int (*fcn)(di_node_t node, di_minor_t minor, void *arg),
1921*26947304SEvan Yan 	int (*fcn_hp)(di_node_t node, di_hp_t hp, void *arg),
19227c478bd9Sstevel@tonic-gate 	char **errstring)
19237c478bd9Sstevel@tonic-gate {
19249595f109Scth 	di_node_t rnode, wnode;
19257c478bd9Sstevel@tonic-gate 	char *cp, *rpath;
19267c478bd9Sstevel@tonic-gate 	size_t len;
19277c478bd9Sstevel@tonic-gate 
19287c478bd9Sstevel@tonic-gate 	if (lookup_cache(libloc_p) == CFGA_OK)
19297c478bd9Sstevel@tonic-gate 		return (CFGA_OK);
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate 	if ((rpath = config_calloc_check(1, strlen(physpath) + 1,
19327c478bd9Sstevel@tonic-gate 	    errstring)) == NULL) {
19337c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
19347c478bd9Sstevel@tonic-gate 	}
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 	(void) strcpy(rpath, physpath);
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate 	/* Remove devices prefix (if any) */
19397c478bd9Sstevel@tonic-gate 	len = strlen(DEVICES_DIR);
19407c478bd9Sstevel@tonic-gate 	if (strncmp(rpath, DEVICES_DIR SLASH, len + strlen(SLASH)) == 0) {
19417c478bd9Sstevel@tonic-gate 		(void) memmove(rpath, rpath + len,
19427c478bd9Sstevel@tonic-gate 		    strlen(rpath + len) + 1);
19437c478bd9Sstevel@tonic-gate 	}
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate 	/* Remove dynamic component if any */
19467c478bd9Sstevel@tonic-gate 	if ((cp = GET_DYN(rpath)) != NULL) {
19477c478bd9Sstevel@tonic-gate 		*cp = '\0';
19487c478bd9Sstevel@tonic-gate 	}
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 	/* Remove minor name (if any) */
19517c478bd9Sstevel@tonic-gate 	if ((cp = strrchr(rpath, ':')) != NULL) {
19527c478bd9Sstevel@tonic-gate 		*cp = '\0';
19537c478bd9Sstevel@tonic-gate 	}
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate 	/*
19567c478bd9Sstevel@tonic-gate 	 * begin walk of device tree
1957*26947304SEvan Yan 	 *
1958*26947304SEvan Yan 	 * Since we create minor nodes & dev links for both all PCI/PCIE
1959*26947304SEvan Yan 	 * connectors, but only create hp nodes for PCIE/PCISHPC connectors
1960*26947304SEvan Yan 	 * of the new framework, we should first match with hp nodes. If
1961*26947304SEvan Yan 	 * the ap_id refers to a PCIE/PCISHPC connector, we'll be able to
1962*26947304SEvan Yan 	 * find it here.
19637c478bd9Sstevel@tonic-gate 	 */
1964*26947304SEvan Yan 	rnode = di_init("/", DINFOSUBTREE | DINFOHP);
1965*26947304SEvan Yan 	if (rnode)
1966*26947304SEvan Yan 		wnode = di_lookup_node(rnode, rpath);
1967*26947304SEvan Yan 	else
1968*26947304SEvan Yan 		wnode = DI_NODE_NIL;
1969*26947304SEvan Yan 
1970*26947304SEvan Yan 	if (wnode == DI_NODE_NIL) {
1971*26947304SEvan Yan 		if (rnode == DI_NODE_NIL) {
1972*26947304SEvan Yan 			S_FREE(rpath);
1973*26947304SEvan Yan 			config_err(errno, DI_INIT_FAILED, errstring);
1974*26947304SEvan Yan 			return (CFGA_LIB_ERROR);
1975*26947304SEvan Yan 		} else {
1976*26947304SEvan Yan 			/*
1977*26947304SEvan Yan 			 * di_lookup_node() may fail, either because the
1978*26947304SEvan Yan 			 * ap_id does not exist, or because the ap_id refers
1979*26947304SEvan Yan 			 * to a legacy PCI slot, thus we'll not able to
1980*26947304SEvan Yan 			 * find node using DINFOHP, try to see if we can
1981*26947304SEvan Yan 			 * find one using DINFOCACHE.
1982*26947304SEvan Yan 			 */
1983*26947304SEvan Yan 			di_fini(rnode);
1984*26947304SEvan Yan 			goto find_minor;
1985*26947304SEvan Yan 		}
1986*26947304SEvan Yan 	}
1987*26947304SEvan Yan 
1988*26947304SEvan Yan 	libloc_p->libp = NULL;
1989*26947304SEvan Yan 	libloc_p->status = CFGA_APID_NOEXIST;
1990*26947304SEvan Yan 
1991*26947304SEvan Yan 	(void) di_walk_hp(wnode, NULL, DI_HP_CONNECTOR,
1992*26947304SEvan Yan 	    libloc_p, fcn_hp);
1993*26947304SEvan Yan 
1994*26947304SEvan Yan 	di_fini(rnode);
1995*26947304SEvan Yan 
1996*26947304SEvan Yan 	/*
1997*26947304SEvan Yan 	 * Failed to find a matching hp node, try minor node.
1998*26947304SEvan Yan 	 */
1999*26947304SEvan Yan 	if (libloc_p->libp == NULL) {
2000*26947304SEvan Yan find_minor:
20019595f109Scth 		rnode = di_init("/", DINFOCACHE);
20029595f109Scth 		if (rnode)
20039595f109Scth 			wnode = di_lookup_node(rnode, rpath);
20049595f109Scth 		else
20059595f109Scth 			wnode = DI_NODE_NIL;
20067c478bd9Sstevel@tonic-gate 
20079595f109Scth 		if (wnode == DI_NODE_NIL) {
20087c478bd9Sstevel@tonic-gate 			if (rnode == DI_NODE_NIL) {
2009*26947304SEvan Yan 				S_FREE(rpath);
20107c478bd9Sstevel@tonic-gate 				config_err(errno, DI_INIT_FAILED, errstring);
20117c478bd9Sstevel@tonic-gate 				return (CFGA_LIB_ERROR);
20129595f109Scth 			} else {
20139595f109Scth 				/*
2014*26947304SEvan Yan 				 * di_lookup_node() may fail, because the
2015*26947304SEvan Yan 				 * ap_id does not exist.
20169595f109Scth 				 */
2017*26947304SEvan Yan 				S_FREE(rpath);
20189595f109Scth 				di_fini(rnode);
20199595f109Scth 				return (CFGA_APID_NOEXIST);
20207c478bd9Sstevel@tonic-gate 			}
20217c478bd9Sstevel@tonic-gate 		}
20227c478bd9Sstevel@tonic-gate 
20237c478bd9Sstevel@tonic-gate 		libloc_p->libp = NULL;
20247c478bd9Sstevel@tonic-gate 		libloc_p->status = CFGA_APID_NOEXIST;
20257c478bd9Sstevel@tonic-gate 
20269595f109Scth 		(void) di_walk_minor(wnode, "ddi_ctl:attachment_point",
20277c478bd9Sstevel@tonic-gate 		    DI_CHECK_ALIAS|DI_CHECK_INTERNAL_PATH,
20287c478bd9Sstevel@tonic-gate 		    libloc_p, fcn);
20297c478bd9Sstevel@tonic-gate 
20307c478bd9Sstevel@tonic-gate 		di_fini(rnode);
2031*26947304SEvan Yan 	}
2032*26947304SEvan Yan 
2033*26947304SEvan Yan 	S_FREE(rpath);
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate 	if (libloc_p->libp != NULL) {
20367c478bd9Sstevel@tonic-gate 		update_cache(libloc_p);
20377c478bd9Sstevel@tonic-gate 		return (CFGA_OK);
20387c478bd9Sstevel@tonic-gate 	} else {
20397c478bd9Sstevel@tonic-gate 		return (libloc_p->status);
20407c478bd9Sstevel@tonic-gate 	}
20417c478bd9Sstevel@tonic-gate }
20427c478bd9Sstevel@tonic-gate 
20437c478bd9Sstevel@tonic-gate /*
2044*26947304SEvan Yan  * check_ap - called for each non-SHP attachment point found
2045*26947304SEvan Yan  */
2046*26947304SEvan Yan static int
2047*26947304SEvan Yan check_ap(
2048*26947304SEvan Yan 	di_node_t node,
2049*26947304SEvan Yan 	di_minor_t minor,
2050*26947304SEvan Yan 	void *arg)
2051*26947304SEvan Yan {
2052*26947304SEvan Yan 	return (check_ap_impl(node, minor, NULL, arg));
2053*26947304SEvan Yan }
2054*26947304SEvan Yan 
2055*26947304SEvan Yan /*
2056*26947304SEvan Yan  * check_ap_hp - called for each SHP attachment point found
2057*26947304SEvan Yan  */
2058*26947304SEvan Yan static int
2059*26947304SEvan Yan check_ap_hp(
2060*26947304SEvan Yan 	di_node_t node,
2061*26947304SEvan Yan 	di_hp_t hp,
2062*26947304SEvan Yan 	void *arg)
2063*26947304SEvan Yan {
2064*26947304SEvan Yan 	return (check_ap_impl(node, NULL, hp, arg));
2065*26947304SEvan Yan }
2066*26947304SEvan Yan 
2067*26947304SEvan Yan /*
2068*26947304SEvan Yan  * check_ap_impl - called for each attachment point found
20697c478bd9Sstevel@tonic-gate  *
20707c478bd9Sstevel@tonic-gate  * This is used in cases where a particular attachment point
20717c478bd9Sstevel@tonic-gate  * or type of attachment point is specified via a logical name or ap_type.
20727c478bd9Sstevel@tonic-gate  * Not used for physical names or in the list case with no
20737c478bd9Sstevel@tonic-gate  * ap's specified.
20747c478bd9Sstevel@tonic-gate  */
20757c478bd9Sstevel@tonic-gate static int
2076*26947304SEvan Yan check_ap_impl(
20777c478bd9Sstevel@tonic-gate 	di_node_t node,
20787c478bd9Sstevel@tonic-gate 	di_minor_t minor,
2079*26947304SEvan Yan 	di_hp_t hp,
20807c478bd9Sstevel@tonic-gate 	void *arg)
20817c478bd9Sstevel@tonic-gate {
20827c478bd9Sstevel@tonic-gate 	char *cp = NULL;
20837c478bd9Sstevel@tonic-gate 	char aptype[MAXPATHLEN];
20847c478bd9Sstevel@tonic-gate 	char *recep_id = NULL;
20857c478bd9Sstevel@tonic-gate 	char *node_minor;
20867c478bd9Sstevel@tonic-gate 	char *drv_name;
20877c478bd9Sstevel@tonic-gate 	char inst[MAXPATHLEN];
20887c478bd9Sstevel@tonic-gate 	char inst2[MAXPATHLEN];
20897c478bd9Sstevel@tonic-gate 	lib_loc_t *libloc_p;
20907c478bd9Sstevel@tonic-gate 	int comparison_test;
20917c478bd9Sstevel@tonic-gate 	int instance;
20927c478bd9Sstevel@tonic-gate 	cfga_ap_types_t type;
20937c478bd9Sstevel@tonic-gate 
2094*26947304SEvan Yan 	if (minor != DI_MINOR_NIL && hp != DI_HP_NIL)
2095*26947304SEvan Yan 		return (DI_WALK_CONTINUE);
20967c478bd9Sstevel@tonic-gate 
20977c478bd9Sstevel@tonic-gate 	libloc_p = (lib_loc_t *)arg;
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 	(void) snprintf(aptype, sizeof (aptype), "%s", libloc_p->ap_base);
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 	/*
21027c478bd9Sstevel@tonic-gate 	 * This routime handles only aptypes and driver based logical apids.
21037c478bd9Sstevel@tonic-gate 	 */
21047c478bd9Sstevel@tonic-gate 	type = find_arg_type(aptype);
21057c478bd9Sstevel@tonic-gate 	if (type == LOGICAL_DRV_AP) {
21067c478bd9Sstevel@tonic-gate 		cp = strchr(aptype, ':');
21077c478bd9Sstevel@tonic-gate 		*cp = '\0';
21087c478bd9Sstevel@tonic-gate 		recep_id =  cp+1;
21097c478bd9Sstevel@tonic-gate 		cp--;
21107c478bd9Sstevel@tonic-gate 		while (isdigit(*cp) && cp != aptype)
21117c478bd9Sstevel@tonic-gate 			cp--;
21127c478bd9Sstevel@tonic-gate 		cp++;
21137c478bd9Sstevel@tonic-gate 
21147c478bd9Sstevel@tonic-gate 		(void) snprintf(inst, sizeof (inst), "%s", cp);
21157c478bd9Sstevel@tonic-gate 
21167c478bd9Sstevel@tonic-gate 		*cp = '\0';
21177c478bd9Sstevel@tonic-gate 	} else if (type != AP_TYPE) {
21187c478bd9Sstevel@tonic-gate 		libloc_p->status = CFGA_APID_NOEXIST;
21197c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
21207c478bd9Sstevel@tonic-gate 	}
21217c478bd9Sstevel@tonic-gate 
2122*26947304SEvan Yan 	if (minor != DI_MINOR_NIL)
21237c478bd9Sstevel@tonic-gate 		node_minor = di_minor_name(minor);
2124*26947304SEvan Yan 	else
2125*26947304SEvan Yan 		node_minor = di_hp_name(hp);
2126*26947304SEvan Yan 
21277c478bd9Sstevel@tonic-gate 	drv_name = di_driver_name(node);
21287c478bd9Sstevel@tonic-gate 	instance = di_instance(node);
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate 	if (node_minor == NULL || drv_name == NULL || instance == -1) {
21317c478bd9Sstevel@tonic-gate 		libloc_p->status = CFGA_APID_NOEXIST;
21327c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
21337c478bd9Sstevel@tonic-gate 	}
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate 	(void) sprintf(inst2, "%d", instance);
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate 	/*
21387c478bd9Sstevel@tonic-gate 	 * If the base matches driver and instance try and find a lib for it,
21397c478bd9Sstevel@tonic-gate 	 * then load it. On any failure we continue the walk.
21407c478bd9Sstevel@tonic-gate 	 *
21417c478bd9Sstevel@tonic-gate 	 * driver based logical ap_ids are derived from driver name + instance.
21427c478bd9Sstevel@tonic-gate 	 * Ap_types are just partial driver names.
21437c478bd9Sstevel@tonic-gate 	 *
21447c478bd9Sstevel@tonic-gate 	 */
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate 	comparison_test = 0;
21477c478bd9Sstevel@tonic-gate 	if (type == AP_TYPE) {
21487c478bd9Sstevel@tonic-gate 		if (strncmp(aptype, drv_name, strlen(aptype)) == 0) {
21497c478bd9Sstevel@tonic-gate 			comparison_test = 1;
21507c478bd9Sstevel@tonic-gate 		}
21517c478bd9Sstevel@tonic-gate 	} else {
21527c478bd9Sstevel@tonic-gate 		if (strcmp(aptype, drv_name) == 0 &&
21537c478bd9Sstevel@tonic-gate 		    strcmp(recep_id, node_minor) == 0 &&
21547c478bd9Sstevel@tonic-gate 		    strcmp(inst, inst2) == 0) {
21557c478bd9Sstevel@tonic-gate 			comparison_test = 1;
21567c478bd9Sstevel@tonic-gate 		}
21577c478bd9Sstevel@tonic-gate 	}
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate 	if (comparison_test) {
21607c478bd9Sstevel@tonic-gate 		/*
21617c478bd9Sstevel@tonic-gate 		 * save the correct type of error so user does not get confused
21627c478bd9Sstevel@tonic-gate 		 */
2163*26947304SEvan Yan 		if (minor != DI_MINOR_NIL) {
21647c478bd9Sstevel@tonic-gate 			if (find_lib(node, minor, libloc_p) != CFGA_OK) {
21657c478bd9Sstevel@tonic-gate 				libloc_p->status = CFGA_NO_LIB;
21667c478bd9Sstevel@tonic-gate 				return (DI_WALK_CONTINUE);
21677c478bd9Sstevel@tonic-gate 			}
21687c478bd9Sstevel@tonic-gate 			if (load_lib(node, minor, libloc_p) != CFGA_OK) {
21697c478bd9Sstevel@tonic-gate 				libloc_p->status = CFGA_LIB_ERROR;
21707c478bd9Sstevel@tonic-gate 				return (DI_WALK_CONTINUE);
21717c478bd9Sstevel@tonic-gate 			}
2172*26947304SEvan Yan 		} else {
2173*26947304SEvan Yan 			if (find_lib_hp(node, hp, libloc_p) != CFGA_OK) {
2174*26947304SEvan Yan 				libloc_p->status = CFGA_NO_LIB;
2175*26947304SEvan Yan 				return (DI_WALK_CONTINUE);
2176*26947304SEvan Yan 			}
2177*26947304SEvan Yan 			if (load_lib_hp(node, hp, libloc_p) != CFGA_OK) {
2178*26947304SEvan Yan 				libloc_p->status = CFGA_LIB_ERROR;
2179*26947304SEvan Yan 				return (DI_WALK_CONTINUE);
2180*26947304SEvan Yan 			}
2181*26947304SEvan Yan 		}
21827c478bd9Sstevel@tonic-gate 		libloc_p->status = CFGA_OK;
21837c478bd9Sstevel@tonic-gate 		return (DI_WALK_TERMINATE);
21847c478bd9Sstevel@tonic-gate 	} else {
21857c478bd9Sstevel@tonic-gate 		libloc_p->status = CFGA_APID_NOEXIST;
21867c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
21877c478bd9Sstevel@tonic-gate 	}
21887c478bd9Sstevel@tonic-gate }
21897c478bd9Sstevel@tonic-gate 
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate /*
2192*26947304SEvan Yan  * check_ap_phys - called for each non-SHP attachment point found
2193*26947304SEvan Yan  */
2194*26947304SEvan Yan static int
2195*26947304SEvan Yan check_ap_phys(
2196*26947304SEvan Yan 	di_node_t node,
2197*26947304SEvan Yan 	di_minor_t minor,
2198*26947304SEvan Yan 	void *arg)
2199*26947304SEvan Yan {
2200*26947304SEvan Yan 	return (check_ap_phys_impl(node, minor, DI_HP_NIL, arg));
2201*26947304SEvan Yan }
2202*26947304SEvan Yan 
2203*26947304SEvan Yan /*
2204*26947304SEvan Yan  * check_ap_phys_hp - called for each SHP attachment point found
2205*26947304SEvan Yan  */
2206*26947304SEvan Yan static int
2207*26947304SEvan Yan check_ap_phys_hp(
2208*26947304SEvan Yan 	di_node_t node,
2209*26947304SEvan Yan 	di_hp_t hp,
2210*26947304SEvan Yan 	void *arg)
2211*26947304SEvan Yan {
2212*26947304SEvan Yan 	return (check_ap_phys_impl(node, DI_HP_NIL, hp, arg));
2213*26947304SEvan Yan }
2214*26947304SEvan Yan 
2215*26947304SEvan Yan /*
2216*26947304SEvan Yan  * check_ap_phys_impl - called for each attachment point found
22177c478bd9Sstevel@tonic-gate  *
22187c478bd9Sstevel@tonic-gate  * This is used in cases where a particular attachment point
22197c478bd9Sstevel@tonic-gate  * is specified via a physical name. If the name matches then
22207c478bd9Sstevel@tonic-gate  * we try and find and load the library for it.
22217c478bd9Sstevel@tonic-gate  */
22227c478bd9Sstevel@tonic-gate static int
2223*26947304SEvan Yan check_ap_phys_impl(
22247c478bd9Sstevel@tonic-gate 	di_node_t node,
22257c478bd9Sstevel@tonic-gate 	di_minor_t minor,
2226*26947304SEvan Yan 	di_hp_t hp,
22277c478bd9Sstevel@tonic-gate 	void *arg)
22287c478bd9Sstevel@tonic-gate {
22297c478bd9Sstevel@tonic-gate 	lib_loc_t *libloc_p;
22307c478bd9Sstevel@tonic-gate 	char phys_name[MAXPATHLEN];
22317c478bd9Sstevel@tonic-gate 	char *devfs_path;
22327c478bd9Sstevel@tonic-gate 	char *minor_name;
22337c478bd9Sstevel@tonic-gate 
2234*26947304SEvan Yan 	if (minor != DI_MINOR_NIL && hp != DI_HP_NIL)
2235*26947304SEvan Yan 		return (DI_WALK_CONTINUE);
2236*26947304SEvan Yan 
22377c478bd9Sstevel@tonic-gate 	libloc_p = (lib_loc_t *)arg;
22387c478bd9Sstevel@tonic-gate 	devfs_path = di_devfs_path(node);
2239*26947304SEvan Yan 	if (minor != DI_MINOR_NIL)
22407c478bd9Sstevel@tonic-gate 		minor_name = di_minor_name(minor);
2241*26947304SEvan Yan 	else
2242*26947304SEvan Yan 		minor_name = di_hp_name(hp);
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate 	if (devfs_path == NULL || minor_name == NULL) {
22457c478bd9Sstevel@tonic-gate 		libloc_p->status = CFGA_APID_NOEXIST;
22467c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
22477c478bd9Sstevel@tonic-gate 	}
22487c478bd9Sstevel@tonic-gate 
22497c478bd9Sstevel@tonic-gate 	(void) snprintf(phys_name, sizeof (phys_name), "%s%s:%s",
22507c478bd9Sstevel@tonic-gate 	    DEVICES_DIR, devfs_path, minor_name);
22517c478bd9Sstevel@tonic-gate 
22527c478bd9Sstevel@tonic-gate 	di_devfs_path_free(devfs_path);
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate 	if (strcmp(phys_name, libloc_p->ap_base) == 0) {
2255*26947304SEvan Yan 		if (minor != DI_MINOR_NIL) {
22567c478bd9Sstevel@tonic-gate 			if (find_lib(node, minor, libloc_p) != CFGA_OK) {
22577c478bd9Sstevel@tonic-gate 				libloc_p->status = CFGA_NO_LIB;
22587c478bd9Sstevel@tonic-gate 				return (DI_WALK_CONTINUE);
22597c478bd9Sstevel@tonic-gate 			}
22607c478bd9Sstevel@tonic-gate 			if (load_lib(node, minor, libloc_p) != CFGA_OK) {
22617c478bd9Sstevel@tonic-gate 				libloc_p->status = CFGA_LIB_ERROR;
22627c478bd9Sstevel@tonic-gate 				return (DI_WALK_CONTINUE);
22637c478bd9Sstevel@tonic-gate 			}
2264*26947304SEvan Yan 		} else {
2265*26947304SEvan Yan 			if (find_lib_hp(node, hp, libloc_p) != CFGA_OK) {
2266*26947304SEvan Yan 				libloc_p->status = CFGA_NO_LIB;
2267*26947304SEvan Yan 				return (DI_WALK_CONTINUE);
2268*26947304SEvan Yan 			}
2269*26947304SEvan Yan 			if (load_lib_hp(node, hp, libloc_p) != CFGA_OK) {
2270*26947304SEvan Yan 				libloc_p->status = CFGA_LIB_ERROR;
2271*26947304SEvan Yan 				return (DI_WALK_CONTINUE);
2272*26947304SEvan Yan 			}
2273*26947304SEvan Yan 		}
2274*26947304SEvan Yan 
22757c478bd9Sstevel@tonic-gate 		libloc_p->status = CFGA_OK;
22767c478bd9Sstevel@tonic-gate 		return (DI_WALK_TERMINATE);
22777c478bd9Sstevel@tonic-gate 	} else {
22787c478bd9Sstevel@tonic-gate 		libloc_p->status = CFGA_APID_NOEXIST;
22797c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
22807c478bd9Sstevel@tonic-gate 	}
22817c478bd9Sstevel@tonic-gate }
22827c478bd9Sstevel@tonic-gate 
22837c478bd9Sstevel@tonic-gate /*
22847c478bd9Sstevel@tonic-gate  * lib_in_list
22857c478bd9Sstevel@tonic-gate  *
22867c478bd9Sstevel@tonic-gate  * See if library, as specified by the full pathname and controller
22877c478bd9Sstevel@tonic-gate  * instance number is already represented in the plugin library list.
22887c478bd9Sstevel@tonic-gate  * If the instance number is -1 it is ignored.
22897c478bd9Sstevel@tonic-gate  */
22907c478bd9Sstevel@tonic-gate static plugin_lib_t *
22917c478bd9Sstevel@tonic-gate lib_in_list(char *libpath)
22927c478bd9Sstevel@tonic-gate {
22937c478bd9Sstevel@tonic-gate 	plugin_lib_t *libp = NULL;
22947c478bd9Sstevel@tonic-gate 
22957c478bd9Sstevel@tonic-gate 	for (libp = plugin_list.next; libp != NULL; libp = libp->next) {
22967c478bd9Sstevel@tonic-gate 		if (strncmp(libpath, libp->libpath, MAXPATHLEN) == 0) {
22977c478bd9Sstevel@tonic-gate 			return (libp);
22987c478bd9Sstevel@tonic-gate 		}
22997c478bd9Sstevel@tonic-gate 	}
23007c478bd9Sstevel@tonic-gate 	return (NULL);
23017c478bd9Sstevel@tonic-gate }
23027c478bd9Sstevel@tonic-gate 
23037c478bd9Sstevel@tonic-gate 
23047c478bd9Sstevel@tonic-gate 
23057c478bd9Sstevel@tonic-gate 
23067c478bd9Sstevel@tonic-gate /*
23077c478bd9Sstevel@tonic-gate  * Coalesce stat and list data into single array
23087c478bd9Sstevel@tonic-gate  */
23097c478bd9Sstevel@tonic-gate static cfga_err_t
23107c478bd9Sstevel@tonic-gate realloc_data_ext(
23117c478bd9Sstevel@tonic-gate 	cfga_list_data_t **ap_id_list,
23127c478bd9Sstevel@tonic-gate 	int *nlistp,
23137c478bd9Sstevel@tonic-gate 	list_stat_t *lstatp)
23147c478bd9Sstevel@tonic-gate {
23157c478bd9Sstevel@tonic-gate 	int i, j;
23167c478bd9Sstevel@tonic-gate 	stat_data_list_t *slp;
23177c478bd9Sstevel@tonic-gate 	cfga_list_data_t *cldp;
23187c478bd9Sstevel@tonic-gate 	array_list_t *alp;
23197c478bd9Sstevel@tonic-gate 	cfga_err_t rc = CFGA_OK;
23207c478bd9Sstevel@tonic-gate 
23217c478bd9Sstevel@tonic-gate 
23227c478bd9Sstevel@tonic-gate 	assert(*lstatp->countp >= 0);
23237c478bd9Sstevel@tonic-gate 
23247c478bd9Sstevel@tonic-gate 	if (*lstatp->countp == 0) {
23257c478bd9Sstevel@tonic-gate 		*ap_id_list = NULL;
23267c478bd9Sstevel@tonic-gate 		*nlistp = 0;
23277c478bd9Sstevel@tonic-gate 		return (CFGA_OK);
23287c478bd9Sstevel@tonic-gate 	}
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate 	/*
23317c478bd9Sstevel@tonic-gate 	 * allocate the array
23327c478bd9Sstevel@tonic-gate 	 */
23337c478bd9Sstevel@tonic-gate 	if ((cldp = config_calloc_check(*lstatp->countp,
23347c478bd9Sstevel@tonic-gate 	    sizeof (cfga_list_data_t), lstatp->errstr)) == NULL) {
23357c478bd9Sstevel@tonic-gate 		rc = CFGA_LIB_ERROR;
23367c478bd9Sstevel@tonic-gate 		goto out;
23377c478bd9Sstevel@tonic-gate 	}
23387c478bd9Sstevel@tonic-gate 
23397c478bd9Sstevel@tonic-gate 	/*
23407c478bd9Sstevel@tonic-gate 	 * copy all the stat elements (if any) into the array
23417c478bd9Sstevel@tonic-gate 	 */
23427c478bd9Sstevel@tonic-gate 	slp = lstatp->sdl;
23437c478bd9Sstevel@tonic-gate 	for (i = 0; slp != NULL; i++) {
23447c478bd9Sstevel@tonic-gate 		if (i >= *lstatp->countp) {
23457c478bd9Sstevel@tonic-gate 			rc = CFGA_LIB_ERROR;
23467c478bd9Sstevel@tonic-gate 			goto out;
23477c478bd9Sstevel@tonic-gate 		}
23487c478bd9Sstevel@tonic-gate 		stat_to_list(&cldp[i], &slp->stat_data);
23497c478bd9Sstevel@tonic-gate 		slp = slp->next;
23507c478bd9Sstevel@tonic-gate 	}
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate 	/*
23537c478bd9Sstevel@tonic-gate 	 * copy all the list elements (if any) into the array
23547c478bd9Sstevel@tonic-gate 	 */
23557c478bd9Sstevel@tonic-gate 	alp = lstatp->al;
23567c478bd9Sstevel@tonic-gate 	for (; alp != NULL; ) {
23577c478bd9Sstevel@tonic-gate 		if (i + alp->nelem > *lstatp->countp) {
23587c478bd9Sstevel@tonic-gate 			rc = CFGA_LIB_ERROR;
23597c478bd9Sstevel@tonic-gate 			goto out;
23607c478bd9Sstevel@tonic-gate 		}
23617c478bd9Sstevel@tonic-gate 
23627c478bd9Sstevel@tonic-gate 		for (j = 0; j < alp->nelem; i++, j++) {
23637c478bd9Sstevel@tonic-gate 			cldp[i] = alp->array[j];
23647c478bd9Sstevel@tonic-gate 		}
23657c478bd9Sstevel@tonic-gate 		alp = alp->next;
23667c478bd9Sstevel@tonic-gate 	}
23677c478bd9Sstevel@tonic-gate 
23687c478bd9Sstevel@tonic-gate 	if (i != *lstatp->countp) {
23697c478bd9Sstevel@tonic-gate 		rc = CFGA_LIB_ERROR;
23707c478bd9Sstevel@tonic-gate 	} else {
23717c478bd9Sstevel@tonic-gate 		rc = CFGA_OK;
23727c478bd9Sstevel@tonic-gate 	}
23737c478bd9Sstevel@tonic-gate 
23747c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
23757c478bd9Sstevel@tonic-gate 
23767c478bd9Sstevel@tonic-gate out:
23777c478bd9Sstevel@tonic-gate 	/* clean up */
23787c478bd9Sstevel@tonic-gate 	lstat_free(lstatp);
23797c478bd9Sstevel@tonic-gate 
23807c478bd9Sstevel@tonic-gate 	if (rc == CFGA_OK) {
23817c478bd9Sstevel@tonic-gate 		*ap_id_list = cldp;
23827c478bd9Sstevel@tonic-gate 		*nlistp = *lstatp->countp;
23837c478bd9Sstevel@tonic-gate 	} else {
23847c478bd9Sstevel@tonic-gate 		S_FREE(cldp);
23857c478bd9Sstevel@tonic-gate 		*ap_id_list = NULL;
23867c478bd9Sstevel@tonic-gate 		*nlistp = 0;
23877c478bd9Sstevel@tonic-gate 	}
23887c478bd9Sstevel@tonic-gate 	return (rc);
23897c478bd9Sstevel@tonic-gate }
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate /*
23927c478bd9Sstevel@tonic-gate  * The caller of this routine may supply a buffer through
23937c478bd9Sstevel@tonic-gate  * ap_id_list for returning data. Otherwise, this routine allocates the
23947c478bd9Sstevel@tonic-gate  * buffer.
23957c478bd9Sstevel@tonic-gate  */
23967c478bd9Sstevel@tonic-gate static cfga_err_t
23977c478bd9Sstevel@tonic-gate realloc_data(cfga_stat_data_t **ap_id_list, int *nlistp, list_stat_t *lstatp)
23987c478bd9Sstevel@tonic-gate {
23997c478bd9Sstevel@tonic-gate 	int i;
24007c478bd9Sstevel@tonic-gate 	stat_data_list_t *slp;
24017c478bd9Sstevel@tonic-gate 	cfga_stat_data_t *csdp, *buf;
24027c478bd9Sstevel@tonic-gate 	cfga_err_t rc;
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate 
24057c478bd9Sstevel@tonic-gate 	assert(*lstatp->countp >= 0);
24067c478bd9Sstevel@tonic-gate 
24077c478bd9Sstevel@tonic-gate 	if (*lstatp->countp == 0) {
24087c478bd9Sstevel@tonic-gate 		*nlistp = 0;
24097c478bd9Sstevel@tonic-gate 		return (CFGA_OK);
24107c478bd9Sstevel@tonic-gate 	}
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate 
24137c478bd9Sstevel@tonic-gate 	/*
24147c478bd9Sstevel@tonic-gate 	 * allocate the array if caller does not supply one.
24157c478bd9Sstevel@tonic-gate 	 */
24167c478bd9Sstevel@tonic-gate 	if (*ap_id_list == NULL) {
24177c478bd9Sstevel@tonic-gate 		if ((buf = config_calloc_check(*lstatp->countp,
24187c478bd9Sstevel@tonic-gate 		    sizeof (cfga_stat_data_t), lstatp->errstr)) == NULL) {
24197c478bd9Sstevel@tonic-gate 			rc = CFGA_LIB_ERROR;
24207c478bd9Sstevel@tonic-gate 			goto out;
24217c478bd9Sstevel@tonic-gate 		}
24227c478bd9Sstevel@tonic-gate 	} else {
24237c478bd9Sstevel@tonic-gate 		buf = *ap_id_list;
24247c478bd9Sstevel@tonic-gate 	}
24257c478bd9Sstevel@tonic-gate 
24267c478bd9Sstevel@tonic-gate 	/*
24277c478bd9Sstevel@tonic-gate 	 * copy the stat elements into the array
24287c478bd9Sstevel@tonic-gate 	 */
24297c478bd9Sstevel@tonic-gate 	csdp = buf;
24307c478bd9Sstevel@tonic-gate 	slp = lstatp->sdl;
24317c478bd9Sstevel@tonic-gate 	for (i = 0; slp != NULL; i++) {
24327c478bd9Sstevel@tonic-gate 		if (i >= *lstatp->countp) {
24337c478bd9Sstevel@tonic-gate 			rc = CFGA_LIB_ERROR;
24347c478bd9Sstevel@tonic-gate 			goto out;
24357c478bd9Sstevel@tonic-gate 		}
24367c478bd9Sstevel@tonic-gate 		*csdp++ = slp->stat_data;
24377c478bd9Sstevel@tonic-gate 		slp = slp->next;
24387c478bd9Sstevel@tonic-gate 	}
24397c478bd9Sstevel@tonic-gate 
24407c478bd9Sstevel@tonic-gate 	rc = CFGA_OK;
24417c478bd9Sstevel@tonic-gate 
24427c478bd9Sstevel@tonic-gate out:
24437c478bd9Sstevel@tonic-gate 	if (rc == CFGA_OK) {
24447c478bd9Sstevel@tonic-gate 		*nlistp = *lstatp->countp;
24457c478bd9Sstevel@tonic-gate 		*ap_id_list = buf;
24467c478bd9Sstevel@tonic-gate 	} else {
24477c478bd9Sstevel@tonic-gate 		/*
24487c478bd9Sstevel@tonic-gate 		 * Free buffer only if we allocated it.
24497c478bd9Sstevel@tonic-gate 		 */
24507c478bd9Sstevel@tonic-gate 		if (*ap_id_list == NULL) {
24517c478bd9Sstevel@tonic-gate 			free(buf);
24527c478bd9Sstevel@tonic-gate 		}
24537c478bd9Sstevel@tonic-gate 		*nlistp = 0;
24547c478bd9Sstevel@tonic-gate 	}
24557c478bd9Sstevel@tonic-gate 
24567c478bd9Sstevel@tonic-gate 	assert(lstatp->al == NULL);
24577c478bd9Sstevel@tonic-gate 	lstat_free(lstatp);
24587c478bd9Sstevel@tonic-gate 
24597c478bd9Sstevel@tonic-gate 	return (rc);
24607c478bd9Sstevel@tonic-gate }
24617c478bd9Sstevel@tonic-gate 
24627c478bd9Sstevel@tonic-gate 
24637c478bd9Sstevel@tonic-gate /*
24647c478bd9Sstevel@tonic-gate  * list_common - walk the device tree and stat all attachment points.
24657c478bd9Sstevel@tonic-gate  */
24667c478bd9Sstevel@tonic-gate static cfga_err_t
24677c478bd9Sstevel@tonic-gate list_common(list_stat_t *lstatp, const char *class)
24687c478bd9Sstevel@tonic-gate {
24697c478bd9Sstevel@tonic-gate 	di_node_t rnode;
24707c478bd9Sstevel@tonic-gate 	char nodetype[MAXPATHLEN];
24717c478bd9Sstevel@tonic-gate 	const char *l_class, *l_sep;
24727c478bd9Sstevel@tonic-gate 
24737c478bd9Sstevel@tonic-gate 	/*
24747c478bd9Sstevel@tonic-gate 	 * May walk a subset of all attachment points in the device tree if
24757c478bd9Sstevel@tonic-gate 	 * a class is specified
24767c478bd9Sstevel@tonic-gate 	 */
24777c478bd9Sstevel@tonic-gate 	if (class != NULL) {
24787c478bd9Sstevel@tonic-gate 		l_sep = ":";
24797c478bd9Sstevel@tonic-gate 		l_class = class;
24807c478bd9Sstevel@tonic-gate 	} else {
24817c478bd9Sstevel@tonic-gate 		l_sep = l_class = "";
24827c478bd9Sstevel@tonic-gate 	}
24837c478bd9Sstevel@tonic-gate 
24847c478bd9Sstevel@tonic-gate 	(void) snprintf(nodetype, sizeof (nodetype), "%s%s%s",
24857c478bd9Sstevel@tonic-gate 	    DDI_NT_ATTACHMENT_POINT, l_sep, l_class);
24867c478bd9Sstevel@tonic-gate 
2487*26947304SEvan Yan 	/*
2488*26947304SEvan Yan 	 * Walk all hp nodes
2489*26947304SEvan Yan 	 */
2490*26947304SEvan Yan 	if ((rnode = di_init("/", DINFOSUBTREE | DINFOHP)) == DI_NODE_NIL) {
2491*26947304SEvan Yan 		config_err(errno, DI_INIT_FAILED, lstatp->errstr);
2492*26947304SEvan Yan 		return (CFGA_LIB_ERROR);
2493*26947304SEvan Yan 	}
2494*26947304SEvan Yan 	/* No need to filter on class for now */
2495*26947304SEvan Yan 	(void) di_walk_hp(rnode, NULL, DI_HP_CONNECTOR,
2496*26947304SEvan Yan 	    lstatp, do_list_common_hp);
2497*26947304SEvan Yan 
2498*26947304SEvan Yan 	di_fini(rnode);
2499*26947304SEvan Yan 
2500*26947304SEvan Yan 	/*
2501*26947304SEvan Yan 	 * Walk all minor nodes
2502*26947304SEvan Yan 	 * but exclude PCIE/PCIESHPC connectors which have been walked above.
2503*26947304SEvan Yan 	 */
2504*26947304SEvan Yan 	if ((rnode = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
2505*26947304SEvan Yan 		config_err(errno, DI_INIT_FAILED, lstatp->errstr);
2506*26947304SEvan Yan 		return (CFGA_LIB_ERROR);
2507*26947304SEvan Yan 	}
25087c478bd9Sstevel@tonic-gate 	(void) di_walk_minor(rnode, nodetype,
25097c478bd9Sstevel@tonic-gate 	    DI_CHECK_ALIAS|DI_CHECK_INTERNAL_PATH, lstatp, do_list_common);
2510*26947304SEvan Yan 
25117c478bd9Sstevel@tonic-gate 	di_fini(rnode);
25127c478bd9Sstevel@tonic-gate 
2513*26947304SEvan Yan 	if (lstatp->shp_errstr != NULL) {
2514*26947304SEvan Yan 		*(lstatp->errstr) = strdup(lstatp->shp_errstr);
2515*26947304SEvan Yan 		free(lstatp->shp_errstr);
2516*26947304SEvan Yan 		lstatp->shp_errstr = NULL;
2517*26947304SEvan Yan 	}
2518*26947304SEvan Yan 
25197c478bd9Sstevel@tonic-gate 	return (CFGA_OK);
25207c478bd9Sstevel@tonic-gate }
25217c478bd9Sstevel@tonic-gate 
25227c478bd9Sstevel@tonic-gate static void
25237c478bd9Sstevel@tonic-gate config_err(int errnum, int err_type, char **errstring)
25247c478bd9Sstevel@tonic-gate {
25257c478bd9Sstevel@tonic-gate 	char *p = NULL, *q = NULL;
25267c478bd9Sstevel@tonic-gate 	char *syserr = NULL;
25277c478bd9Sstevel@tonic-gate 	char syserr_num[20];
25287c478bd9Sstevel@tonic-gate 	int len = 0;
25297c478bd9Sstevel@tonic-gate 
25307c478bd9Sstevel@tonic-gate 	/*
25317c478bd9Sstevel@tonic-gate 	 * If errstring is null it means user in not interested in getting
25327c478bd9Sstevel@tonic-gate 	 * error status. So we don't do all the work
25337c478bd9Sstevel@tonic-gate 	 */
25347c478bd9Sstevel@tonic-gate 	if (errstring == NULL) {
25357c478bd9Sstevel@tonic-gate 		return;
25367c478bd9Sstevel@tonic-gate 	}
25377c478bd9Sstevel@tonic-gate 
25387c478bd9Sstevel@tonic-gate 	if (errnum != 0) {
25397c478bd9Sstevel@tonic-gate 		syserr = strerror(errnum);
25407c478bd9Sstevel@tonic-gate 		if (syserr == NULL) {
25417c478bd9Sstevel@tonic-gate 			(void) sprintf(syserr_num, "errno=%d", errnum);
25427c478bd9Sstevel@tonic-gate 			syserr = syserr_num;
25437c478bd9Sstevel@tonic-gate 		}
25447c478bd9Sstevel@tonic-gate 	} else
25457c478bd9Sstevel@tonic-gate 		syserr = NULL;
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate 	q = dgettext(TEXT_DOMAIN, err_strings[err_type]);
25487c478bd9Sstevel@tonic-gate 
25497c478bd9Sstevel@tonic-gate 	len = strlen(q);
25507c478bd9Sstevel@tonic-gate 	if (syserr != NULL) {
25517c478bd9Sstevel@tonic-gate 		len += strlen(err_sep) + strlen(syserr);
25527c478bd9Sstevel@tonic-gate 	}
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate 	p = malloc(len + 1);
25557c478bd9Sstevel@tonic-gate 	if (p == NULL) {
25567c478bd9Sstevel@tonic-gate 		*errstring = NULL;
25577c478bd9Sstevel@tonic-gate 		return;
25587c478bd9Sstevel@tonic-gate 	}
25597c478bd9Sstevel@tonic-gate 
25607c478bd9Sstevel@tonic-gate 	(void) strcpy(p, q);
25617c478bd9Sstevel@tonic-gate 	if (syserr != NULL) {
25627c478bd9Sstevel@tonic-gate 		(void) strcat(p, err_sep);
25637c478bd9Sstevel@tonic-gate 		(void) strcat(p, syserr);
25647c478bd9Sstevel@tonic-gate 	}
25657c478bd9Sstevel@tonic-gate 
25667c478bd9Sstevel@tonic-gate 	*errstring  = p;
25677c478bd9Sstevel@tonic-gate }
25687c478bd9Sstevel@tonic-gate 
25697c478bd9Sstevel@tonic-gate /*
2570*26947304SEvan Yan  * do_list_common - list non-SHP attachment point
25717c478bd9Sstevel@tonic-gate  */
25727c478bd9Sstevel@tonic-gate static int
25737c478bd9Sstevel@tonic-gate do_list_common(
25747c478bd9Sstevel@tonic-gate 	di_node_t node,
25757c478bd9Sstevel@tonic-gate 	di_minor_t minor,
25767c478bd9Sstevel@tonic-gate 	void *arg)
25777c478bd9Sstevel@tonic-gate {
2578*26947304SEvan Yan 	di_node_t rnode;
2579*26947304SEvan Yan 	di_hp_t hp;
2580*26947304SEvan Yan 	char *minor_name;
2581*26947304SEvan Yan 
2582*26947304SEvan Yan 	minor_name = di_minor_name(minor);
2583*26947304SEvan Yan 
2584*26947304SEvan Yan 	/*
2585*26947304SEvan Yan 	 * since PCIE/PCIHSHPC connectors have both hp nodes and minor nodes
2586*26947304SEvan Yan 	 * created for now, we need to specifically exclude these connectors
2587*26947304SEvan Yan 	 * during walking minor nodes.
2588*26947304SEvan Yan 	 */
2589*26947304SEvan Yan 	if ((rnode = di_init(di_devfs_path(node), DINFOSUBTREE | DINFOHP))
2590*26947304SEvan Yan 	    == DI_NODE_NIL) {
2591*26947304SEvan Yan 		return (DI_WALK_CONTINUE);
2592*26947304SEvan Yan 	}
2593*26947304SEvan Yan 
2594*26947304SEvan Yan 	for (hp = DI_HP_NIL; (hp = di_hp_next(rnode, hp)) != DI_HP_NIL; ) {
2595*26947304SEvan Yan 		if (strcmp(di_hp_name(hp), minor_name) == 0) {
2596*26947304SEvan Yan 			di_fini(rnode);
2597*26947304SEvan Yan 			return (DI_WALK_CONTINUE);
2598*26947304SEvan Yan 		}
2599*26947304SEvan Yan 	}
2600*26947304SEvan Yan 
2601*26947304SEvan Yan 	di_fini(rnode);
2602*26947304SEvan Yan 
2603*26947304SEvan Yan 	return (do_list_common_impl(node, minor, NULL, arg));
2604*26947304SEvan Yan }
2605*26947304SEvan Yan 
2606*26947304SEvan Yan /*
2607*26947304SEvan Yan  * do_list_common_hp - list SHP attachment point
2608*26947304SEvan Yan  */
2609*26947304SEvan Yan static int
2610*26947304SEvan Yan do_list_common_hp(
2611*26947304SEvan Yan 	di_node_t node,
2612*26947304SEvan Yan 	di_hp_t hp,
2613*26947304SEvan Yan 	void *arg)
2614*26947304SEvan Yan {
2615*26947304SEvan Yan 	return (do_list_common_impl(node, NULL, hp, arg));
2616*26947304SEvan Yan }
2617*26947304SEvan Yan 
2618*26947304SEvan Yan /*
2619*26947304SEvan Yan  * do_list_common_impl - Routine to list attachment point as part of
2620*26947304SEvan Yan  * a config_list opertion. Used by both v1 and v2 interfaces.
2621*26947304SEvan Yan  * This is somewhat similar to config_get_lib() and its helper routines
2622*26947304SEvan Yan  * except that the ap_ids are always physical and don't have dynamic
2623*26947304SEvan Yan  * components.
2624*26947304SEvan Yan  */
2625*26947304SEvan Yan static int
2626*26947304SEvan Yan do_list_common_impl(
2627*26947304SEvan Yan 	di_node_t node,
2628*26947304SEvan Yan 	di_minor_t minor,
2629*26947304SEvan Yan 	di_hp_t hp,
2630*26947304SEvan Yan 	void *arg)
2631*26947304SEvan Yan {
26327c478bd9Sstevel@tonic-gate 	lib_loc_t lib_loc;
26337c478bd9Sstevel@tonic-gate 	plugin_lib_t *libp;
26347c478bd9Sstevel@tonic-gate 	list_stat_t *lstatp = NULL;
26357c478bd9Sstevel@tonic-gate 	cfga_err_t ret = CFGA_ERROR;
26367c478bd9Sstevel@tonic-gate 
2637*26947304SEvan Yan 	if (minor != DI_MINOR_NIL && hp != DI_HP_NIL)
2638*26947304SEvan Yan 		return (DI_WALK_CONTINUE);
26397c478bd9Sstevel@tonic-gate 
26407c478bd9Sstevel@tonic-gate 	lstatp = (list_stat_t *)arg;
26417c478bd9Sstevel@tonic-gate 
26427c478bd9Sstevel@tonic-gate 	lib_loc.libp = NULL;
26437c478bd9Sstevel@tonic-gate 	/*
26447c478bd9Sstevel@tonic-gate 	 * try and find a lib for this node
26457c478bd9Sstevel@tonic-gate 	 */
2646*26947304SEvan Yan 	if (minor != DI_MINOR_NIL) {
2647*26947304SEvan Yan 		ret = find_lib(node, minor, &lib_loc);
2648*26947304SEvan Yan 	} else {
2649*26947304SEvan Yan 		ret = find_lib_hp(node, hp, &lib_loc);
2650*26947304SEvan Yan 	}
2651*26947304SEvan Yan 	if (ret != CFGA_OK) {
26527c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
26537c478bd9Sstevel@tonic-gate 	}
26547c478bd9Sstevel@tonic-gate 
26557c478bd9Sstevel@tonic-gate 	/*
26567c478bd9Sstevel@tonic-gate 	 * Load all plugins. We will check compatibility later in this
26577c478bd9Sstevel@tonic-gate 	 * routine.
26587c478bd9Sstevel@tonic-gate 	 */
26597c478bd9Sstevel@tonic-gate 	lib_loc.vers_req.v_min = CFGA_HSL_V1;
26607c478bd9Sstevel@tonic-gate 	lib_loc.vers_req.v_max = CFGA_HSL_VERS;
26617c478bd9Sstevel@tonic-gate 
2662*26947304SEvan Yan 	if (minor != DI_MINOR_NIL) {
26637c478bd9Sstevel@tonic-gate 		ret = load_lib(node, minor, &lib_loc);
2664*26947304SEvan Yan 	} else {
2665*26947304SEvan Yan 		ret = load_lib_hp(node, hp, &lib_loc);
2666*26947304SEvan Yan 	}
26677c478bd9Sstevel@tonic-gate 	if (ret != CFGA_OK) {
26687c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
26697c478bd9Sstevel@tonic-gate 	}
26707c478bd9Sstevel@tonic-gate 
26717c478bd9Sstevel@tonic-gate 	libp = lib_loc.libp;
26727c478bd9Sstevel@tonic-gate 	assert(libp != NULL);
26737c478bd9Sstevel@tonic-gate 
26747c478bd9Sstevel@tonic-gate 	/*
26757c478bd9Sstevel@tonic-gate 	 * Note: For list type routines (list all attachment points in
26767c478bd9Sstevel@tonic-gate 	 * device tree) we don't pass errstring to the plugin, nor do we
26777c478bd9Sstevel@tonic-gate 	 * stop the walk if an error occurs in the plugin.
26787c478bd9Sstevel@tonic-gate 	 */
26797c478bd9Sstevel@tonic-gate 	if (compat_plugin(&lstatp->use_vers, libp->plugin_vers)) {
2680*26947304SEvan Yan 		if (minor != DI_MINOR_NIL) {
2681*26947304SEvan Yan 			(void) libp->vers_ops->stat_plugin(lstatp,
2682*26947304SEvan Yan 			    &lib_loc, NULL);
2683*26947304SEvan Yan 		} else {
2684*26947304SEvan Yan 			/*
2685*26947304SEvan Yan 			 * If the underlying hotplug daemon is not enabled,
2686*26947304SEvan Yan 			 * the SHP attach points will not be shown, this
2687*26947304SEvan Yan 			 * could confuse the uesrs. We specifically pass the
2688*26947304SEvan Yan 			 * errstring to SHP plugin so that it can set the
2689*26947304SEvan Yan 			 * errstring accordingly in this case, giving users
2690*26947304SEvan Yan 			 * a hint.
2691*26947304SEvan Yan 			 */
2692*26947304SEvan Yan 			ret = libp->vers_ops->stat_plugin(lstatp,
2693*26947304SEvan Yan 			    &lib_loc, lstatp->errstr);
2694*26947304SEvan Yan 			if (ret == CFGA_NOTSUPP && *(lstatp->errstr) != NULL) {
2695*26947304SEvan Yan 				if (lstatp->shp_errstr == NULL) {
2696*26947304SEvan Yan 					lstatp->shp_errstr =
2697*26947304SEvan Yan 					    strdup(*(lstatp->errstr));
2698*26947304SEvan Yan 				}
2699*26947304SEvan Yan 			}
2700*26947304SEvan Yan 
2701*26947304SEvan Yan 			if (*(lstatp->errstr) != NULL) {
2702*26947304SEvan Yan 				free(*(lstatp->errstr));
2703*26947304SEvan Yan 				*(lstatp->errstr) = NULL;
2704*26947304SEvan Yan 			}
2705*26947304SEvan Yan 		}
27067c478bd9Sstevel@tonic-gate 	}
27077c478bd9Sstevel@tonic-gate 	rele_lib(libp);
27087c478bd9Sstevel@tonic-gate 
27097c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
27107c478bd9Sstevel@tonic-gate }
27117c478bd9Sstevel@tonic-gate 
27127c478bd9Sstevel@tonic-gate /*
27137c478bd9Sstevel@tonic-gate  * stat_common - stat a user specified set of attachment points.
27147c478bd9Sstevel@tonic-gate  */
27157c478bd9Sstevel@tonic-gate static cfga_err_t
27167c478bd9Sstevel@tonic-gate stat_common(
27177c478bd9Sstevel@tonic-gate 	int num_ap_ids,
27187c478bd9Sstevel@tonic-gate 	char *const *ap_ids,
27197c478bd9Sstevel@tonic-gate 	const char *class,
27207c478bd9Sstevel@tonic-gate 	list_stat_t *lstatp)
27217c478bd9Sstevel@tonic-gate {
27227c478bd9Sstevel@tonic-gate 	int i;
27237c478bd9Sstevel@tonic-gate 	lib_loc_t libloc;
27247c478bd9Sstevel@tonic-gate 	plugin_lib_t *libp;
27257c478bd9Sstevel@tonic-gate 	cfga_err_t rc = CFGA_OK;
27267c478bd9Sstevel@tonic-gate 
27277c478bd9Sstevel@tonic-gate 
27287c478bd9Sstevel@tonic-gate 	/*
27297c478bd9Sstevel@tonic-gate 	 * operate on each ap_id
27307c478bd9Sstevel@tonic-gate 	 */
27317c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_ap_ids; i++) {
27327c478bd9Sstevel@tonic-gate 		libloc.libp = NULL;
27337c478bd9Sstevel@tonic-gate 		if ((rc = config_get_lib(ap_ids[i], &libloc,
27347c478bd9Sstevel@tonic-gate 		    lstatp->errstr)) != CFGA_OK) {
27357c478bd9Sstevel@tonic-gate 			break;
27367c478bd9Sstevel@tonic-gate 		}
27377c478bd9Sstevel@tonic-gate 		assert(libloc.libp != NULL);
27387c478bd9Sstevel@tonic-gate 		libp = libloc.libp;
27397c478bd9Sstevel@tonic-gate 
27407c478bd9Sstevel@tonic-gate 		/*
27417c478bd9Sstevel@tonic-gate 		 * do pre-filtering if requested
27427c478bd9Sstevel@tonic-gate 		 */
27437c478bd9Sstevel@tonic-gate 		if (class != NULL && strcmp(libloc.ap_class, class)) {
27447c478bd9Sstevel@tonic-gate 			rele_lib(libp);
27457c478bd9Sstevel@tonic-gate 			continue;
27467c478bd9Sstevel@tonic-gate 		}
27477c478bd9Sstevel@tonic-gate 
27487c478bd9Sstevel@tonic-gate 		/*
27497c478bd9Sstevel@tonic-gate 		 * Unlike list type routines, while stat'ing specific
27507c478bd9Sstevel@tonic-gate 		 * attachment points we pass errstring to the plugins
27517c478bd9Sstevel@tonic-gate 		 * and halt if an error occurs in the plugin.
27527c478bd9Sstevel@tonic-gate 		 */
27537c478bd9Sstevel@tonic-gate 		rc = libp->vers_ops->stat_plugin(lstatp, &libloc,
27547c478bd9Sstevel@tonic-gate 		    lstatp->errstr);
27557c478bd9Sstevel@tonic-gate 		rele_lib(libp);
27567c478bd9Sstevel@tonic-gate 		if (rc != CFGA_OK) {
27577c478bd9Sstevel@tonic-gate 			break;
27587c478bd9Sstevel@tonic-gate 		}
27597c478bd9Sstevel@tonic-gate 	}
27607c478bd9Sstevel@tonic-gate 
27617c478bd9Sstevel@tonic-gate 	if (rc != CFGA_OK) {
27627c478bd9Sstevel@tonic-gate 		lstat_free(lstatp);
27637c478bd9Sstevel@tonic-gate 	}
27647c478bd9Sstevel@tonic-gate 	return (rc);
27657c478bd9Sstevel@tonic-gate }
27667c478bd9Sstevel@tonic-gate 
27677c478bd9Sstevel@tonic-gate /*ARGSUSED*/
27687c478bd9Sstevel@tonic-gate static cfga_err_t
27697c478bd9Sstevel@tonic-gate null_stat_plugin(list_stat_t *lstatp, lib_loc_t *libloc_p, char **errstring)
27707c478bd9Sstevel@tonic-gate {
27717c478bd9Sstevel@tonic-gate 	return (CFGA_OK);
27727c478bd9Sstevel@tonic-gate }
27737c478bd9Sstevel@tonic-gate 
27747c478bd9Sstevel@tonic-gate /*
27757c478bd9Sstevel@tonic-gate  * Pass errstring as a separate argument. Some higher level routines need
27767c478bd9Sstevel@tonic-gate  * it to be NULL.
27777c478bd9Sstevel@tonic-gate  */
27787c478bd9Sstevel@tonic-gate static cfga_err_t
27797c478bd9Sstevel@tonic-gate stat_plugin_v1(list_stat_t *lstatp, lib_loc_t *libloc_p, char **errstring)
27807c478bd9Sstevel@tonic-gate {
27817c478bd9Sstevel@tonic-gate 	stat_data_list_t *slp, *slp2 = NULL;
27827c478bd9Sstevel@tonic-gate 	cfga_err_t rc;
27837c478bd9Sstevel@tonic-gate 
27847c478bd9Sstevel@tonic-gate 	/*
27857c478bd9Sstevel@tonic-gate 	 * allocate stat data buffer and list element
27867c478bd9Sstevel@tonic-gate 	 */
27877c478bd9Sstevel@tonic-gate 	if ((slp = config_calloc_check(1, sizeof (stat_data_list_t),
27887c478bd9Sstevel@tonic-gate 	    errstring)) == NULL) {
27897c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
27907c478bd9Sstevel@tonic-gate 	}
27917c478bd9Sstevel@tonic-gate 
27927c478bd9Sstevel@tonic-gate 	/*
27937c478bd9Sstevel@tonic-gate 	 * Do the stat
27947c478bd9Sstevel@tonic-gate 	 */
27957c478bd9Sstevel@tonic-gate 	errno = 0;
27967c478bd9Sstevel@tonic-gate 	if ((rc = (*(libloc_p->libp->cfga_stat_p))(libloc_p->ap_physical,
27977c478bd9Sstevel@tonic-gate 	    &slp->stat_data, lstatp->opts, errstring)) != CFGA_OK) {
27987c478bd9Sstevel@tonic-gate 		S_FREE(slp);
27997c478bd9Sstevel@tonic-gate 		return (rc);
28007c478bd9Sstevel@tonic-gate 	}
28017c478bd9Sstevel@tonic-gate 	slp->next = NULL;
28027c478bd9Sstevel@tonic-gate 
28037c478bd9Sstevel@tonic-gate 	/*
28047c478bd9Sstevel@tonic-gate 	 * Set up the logical and physical id's.
28057c478bd9Sstevel@tonic-gate 	 * For v1 interfaces, the generic library (libcfgadm) creates the
28067c478bd9Sstevel@tonic-gate 	 * ap_ids. mklog() is assumed to have been called in
28077c478bd9Sstevel@tonic-gate 	 * the caller of this routine.
28087c478bd9Sstevel@tonic-gate 	 */
28097c478bd9Sstevel@tonic-gate 	(void) snprintf(slp->stat_data.ap_log_id, CFGA_AP_LOG_ID_LEN, "%s",
28107c478bd9Sstevel@tonic-gate 	    libloc_p->ap_logical);
28117c478bd9Sstevel@tonic-gate 
28127c478bd9Sstevel@tonic-gate 	(void) snprintf(slp->stat_data.ap_phys_id, CFGA_AP_PHYS_ID_LEN, "%s",
28137c478bd9Sstevel@tonic-gate 	    libloc_p->ap_physical);
28147c478bd9Sstevel@tonic-gate 
28157c478bd9Sstevel@tonic-gate 	/*
28167c478bd9Sstevel@tonic-gate 	 * link it in
28177c478bd9Sstevel@tonic-gate 	 */
28187c478bd9Sstevel@tonic-gate 	if ((slp2 = lstatp->sdl) == NULL) {
28197c478bd9Sstevel@tonic-gate 		lstatp->sdl = slp;
28207c478bd9Sstevel@tonic-gate 	} else {
28217c478bd9Sstevel@tonic-gate 		while (slp2->next != NULL)
28227c478bd9Sstevel@tonic-gate 			slp2 = slp2->next;
28237c478bd9Sstevel@tonic-gate 		slp2->next = slp;
28247c478bd9Sstevel@tonic-gate 	}
28257c478bd9Sstevel@tonic-gate 
28267c478bd9Sstevel@tonic-gate 	/* keep count */
28277c478bd9Sstevel@tonic-gate 	(*lstatp->countp)++;
28287c478bd9Sstevel@tonic-gate 
28297c478bd9Sstevel@tonic-gate 	return (CFGA_OK);
28307c478bd9Sstevel@tonic-gate }
28317c478bd9Sstevel@tonic-gate 
28327c478bd9Sstevel@tonic-gate static cfga_err_t
28337c478bd9Sstevel@tonic-gate stat_plugin_v2(list_stat_t *lstatp, lib_loc_t *libloc_p, char **errstring)
28347c478bd9Sstevel@tonic-gate {
28357c478bd9Sstevel@tonic-gate 	int i;
28367c478bd9Sstevel@tonic-gate 	array_list_t *alp, *alp2 = NULL;
28377c478bd9Sstevel@tonic-gate 	cfga_err_t rc;
28387c478bd9Sstevel@tonic-gate 	char *class;
28397c478bd9Sstevel@tonic-gate 
28407c478bd9Sstevel@tonic-gate 	/*
28417c478bd9Sstevel@tonic-gate 	 * allocate array list
28427c478bd9Sstevel@tonic-gate 	 */
28437c478bd9Sstevel@tonic-gate 	if ((alp = config_calloc_check(1, sizeof (array_list_t),
28447c478bd9Sstevel@tonic-gate 	    errstring)) == NULL) {
28457c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
28467c478bd9Sstevel@tonic-gate 	}
28477c478bd9Sstevel@tonic-gate 
28487c478bd9Sstevel@tonic-gate 	alp->array = NULL;
28497c478bd9Sstevel@tonic-gate 	alp->nelem = 0;
28507c478bd9Sstevel@tonic-gate 
28517c478bd9Sstevel@tonic-gate 	/*
28527c478bd9Sstevel@tonic-gate 	 * The listopts argument is currently unused. Use NULL
28537c478bd9Sstevel@tonic-gate 	 */
28547c478bd9Sstevel@tonic-gate 	errno = 0;
28557c478bd9Sstevel@tonic-gate 	if ((rc = (*(libloc_p->libp->cfga_list_ext_p))(
28567c478bd9Sstevel@tonic-gate 	    libloc_p->ap_physical, &alp->array, &alp->nelem, lstatp->opts, NULL,
28577c478bd9Sstevel@tonic-gate 	    errstring, lstatp->flags)) != CFGA_OK || alp->nelem <= 0) {
28587c478bd9Sstevel@tonic-gate 		S_FREE(alp);
28597c478bd9Sstevel@tonic-gate 		return (rc);
28607c478bd9Sstevel@tonic-gate 	}
28617c478bd9Sstevel@tonic-gate 	alp->next = NULL;
28627c478bd9Sstevel@tonic-gate 
28637c478bd9Sstevel@tonic-gate 	/*
28647c478bd9Sstevel@tonic-gate 	 * Set up the logical and physical id's if necessary.
28657c478bd9Sstevel@tonic-gate 	 * For v2 interfaces, the generic library (libcfgadm) creates the
28667c478bd9Sstevel@tonic-gate 	 * ap_ids only if there are no dynamic attachment points and the
28677c478bd9Sstevel@tonic-gate 	 * plug-in does not create the name itself.  mklog() is
28687c478bd9Sstevel@tonic-gate 	 * assumed to have been called in the caller of this routine.
28697c478bd9Sstevel@tonic-gate 	 */
28707c478bd9Sstevel@tonic-gate 	if (alp->nelem == 1) {
28717c478bd9Sstevel@tonic-gate 		char cphys, clog;
28727c478bd9Sstevel@tonic-gate 
28737c478bd9Sstevel@tonic-gate 		clog = (alp->array[0]).ap_log_id[0];
28747c478bd9Sstevel@tonic-gate 		cphys = (alp->array[0]).ap_phys_id[0];
28757c478bd9Sstevel@tonic-gate 
28767c478bd9Sstevel@tonic-gate 		if (clog == '\0') {
28777c478bd9Sstevel@tonic-gate 			(void) snprintf((alp->array[0]).ap_log_id,
28787c478bd9Sstevel@tonic-gate 			    sizeof ((alp->array[0]).ap_log_id), "%s",
28797c478bd9Sstevel@tonic-gate 			    libloc_p->ap_logical);
28807c478bd9Sstevel@tonic-gate 		}
28817c478bd9Sstevel@tonic-gate 
28827c478bd9Sstevel@tonic-gate 		if (cphys == '\0') {
28837c478bd9Sstevel@tonic-gate 			(void) snprintf((alp->array[0]).ap_phys_id,
28847c478bd9Sstevel@tonic-gate 			    sizeof ((alp->array[0]).ap_phys_id), "%s",
28857c478bd9Sstevel@tonic-gate 			    libloc_p->ap_physical);
28867c478bd9Sstevel@tonic-gate 		}
28877c478bd9Sstevel@tonic-gate 	}
28887c478bd9Sstevel@tonic-gate 
28897c478bd9Sstevel@tonic-gate 	if (libloc_p->ap_class[0] == '\0') {
28907c478bd9Sstevel@tonic-gate 		class = CFGA_NO_CLASS;
28917c478bd9Sstevel@tonic-gate 	} else {
28927c478bd9Sstevel@tonic-gate 		class = libloc_p->ap_class;
28937c478bd9Sstevel@tonic-gate 	}
28947c478bd9Sstevel@tonic-gate 
28957c478bd9Sstevel@tonic-gate 	/* Fill in the class information for all list elements */
28967c478bd9Sstevel@tonic-gate 	for (i = 0; i < alp->nelem; i++) {
28977c478bd9Sstevel@tonic-gate 		(void) snprintf((alp->array[i]).ap_class,
28987c478bd9Sstevel@tonic-gate 		    sizeof ((alp->array[i]).ap_class), "%s", class);
28997c478bd9Sstevel@tonic-gate 	}
29007c478bd9Sstevel@tonic-gate 
29017c478bd9Sstevel@tonic-gate 	/*
29027c478bd9Sstevel@tonic-gate 	 * link it in
29037c478bd9Sstevel@tonic-gate 	 */
29047c478bd9Sstevel@tonic-gate 	if ((alp2 = lstatp->al) == NULL) {
29057c478bd9Sstevel@tonic-gate 		lstatp->al = alp;
29067c478bd9Sstevel@tonic-gate 	} else {
29077c478bd9Sstevel@tonic-gate 		while (alp2->next != NULL)
29087c478bd9Sstevel@tonic-gate 			alp2 = alp2->next;
29097c478bd9Sstevel@tonic-gate 		alp2->next = alp;
29107c478bd9Sstevel@tonic-gate 	}
29117c478bd9Sstevel@tonic-gate 
29127c478bd9Sstevel@tonic-gate 	/* keep count */
29137c478bd9Sstevel@tonic-gate 	(*lstatp->countp) += alp->nelem;
29147c478bd9Sstevel@tonic-gate 
29157c478bd9Sstevel@tonic-gate 	return (CFGA_OK);
29167c478bd9Sstevel@tonic-gate }
29177c478bd9Sstevel@tonic-gate 
29187c478bd9Sstevel@tonic-gate /*
29197c478bd9Sstevel@tonic-gate  * Check if a plugin version is within requested limits.
29207c478bd9Sstevel@tonic-gate  */
29217c478bd9Sstevel@tonic-gate static int
29227c478bd9Sstevel@tonic-gate compat_plugin(vers_req_t *reqp, int plugin_vers)
29237c478bd9Sstevel@tonic-gate {
29247c478bd9Sstevel@tonic-gate 
29257c478bd9Sstevel@tonic-gate 	if (!VALID_HSL_VERS(reqp->v_min) || !VALID_HSL_VERS(reqp->v_max) ||
29267c478bd9Sstevel@tonic-gate 	    !VALID_HSL_VERS(plugin_vers)) {
29277c478bd9Sstevel@tonic-gate 		return (0);
29287c478bd9Sstevel@tonic-gate 	}
29297c478bd9Sstevel@tonic-gate 
29307c478bd9Sstevel@tonic-gate 	if (plugin_vers < reqp->v_min || plugin_vers > reqp->v_max) {
29317c478bd9Sstevel@tonic-gate 		return (0);
29327c478bd9Sstevel@tonic-gate 	}
29337c478bd9Sstevel@tonic-gate 
29347c478bd9Sstevel@tonic-gate 
29357c478bd9Sstevel@tonic-gate 	return (1);
29367c478bd9Sstevel@tonic-gate }
29377c478bd9Sstevel@tonic-gate 
29387c478bd9Sstevel@tonic-gate /*
29397c478bd9Sstevel@tonic-gate  * find_arg_type - determine if an argument is an ap_id or an ap_type.
29407c478bd9Sstevel@tonic-gate  * Adapted from cfgadm.c
29417c478bd9Sstevel@tonic-gate  */
29427c478bd9Sstevel@tonic-gate static cfga_ap_types_t
29437c478bd9Sstevel@tonic-gate find_arg_type(const char *ap_id)
29447c478bd9Sstevel@tonic-gate {
29457c478bd9Sstevel@tonic-gate 	struct stat sbuf;
29467c478bd9Sstevel@tonic-gate 	cfga_ap_types_t type = UNKNOWN_AP;
29477c478bd9Sstevel@tonic-gate 	char *mkr = NULL;
29487c478bd9Sstevel@tonic-gate 	size_t len;
29497c478bd9Sstevel@tonic-gate 	int size_ap = 0, size_mkr = 0, digit = 0, i = 0;
29507c478bd9Sstevel@tonic-gate 	char *cp, path[MAXPATHLEN], ap_base[MAXPATHLEN];
29517c478bd9Sstevel@tonic-gate 
29527c478bd9Sstevel@tonic-gate 
29537c478bd9Sstevel@tonic-gate 	/*
29547c478bd9Sstevel@tonic-gate 	 * sanity checks
29557c478bd9Sstevel@tonic-gate 	 */
29567c478bd9Sstevel@tonic-gate 	if (ap_id == NULL || *ap_id == '\0') {
29577c478bd9Sstevel@tonic-gate 
29587c478bd9Sstevel@tonic-gate 		return (UNKNOWN_AP);
29597c478bd9Sstevel@tonic-gate 	}
29607c478bd9Sstevel@tonic-gate 
29617c478bd9Sstevel@tonic-gate 	/*
29627c478bd9Sstevel@tonic-gate 	 * Extract the base component
29637c478bd9Sstevel@tonic-gate 	 */
29647c478bd9Sstevel@tonic-gate 	if ((cp = GET_DYN(ap_id)) != NULL) {
29657c478bd9Sstevel@tonic-gate 		len = cp - ap_id;
29667c478bd9Sstevel@tonic-gate 	} else {
29677c478bd9Sstevel@tonic-gate 		len = strlen(ap_id);
29687c478bd9Sstevel@tonic-gate 	}
29697c478bd9Sstevel@tonic-gate 
29707c478bd9Sstevel@tonic-gate 	if (len >= sizeof (ap_base)) {
29717c478bd9Sstevel@tonic-gate 		return (UNKNOWN_AP);
29727c478bd9Sstevel@tonic-gate 	}
29737c478bd9Sstevel@tonic-gate 
29747c478bd9Sstevel@tonic-gate 	/* Copy only the first "len" chars */
29757c478bd9Sstevel@tonic-gate 	(void) strncpy(ap_base, ap_id, len);
29767c478bd9Sstevel@tonic-gate 	ap_base[len] = '\0';
29777c478bd9Sstevel@tonic-gate 
29787c478bd9Sstevel@tonic-gate 	/*
29797c478bd9Sstevel@tonic-gate 	 * If it starts with a slash and is stat-able its a physical.
29807c478bd9Sstevel@tonic-gate 	 */
29817c478bd9Sstevel@tonic-gate 	if (*ap_base == '/' && stat(ap_base, &sbuf) == 0) {
29827c478bd9Sstevel@tonic-gate 		return (PHYSICAL_AP);
29837c478bd9Sstevel@tonic-gate 	}
29847c478bd9Sstevel@tonic-gate 
29857c478bd9Sstevel@tonic-gate 	/*
29867c478bd9Sstevel@tonic-gate 	 * Is this a symlink in CFGA_DEV_DIR ?
29877c478bd9Sstevel@tonic-gate 	 */
29887c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s%s",
29897c478bd9Sstevel@tonic-gate 	    CFGA_DEV_DIR SLASH, ap_base);
29907c478bd9Sstevel@tonic-gate 
29917c478bd9Sstevel@tonic-gate 	if (lstat(path, &sbuf) == 0 && S_ISLNK(sbuf.st_mode) &&
29927c478bd9Sstevel@tonic-gate 	    stat(path, &sbuf) == 0) {
29937c478bd9Sstevel@tonic-gate 		return (LOGICAL_LINK_AP);
29947c478bd9Sstevel@tonic-gate 	}
29957c478bd9Sstevel@tonic-gate 
29967c478bd9Sstevel@tonic-gate 	/*
29977c478bd9Sstevel@tonic-gate 	 * Check for ":" which is always present in an ap_id
29987c478bd9Sstevel@tonic-gate 	 * but not in an ap_type.
29997c478bd9Sstevel@tonic-gate 	 * we need to check that the characters right before the : are digits
30007c478bd9Sstevel@tonic-gate 	 * since an ap_id is of the form <name><instance>:<specific ap name>
30017c478bd9Sstevel@tonic-gate 	 */
30027c478bd9Sstevel@tonic-gate 	if ((mkr = strchr(ap_base, ':')) == NULL)  {
30037c478bd9Sstevel@tonic-gate 		type = AP_TYPE;
30047c478bd9Sstevel@tonic-gate 	} else {
30057c478bd9Sstevel@tonic-gate 		size_ap = strlen(ap_base);
30067c478bd9Sstevel@tonic-gate 		size_mkr = strlen(mkr);
30077c478bd9Sstevel@tonic-gate 		mkr = ap_base;
30087c478bd9Sstevel@tonic-gate 
30097c478bd9Sstevel@tonic-gate 		digit = 0;
30107c478bd9Sstevel@tonic-gate 		for (i = size_ap - size_mkr - 1;  i > 0; i--) {
30117c478bd9Sstevel@tonic-gate 			if ((int)isdigit(mkr[i])) {
30127c478bd9Sstevel@tonic-gate 				digit++;
30137c478bd9Sstevel@tonic-gate 				break;
30147c478bd9Sstevel@tonic-gate 			}
30157c478bd9Sstevel@tonic-gate 		}
30167c478bd9Sstevel@tonic-gate 		if (digit == 0) {
30177c478bd9Sstevel@tonic-gate 			type = AP_TYPE;
30187c478bd9Sstevel@tonic-gate 		} else {
30197c478bd9Sstevel@tonic-gate 			type = LOGICAL_DRV_AP;
30207c478bd9Sstevel@tonic-gate 		}
30217c478bd9Sstevel@tonic-gate 	}
30227c478bd9Sstevel@tonic-gate 
30237c478bd9Sstevel@tonic-gate 	return (type);
30247c478bd9Sstevel@tonic-gate }
30257c478bd9Sstevel@tonic-gate 
30267c478bd9Sstevel@tonic-gate /*ARGSUSED*/
30277c478bd9Sstevel@tonic-gate static cfga_err_t
30287c478bd9Sstevel@tonic-gate null_get_cond(lib_loc_t *liblocp, cfga_cond_t *condp, char **errstring)
30297c478bd9Sstevel@tonic-gate {
30307c478bd9Sstevel@tonic-gate 	return (CFGA_OK);
30317c478bd9Sstevel@tonic-gate }
30327c478bd9Sstevel@tonic-gate 
30337c478bd9Sstevel@tonic-gate static cfga_err_t
30347c478bd9Sstevel@tonic-gate get_cond_v1(lib_loc_t *liblocp, cfga_cond_t *condp, char **errstring)
30357c478bd9Sstevel@tonic-gate {
30367c478bd9Sstevel@tonic-gate 	plugin_lib_t *libp;
30377c478bd9Sstevel@tonic-gate 	cfga_stat_data_t sdbuf;
30387c478bd9Sstevel@tonic-gate 	cfga_err_t rc;
30397c478bd9Sstevel@tonic-gate 
30407c478bd9Sstevel@tonic-gate 
30417c478bd9Sstevel@tonic-gate 	libp = liblocp->libp;
30427c478bd9Sstevel@tonic-gate 	if (libp->plugin_vers != CFGA_HSL_V1) {
30437c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
30447c478bd9Sstevel@tonic-gate 	}
30457c478bd9Sstevel@tonic-gate 
30467c478bd9Sstevel@tonic-gate 	errno = 0;
30477c478bd9Sstevel@tonic-gate 	if ((rc = (*liblocp->libp->cfga_stat_p)(
30487c478bd9Sstevel@tonic-gate 	    liblocp->ap_physical, &sdbuf, NULL, errstring))
30497c478bd9Sstevel@tonic-gate 	    == CFGA_OK) {
30507c478bd9Sstevel@tonic-gate 		*condp = sdbuf.ap_cond;
30517c478bd9Sstevel@tonic-gate 	} else {
30527c478bd9Sstevel@tonic-gate 		*condp = CFGA_COND_UNKNOWN;
30537c478bd9Sstevel@tonic-gate 	}
30547c478bd9Sstevel@tonic-gate 
30557c478bd9Sstevel@tonic-gate 	return (rc);
30567c478bd9Sstevel@tonic-gate }
30577c478bd9Sstevel@tonic-gate 
30587c478bd9Sstevel@tonic-gate static cfga_err_t
30597c478bd9Sstevel@tonic-gate get_cond_v2(lib_loc_t *liblocp, cfga_cond_t *condp, char **errstring)
30607c478bd9Sstevel@tonic-gate {
30617c478bd9Sstevel@tonic-gate 	int nelem;
30627c478bd9Sstevel@tonic-gate 	plugin_lib_t *libp;
30637c478bd9Sstevel@tonic-gate 	cfga_list_data_t *ldbufp;
30647c478bd9Sstevel@tonic-gate 	cfga_err_t rc;
30657c478bd9Sstevel@tonic-gate 
30667c478bd9Sstevel@tonic-gate 
30677c478bd9Sstevel@tonic-gate 	libp = liblocp->libp;
30687c478bd9Sstevel@tonic-gate 	if (libp->plugin_vers != CFGA_HSL_V2) {
30697c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
30707c478bd9Sstevel@tonic-gate 	}
30717c478bd9Sstevel@tonic-gate 
30727c478bd9Sstevel@tonic-gate 	errno = 0;
30737c478bd9Sstevel@tonic-gate 	nelem = 0;
30747c478bd9Sstevel@tonic-gate 	ldbufp = NULL;
30757c478bd9Sstevel@tonic-gate 	if ((rc = (*liblocp->libp->cfga_list_ext_p)(
30767c478bd9Sstevel@tonic-gate 	    liblocp->ap_physical, &ldbufp, &nelem, NULL, NULL,
30777c478bd9Sstevel@tonic-gate 	    errstring, 0)) == CFGA_OK) {
30787c478bd9Sstevel@tonic-gate 		assert(nelem == 1 && ldbufp != NULL);
30797c478bd9Sstevel@tonic-gate 
30807c478bd9Sstevel@tonic-gate 		*condp = ldbufp->ap_cond;
30817c478bd9Sstevel@tonic-gate 		S_FREE(ldbufp);
30827c478bd9Sstevel@tonic-gate 	} else {
30837c478bd9Sstevel@tonic-gate 		*condp = CFGA_COND_UNKNOWN;
30847c478bd9Sstevel@tonic-gate 	}
30857c478bd9Sstevel@tonic-gate 
30867c478bd9Sstevel@tonic-gate 	return (rc);
30877c478bd9Sstevel@tonic-gate }
30887c478bd9Sstevel@tonic-gate 
30897c478bd9Sstevel@tonic-gate /* mask represents the flags accepted */
30907c478bd9Sstevel@tonic-gate static cfga_err_t
30917c478bd9Sstevel@tonic-gate check_flags(cfga_flags_t flags, cfga_flags_t mask, char **errstring)
30927c478bd9Sstevel@tonic-gate {
30937c478bd9Sstevel@tonic-gate 	if ((flags & ~mask) != 0) {
30947c478bd9Sstevel@tonic-gate 		config_err(0, INVALID_ARGS, errstring);
30957c478bd9Sstevel@tonic-gate 		return (CFGA_ERROR);
30967c478bd9Sstevel@tonic-gate 	} else {
30977c478bd9Sstevel@tonic-gate 		return (CFGA_OK);
30987c478bd9Sstevel@tonic-gate 	}
30997c478bd9Sstevel@tonic-gate }
31007c478bd9Sstevel@tonic-gate 
31017c478bd9Sstevel@tonic-gate static cfga_err_t
31027c478bd9Sstevel@tonic-gate check_apids(int num_ap_ids, char *const *ap_ids, char **errstring)
31037c478bd9Sstevel@tonic-gate {
31047c478bd9Sstevel@tonic-gate 	if (num_ap_ids <= 0 || ap_ids == NULL) {
31057c478bd9Sstevel@tonic-gate 		config_err(0, INVALID_ARGS, errstring);
31067c478bd9Sstevel@tonic-gate 		return (CFGA_ERROR);
31077c478bd9Sstevel@tonic-gate 	} else {
31087c478bd9Sstevel@tonic-gate 		return (CFGA_OK);
31097c478bd9Sstevel@tonic-gate 	}
31107c478bd9Sstevel@tonic-gate }
31117c478bd9Sstevel@tonic-gate 
31127c478bd9Sstevel@tonic-gate /*
31137c478bd9Sstevel@tonic-gate  * Returns the class or the empty string if attacment point has
31147c478bd9Sstevel@tonic-gate  * no class.
31157c478bd9Sstevel@tonic-gate  */
31167c478bd9Sstevel@tonic-gate static char *
31177c478bd9Sstevel@tonic-gate get_class(di_minor_t minor)
31187c478bd9Sstevel@tonic-gate {
31197c478bd9Sstevel@tonic-gate 	char *cp, c;
31207c478bd9Sstevel@tonic-gate 	size_t len;
31217c478bd9Sstevel@tonic-gate 
31227c478bd9Sstevel@tonic-gate 
31237c478bd9Sstevel@tonic-gate 	if (minor == DI_MINOR_NIL) {
31247c478bd9Sstevel@tonic-gate 		return (NULL);
31257c478bd9Sstevel@tonic-gate 	}
31267c478bd9Sstevel@tonic-gate 
31277c478bd9Sstevel@tonic-gate 	cp = di_minor_nodetype(minor);
31287c478bd9Sstevel@tonic-gate 	if (cp == NULL) {
31297c478bd9Sstevel@tonic-gate 		return (NULL);
31307c478bd9Sstevel@tonic-gate 	}
31317c478bd9Sstevel@tonic-gate 
31327c478bd9Sstevel@tonic-gate 	len = strlen(DDI_NT_ATTACHMENT_POINT);
31337c478bd9Sstevel@tonic-gate 	if (strncmp(cp, DDI_NT_ATTACHMENT_POINT, len)) {
31347c478bd9Sstevel@tonic-gate 		return (NULL);
31357c478bd9Sstevel@tonic-gate 	}
31367c478bd9Sstevel@tonic-gate 
31377c478bd9Sstevel@tonic-gate 	cp += len;
31387c478bd9Sstevel@tonic-gate 
31397c478bd9Sstevel@tonic-gate 	c = *cp;
31407c478bd9Sstevel@tonic-gate 	if (c != '\0' && c != ':') {
31417c478bd9Sstevel@tonic-gate 		return (NULL);
31427c478bd9Sstevel@tonic-gate 	}
31437c478bd9Sstevel@tonic-gate 
31447c478bd9Sstevel@tonic-gate 	if (c == ':') {
31457c478bd9Sstevel@tonic-gate 		cp++;
31467c478bd9Sstevel@tonic-gate 	}
31477c478bd9Sstevel@tonic-gate 
31487c478bd9Sstevel@tonic-gate 	return (cp);
31497c478bd9Sstevel@tonic-gate 
31507c478bd9Sstevel@tonic-gate }
31517c478bd9Sstevel@tonic-gate 
31527c478bd9Sstevel@tonic-gate /*
31537c478bd9Sstevel@tonic-gate  * Transform stat data to list data
31547c478bd9Sstevel@tonic-gate  */
31557c478bd9Sstevel@tonic-gate static void
31567c478bd9Sstevel@tonic-gate stat_to_list(cfga_list_data_t *lp, cfga_stat_data_t *statp)
31577c478bd9Sstevel@tonic-gate {
31587c478bd9Sstevel@tonic-gate 
31597c478bd9Sstevel@tonic-gate 	(void) snprintf(lp->ap_log_id, sizeof (lp->ap_log_id), "%s",
31607c478bd9Sstevel@tonic-gate 	    statp->ap_log_id);
31617c478bd9Sstevel@tonic-gate 
31627c478bd9Sstevel@tonic-gate 	(void) snprintf(lp->ap_phys_id, sizeof (lp->ap_phys_id), "%s",
31637c478bd9Sstevel@tonic-gate 	    statp->ap_phys_id);
31647c478bd9Sstevel@tonic-gate 
31657c478bd9Sstevel@tonic-gate 	(void) snprintf(lp->ap_class, sizeof (lp->ap_class), "%s",
31667c478bd9Sstevel@tonic-gate 	    CFGA_NO_CLASS);
31677c478bd9Sstevel@tonic-gate 
31687c478bd9Sstevel@tonic-gate 	lp->ap_r_state = statp->ap_r_state;
31697c478bd9Sstevel@tonic-gate 	lp->ap_o_state = statp->ap_o_state;
31707c478bd9Sstevel@tonic-gate 	lp->ap_cond = statp->ap_cond;
31717c478bd9Sstevel@tonic-gate 	lp->ap_busy = statp->ap_busy;
31727c478bd9Sstevel@tonic-gate 	lp->ap_status_time = statp->ap_status_time;
31737c478bd9Sstevel@tonic-gate 
31747c478bd9Sstevel@tonic-gate 	(void) snprintf(lp->ap_info, sizeof (lp->ap_info), "%s",
31757c478bd9Sstevel@tonic-gate 	    statp->ap_info);
31767c478bd9Sstevel@tonic-gate 	(void) snprintf(lp->ap_type, sizeof (lp->ap_type), "%s",
31777c478bd9Sstevel@tonic-gate 	    statp->ap_type);
31787c478bd9Sstevel@tonic-gate }
31797c478bd9Sstevel@tonic-gate 
31807c478bd9Sstevel@tonic-gate static void
31817c478bd9Sstevel@tonic-gate lstat_free(list_stat_t *lstatp)
31827c478bd9Sstevel@tonic-gate {
31837c478bd9Sstevel@tonic-gate 	stat_data_list_t *slp, *slp2;
31847c478bd9Sstevel@tonic-gate 	array_list_t *ap, *ap2;
31857c478bd9Sstevel@tonic-gate 
31867c478bd9Sstevel@tonic-gate 	slp = lstatp->sdl;
31877c478bd9Sstevel@tonic-gate 	while (slp != NULL) {
31887c478bd9Sstevel@tonic-gate 		slp2 = slp->next;
31897c478bd9Sstevel@tonic-gate 		S_FREE(slp);
31907c478bd9Sstevel@tonic-gate 		slp = slp2;
31917c478bd9Sstevel@tonic-gate 	}
31927c478bd9Sstevel@tonic-gate 
31937c478bd9Sstevel@tonic-gate 	lstatp->sdl = NULL;
31947c478bd9Sstevel@tonic-gate 
31957c478bd9Sstevel@tonic-gate 	ap = lstatp->al;
31967c478bd9Sstevel@tonic-gate 	while (ap != NULL) {
31977c478bd9Sstevel@tonic-gate 		ap2 = ap->next;
31987c478bd9Sstevel@tonic-gate 		S_FREE(ap->array);
31997c478bd9Sstevel@tonic-gate 		S_FREE(ap);
32007c478bd9Sstevel@tonic-gate 		ap = ap2;
32017c478bd9Sstevel@tonic-gate 	}
32027c478bd9Sstevel@tonic-gate 
32037c478bd9Sstevel@tonic-gate 	lstatp->al = NULL;
32047c478bd9Sstevel@tonic-gate }
32057c478bd9Sstevel@tonic-gate 
32067c478bd9Sstevel@tonic-gate static cfga_err_t
32077c478bd9Sstevel@tonic-gate split_apid(char *ap_id, char **dyncompp, char **errstring)
32087c478bd9Sstevel@tonic-gate {
32097c478bd9Sstevel@tonic-gate 	char *cp;
32107c478bd9Sstevel@tonic-gate 
32117c478bd9Sstevel@tonic-gate 	*dyncompp = NULL;
32127c478bd9Sstevel@tonic-gate 
32137c478bd9Sstevel@tonic-gate 	if (ap_id == NULL) {
32147c478bd9Sstevel@tonic-gate 		return (CFGA_ERROR);
32157c478bd9Sstevel@tonic-gate 	}
32167c478bd9Sstevel@tonic-gate 
32177c478bd9Sstevel@tonic-gate 	if ((cp = strstr(ap_id, CFGA_DYN_SEP)) == NULL) {
32187c478bd9Sstevel@tonic-gate 		return (CFGA_OK);
32197c478bd9Sstevel@tonic-gate 	}
32207c478bd9Sstevel@tonic-gate 
32217c478bd9Sstevel@tonic-gate 	*cp = '\0';
32227c478bd9Sstevel@tonic-gate 	cp += strlen(CFGA_DYN_SEP);
32237c478bd9Sstevel@tonic-gate 	if ((*dyncompp = config_calloc_check(1, strlen(cp) + 1,
32247c478bd9Sstevel@tonic-gate 	    errstring)) == NULL) {
32257c478bd9Sstevel@tonic-gate 		return (CFGA_LIB_ERROR);
32267c478bd9Sstevel@tonic-gate 	}
32277c478bd9Sstevel@tonic-gate 	(void) strcpy(*dyncompp, cp);
32287c478bd9Sstevel@tonic-gate 
32297c478bd9Sstevel@tonic-gate 	return (CFGA_OK);
32307c478bd9Sstevel@tonic-gate }
32317c478bd9Sstevel@tonic-gate 
32327c478bd9Sstevel@tonic-gate static void
32337c478bd9Sstevel@tonic-gate append_dyn(char *buf, const char *dyncomp, size_t blen)
32347c478bd9Sstevel@tonic-gate {
32357c478bd9Sstevel@tonic-gate 	if (dyncomp != NULL) {
32367c478bd9Sstevel@tonic-gate 		char *cp = buf + strlen(buf);
32377c478bd9Sstevel@tonic-gate 		size_t len = blen - strlen(buf);
32387c478bd9Sstevel@tonic-gate 
32397c478bd9Sstevel@tonic-gate 		(void) snprintf(cp, len, "%s%s", CFGA_DYN_SEP,
32407c478bd9Sstevel@tonic-gate 		    dyncomp);
32417c478bd9Sstevel@tonic-gate 	}
32427c478bd9Sstevel@tonic-gate }
32437c478bd9Sstevel@tonic-gate 
32447c478bd9Sstevel@tonic-gate /*
32457c478bd9Sstevel@tonic-gate  * Default implementation of cfga_ap_id_cmp. Works for most cases
32467c478bd9Sstevel@tonic-gate  * except for long hex number sequences like world-wide-name.
32477c478bd9Sstevel@tonic-gate  *
32487c478bd9Sstevel@tonic-gate  * This function compares the ap's in a generic way.  It does so by
32497c478bd9Sstevel@tonic-gate  * determining the place of difference between the 2 aps.  If the first
32507c478bd9Sstevel@tonic-gate  * difference is a digit, it attempts to obtain the numbers and compare them
32517c478bd9Sstevel@tonic-gate  * Otherwise it just compares the aps as strings
32527c478bd9Sstevel@tonic-gate  */
32537c478bd9Sstevel@tonic-gate static int
32547c478bd9Sstevel@tonic-gate default_ap_id_cmp(const char *ap_id1, const char *ap_id2)
32557c478bd9Sstevel@tonic-gate {
32567c478bd9Sstevel@tonic-gate 	int i = 0;
32577c478bd9Sstevel@tonic-gate 
32587c478bd9Sstevel@tonic-gate 	/*
32597c478bd9Sstevel@tonic-gate 	 * Search for first different char
32607c478bd9Sstevel@tonic-gate 	 */
32617c478bd9Sstevel@tonic-gate 	while (ap_id1[i] == ap_id2[i] && ap_id1[i] != '\0')
32627c478bd9Sstevel@tonic-gate 		i++;
32637c478bd9Sstevel@tonic-gate 
32647c478bd9Sstevel@tonic-gate 	/*
32657c478bd9Sstevel@tonic-gate 	 * If one of the char is a digit, back up to where the
32667c478bd9Sstevel@tonic-gate 	 * number started, compare the number.
32677c478bd9Sstevel@tonic-gate 	 */
32687c478bd9Sstevel@tonic-gate 	if (isdigit(ap_id1[i]) || isdigit(ap_id2[i])) {
32697c478bd9Sstevel@tonic-gate 		while ((i > 0) && isdigit(ap_id1[i - 1]))
32707c478bd9Sstevel@tonic-gate 			i--;
32717c478bd9Sstevel@tonic-gate 
32727c478bd9Sstevel@tonic-gate 		if (isdigit(ap_id1[i]) && isdigit(ap_id2[i]))
32737c478bd9Sstevel@tonic-gate 			return (atoi(ap_id1 + i) - atoi(ap_id2 + i));
32747c478bd9Sstevel@tonic-gate 	}
32757c478bd9Sstevel@tonic-gate 
32767c478bd9Sstevel@tonic-gate 	/* One of them isn't a number, compare the char */
32777c478bd9Sstevel@tonic-gate 	return (ap_id1[i] - ap_id2[i]);
32787c478bd9Sstevel@tonic-gate }
32797c478bd9Sstevel@tonic-gate 
32807c478bd9Sstevel@tonic-gate static void
32817c478bd9Sstevel@tonic-gate hold_lib(plugin_lib_t *libp)
32827c478bd9Sstevel@tonic-gate {
32837c478bd9Sstevel@tonic-gate 	assert(libp->refcnt >= 0);
32847c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&libp->lock);
32857c478bd9Sstevel@tonic-gate 	libp->refcnt++;
32867c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&libp->lock);
32877c478bd9Sstevel@tonic-gate }
32887c478bd9Sstevel@tonic-gate 
32897c478bd9Sstevel@tonic-gate static void
32907c478bd9Sstevel@tonic-gate rele_lib(plugin_lib_t *libp)
32917c478bd9Sstevel@tonic-gate {
32927c478bd9Sstevel@tonic-gate 	assert(libp->refcnt > 0);
32937c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&libp->lock);
32947c478bd9Sstevel@tonic-gate 	libp->refcnt--;
32957c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&libp->lock);
32967c478bd9Sstevel@tonic-gate }
3297