1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1957 dnielsen * Common Development and Distribution License (the "License"). 6 1957 dnielsen * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 133 dmick 22 133 dmick /* Portions Copyright 2005 Cyril Plisko */ 23 133 dmick 24 0 stevel /* 25 10923 Evan * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 26 0 stevel * Use is subject to license terms. 27 0 stevel */ 28 0 stevel 29 0 stevel #include <errno.h> 30 0 stevel #include <stdio.h> 31 0 stevel #include <stdlib.h> 32 0 stevel #include <string.h> 33 0 stevel #include <locale.h> 34 0 stevel #include <langinfo.h> 35 0 stevel #include <time.h> 36 0 stevel 37 0 stevel #if !defined(DEBUG) 38 0 stevel #define NDEBUG 1 39 0 stevel #else 40 0 stevel #undef NDEBUG 41 0 stevel #endif 42 0 stevel 43 0 stevel #include <assert.h> 44 0 stevel #include <sys/types.h> 45 0 stevel #include <sys/stat.h> 46 0 stevel #include <sys/param.h> 47 0 stevel #include <dlfcn.h> 48 0 stevel #include <synch.h> 49 0 stevel #include <sys/systeminfo.h> 50 0 stevel #include <sys/sunddi.h> 51 0 stevel #include <libdevinfo.h> 52 0 stevel #include <unistd.h> 53 0 stevel #include <stdarg.h> 54 0 stevel #include <limits.h> 55 0 stevel #include <ftw.h> 56 0 stevel #include <ctype.h> 57 0 stevel 58 0 stevel #define CFGA_PLUGIN_LIB 59 0 stevel #include <config_admin.h> 60 0 stevel 61 0 stevel /* Limit size of sysinfo return */ 62 0 stevel #define SYSINFO_LENGTH 256 63 0 stevel 64 0 stevel /* 65 0 stevel * Attachment point specifier types. 66 0 stevel */ 67 0 stevel typedef enum { 68 0 stevel UNKNOWN_AP, 69 0 stevel LOGICAL_LINK_AP, 70 0 stevel LOGICAL_DRV_AP, 71 0 stevel PHYSICAL_AP, 72 0 stevel AP_TYPE 73 0 stevel } cfga_ap_types_t; 74 0 stevel 75 0 stevel static char *listopt_array[] = { 76 0 stevel 77 0 stevel #define LISTOPT_CLASS 0 78 0 stevel "class", 79 0 stevel NULL 80 0 stevel }; 81 0 stevel 82 0 stevel typedef struct { 83 0 stevel int v_min; /* Min acceptable version */ 84 0 stevel int v_max; /* Max acceptable version */ 85 0 stevel } vers_req_t; 86 0 stevel 87 0 stevel #define INVALID_VERSION -1 88 0 stevel #define VALID_HSL_VERS(v) (((v) >= CFGA_HSL_V1) && \ 89 0 stevel ((v) <= CFGA_HSL_VERS)) 90 0 stevel 91 0 stevel /* 92 0 stevel * Incomplete definition 93 0 stevel */ 94 0 stevel struct cfga_vers_ops; 95 0 stevel 96 0 stevel /* 97 0 stevel * Structure that contains plugin library information. 98 0 stevel */ 99 0 stevel typedef struct plugin_lib { 100 0 stevel struct plugin_lib *next; /* pointer to next */ 101 0 stevel mutex_t lock; /* protects refcnt */ 102 0 stevel int refcnt; /* reference count */ 103 0 stevel void *handle; /* handle from dlopen */ 104 0 stevel cfga_err_t (*cfga_change_state_p)(); 105 0 stevel cfga_err_t (*cfga_private_func_p)(); 106 0 stevel cfga_err_t (*cfga_test_p)(); 107 0 stevel cfga_err_t (*cfga_stat_p)(); 108 0 stevel cfga_err_t (*cfga_list_p)(); 109 0 stevel cfga_err_t (*cfga_help_p)(); 110 0 stevel int (*cfga_ap_id_cmp_p)(); 111 0 stevel cfga_err_t (*cfga_list_ext_p)(); /* For V2 plug-ins only */ 112 0 stevel 113 0 stevel int plugin_vers; /* actual plugin version */ 114 0 stevel struct cfga_vers_ops *vers_ops; /* version dependant routines */ 115 0 stevel char libpath[MAXPATHLEN]; /* full pathname to lib */ 116 0 stevel } plugin_lib_t; 117 0 stevel 118 0 stevel static plugin_lib_t plugin_list; 119 0 stevel 120 0 stevel typedef struct lib_cache { 121 0 stevel struct lib_cache *lc_next; 122 0 stevel plugin_lib_t *lc_libp; 123 0 stevel char *lc_ap_id; 124 0 stevel char *lc_ap_physical; /* physical ap_id */ 125 0 stevel char *lc_ap_logical; /* logical ap_id */ 126 0 stevel } lib_cache_t; 127 0 stevel 128 0 stevel static lib_cache_t *lib_cache; 129 0 stevel static mutex_t lib_cache_lock; 130 0 stevel 131 0 stevel /* 132 0 stevel * Library locator data struct - used to pass down through the device 133 0 stevel * tree walking code. 134 0 stevel */ 135 0 stevel typedef struct lib_locator { 136 0 stevel char ap_base[MAXPATHLEN]; 137 0 stevel char ap_logical[CFGA_LOG_EXT_LEN]; 138 0 stevel char ap_physical[CFGA_PHYS_EXT_LEN]; 139 0 stevel char ap_class[CFGA_CLASS_LEN]; 140 0 stevel char pathname[MAXPATHLEN]; 141 0 stevel plugin_lib_t *libp; 142 0 stevel cfga_err_t status; 143 0 stevel vers_req_t vers_req; /* plug-in version required */ 144 0 stevel } lib_loc_t; 145 0 stevel 146 0 stevel /* 147 0 stevel * linked list of cfga_stat_data structs - used for 148 0 stevel * config_list 149 0 stevel */ 150 0 stevel typedef struct stat_data_list { 151 0 stevel struct stat_data_list *next; 152 0 stevel cfga_stat_data_t stat_data; 153 0 stevel } stat_data_list_t; 154 0 stevel 155 0 stevel /* 156 0 stevel * linked list of arrays. Each array represents a bunch 157 0 stevel * of list_data_t structures returned by a single call 158 0 stevel * to a plugin's cfga_list_ext() routine. 159 0 stevel */ 160 0 stevel typedef struct array_list { 161 0 stevel struct array_list *next; 162 0 stevel cfga_list_data_t *array; 163 0 stevel int nelem; 164 0 stevel } array_list_t; 165 0 stevel 166 0 stevel /* 167 0 stevel * encapsulate config_list args to get them through the tree 168 0 stevel * walking code 169 0 stevel */ 170 0 stevel typedef struct list_stat { 171 0 stevel const char *opts; /* Hardware specific options */ 172 0 stevel char **errstr; 173 0 stevel cfga_flags_t flags; 174 0 stevel int *countp; /* Total number of list and stat structures */ 175 0 stevel stat_data_list_t *sdl; /* Linked list of stat structures */ 176 0 stevel array_list_t *al; /* Linked list of arrays of list structures */ 177 0 stevel vers_req_t use_vers; /* plugin versions to be stat'ed */ 178 10923 Evan char *shp_errstr; /* only for shp plugin */ 179 0 stevel } list_stat_t; 180 0 stevel 181 0 stevel /* 182 0 stevel * Internal operations for libcfgadm which are version dependant 183 0 stevel */ 184 0 stevel struct cfga_vers_ops { 185 0 stevel cfga_err_t (*resolve_lib)(plugin_lib_t *libp); 186 0 stevel cfga_err_t (*stat_plugin)(list_stat_t *, lib_loc_t *, char **errstring); 187 0 stevel cfga_err_t (*mklog)(di_node_t, di_minor_t, plugin_lib_t *, 188 0 stevel lib_loc_t *liblocp); 189 0 stevel cfga_err_t (*get_cond)(lib_loc_t *, cfga_cond_t *, char **); 190 0 stevel }; 191 0 stevel 192 0 stevel 193 0 stevel /* 194 0 stevel * Lock to protect list of libraries 195 0 stevel */ 196 0 stevel static mutex_t plugin_list_lock; 197 0 stevel 198 0 stevel /* 199 0 stevel * Forward declarations 200 0 stevel */ 201 0 stevel 202 0 stevel static const char *__config_strerror(cfga_err_t); 203 0 stevel static void *config_calloc_check(size_t, size_t, char **); 204 0 stevel static cfga_err_t resolve_lib_ref(plugin_lib_t *, lib_loc_t *); 205 0 stevel static cfga_err_t config_get_lib(const char *, lib_loc_t *, char **); 206 0 stevel static int check_ap(di_node_t, di_minor_t, void *); 207 10923 Evan static int check_ap_hp(di_node_t, di_hp_t, void *); 208 10923 Evan static int check_ap_impl(di_node_t, di_minor_t, di_hp_t, void *); 209 0 stevel static int check_ap_phys(di_node_t, di_minor_t, void *); 210 10923 Evan static int check_ap_phys_hp(di_node_t, di_hp_t, void *); 211 10923 Evan static int check_ap_phys_impl(di_node_t, di_minor_t, di_hp_t, void *); 212 0 stevel 213 0 stevel static cfga_err_t find_ap_common(lib_loc_t *libloc_p, const char *rootpath, 214 10923 Evan int (*fcn)(di_node_t node, di_minor_t minor, void *arg), 215 10923 Evan int (*fcn_hp)(di_node_t node, di_hp_t hp, void *arg), 216 10923 Evan char **errstring); 217 0 stevel 218 0 stevel static plugin_lib_t *lib_in_list(char *); 219 10923 Evan static cfga_err_t find_lib(di_node_t, di_minor_t, lib_loc_t *); 220 10923 Evan static cfga_err_t find_lib_hp(di_node_t, di_hp_t, lib_loc_t *); 221 10923 Evan static cfga_err_t find_lib_impl(char *, lib_loc_t *); 222 0 stevel static cfga_err_t load_lib(di_node_t, di_minor_t, lib_loc_t *); 223 10923 Evan static cfga_err_t load_lib_hp(di_node_t, di_hp_t, lib_loc_t *); 224 10923 Evan static cfga_err_t load_lib_impl(di_node_t, di_minor_t, di_hp_t, lib_loc_t *); 225 0 stevel extern void bcopy(const void *, void *, size_t); 226 0 stevel static void config_err(int, int, char **); 227 0 stevel static void hold_lib(plugin_lib_t *); 228 0 stevel static void rele_lib(plugin_lib_t *); 229 0 stevel 230 0 stevel static cfga_err_t parse_listopt(char *listopts, char **classpp, 231 0 stevel char **errstring); 232 0 stevel 233 0 stevel static cfga_err_t list_common(list_stat_t *lstatp, const char *class); 234 0 stevel static int do_list_common(di_node_t node, di_minor_t minor, void *arg); 235 10923 Evan static int do_list_common_hp(di_node_t node, di_hp_t hp, void *arg); 236 10923 Evan static int do_list_common_impl(di_node_t node, di_minor_t minor, 237 10923 Evan di_hp_t hp, void *arg); 238 0 stevel static cfga_err_t stat_common(int num_ap_ids, char *const *ap_ids, 239 0 stevel const char *class, list_stat_t *lstatp); 240 0 stevel 241 0 stevel static cfga_err_t null_resolve(plugin_lib_t *libp); 242 0 stevel static cfga_err_t resolve_v1(plugin_lib_t *libp); 243 0 stevel static cfga_err_t resolve_v2(plugin_lib_t *libp); 244 0 stevel 245 0 stevel static cfga_err_t mklog_common(di_node_t node, di_minor_t minor, 246 0 stevel lib_loc_t *liblocp, size_t len); 247 0 stevel 248 0 stevel static cfga_err_t null_mklog(di_node_t node, di_minor_t minor, 249 0 stevel plugin_lib_t *libp, lib_loc_t *liblocp); 250 0 stevel static cfga_err_t mklog_v1(di_node_t node, di_minor_t minor, 251 0 stevel plugin_lib_t *libp, lib_loc_t *liblocp); 252 0 stevel static cfga_err_t mklog_v2(di_node_t node, di_minor_t minor, 253 0 stevel plugin_lib_t *libp, lib_loc_t *liblocp); 254 0 stevel 255 0 stevel static cfga_err_t null_stat_plugin(list_stat_t *lstatp, lib_loc_t *libloc_p, 256 0 stevel char **errstring); 257 0 stevel static cfga_err_t stat_plugin_v2(list_stat_t *lstat, lib_loc_t *libloc_p, 258 0 stevel char **errstring); 259 0 stevel static cfga_err_t stat_plugin_v1(list_stat_t *lstat, lib_loc_t *libloc_p, 260 0 stevel char **errstring); 261 0 stevel 262 0 stevel static cfga_err_t null_get_cond(lib_loc_t *liblocp, cfga_cond_t *condp, 263 0 stevel char **errstring); 264 0 stevel static cfga_err_t get_cond_v1(lib_loc_t *liblocp, cfga_cond_t *condp, 265 0 stevel char **errstring); 266 0 stevel static cfga_err_t get_cond_v2(lib_loc_t *liblocp, cfga_cond_t *condp, 267 0 stevel char **errstring); 268 0 stevel 269 0 stevel static cfga_err_t realloc_data(cfga_stat_data_t **ap_id_list, 270 0 stevel int *nlistp, list_stat_t *lstatp); 271 0 stevel static cfga_err_t realloc_data_ext(cfga_list_data_t **ap_id_list, 272 0 stevel int *nlistp, list_stat_t *lstatp); 273 0 stevel 274 0 stevel static void stat_to_list(cfga_list_data_t *lp, cfga_stat_data_t *statp); 275 0 stevel static void lstat_free(list_stat_t *lstatp); 276 0 stevel static cfga_ap_types_t find_arg_type(const char *ap_id); 277 0 stevel static int compat_plugin(vers_req_t *reqp, int plugin_vers); 278 0 stevel 279 0 stevel static cfga_err_t check_flags(cfga_flags_t flags, cfga_flags_t mask, 280 0 stevel char **errstring); 281 0 stevel static cfga_err_t check_apids(int num_ap_ids, char *const *ap_ids, 282 0 stevel char **errstring); 283 0 stevel 284 0 stevel static char *get_class(di_minor_t minor); 285 0 stevel static cfga_err_t split_apid(char *ap_id, char **dyncompp, char **errstring); 286 0 stevel static void append_dyn(char *buf, const char *dyncomp, size_t blen); 287 0 stevel static int default_ap_id_cmp(const char *ap_id1, const char *ap_id2); 288 0 stevel static void destroy_cache(); 289 0 stevel 290 0 stevel /* 291 0 stevel * Plugin library search path helpers 292 0 stevel */ 293 0 stevel #define LIB_PATH_BASE1 "/usr/platform/" 294 0 stevel #define LIB_PATH_BASE2 "/usr" 295 133 dmick #if defined(__sparcv9) 296 0 stevel #define LIB_PATH_MIDDLE "/lib/cfgadm/sparcv9/" 297 133 dmick #elif defined(__amd64) 298 133 dmick #define LIB_PATH_MIDDLE "/lib/cfgadm/amd64/" 299 0 stevel #else 300 0 stevel #define LIB_PATH_MIDDLE "/lib/cfgadm/" 301 0 stevel #endif 302 0 stevel #define LIB_PATH_TAIL ".so.1" 303 0 stevel 304 0 stevel 305 0 stevel #if !defined(TEXT_DOMAIN) 306 0 stevel #define TEXT_DOMAIN "SYS_TEST" 307 0 stevel #endif 308 0 stevel 309 0 stevel /* 310 0 stevel * Defined constants 311 0 stevel */ 312 0 stevel #define DEVICES_DIR "/devices" 313 0 stevel #define DOT_DOT_DEVICES "../devices" 314 0 stevel #define CFGA_DEV_DIR "/dev/cfg" 315 0 stevel #define SLASH "/" 316 0 stevel #define S_FREE(x) (((x) != NULL) ? (free(x), (x) = NULL) : (void *)0) 317 0 stevel #define GET_DYN(a) (strstr((a), CFGA_DYN_SEP)) 318 0 stevel 319 0 stevel #define CFGA_NO_CLASS "none" 320 0 stevel 321 0 stevel /* 322 0 stevel * Error strings 323 0 stevel */ 324 0 stevel #define DI_INIT_FAILED 1 325 0 stevel #define ALLOC_FAILED 2 326 0 stevel #define INVALID_ARGS 3 327 0 stevel 328 0 stevel static char * 329 0 stevel err_strings[] = { 330 0 stevel NULL, 331 0 stevel "Device library initialize failed", 332 0 stevel "Memory allocation failed", 333 0 stevel "Invalid argument(s)" 334 0 stevel }; 335 0 stevel 336 0 stevel static const char err_sep[] = ": "; 337 0 stevel 338 0 stevel 339 0 stevel /* 340 0 stevel * Table of version dependant routines 341 0 stevel */ 342 0 stevel static struct cfga_vers_ops cfga_vers_ops[CFGA_HSL_VERS + 1] = { 343 0 stevel 344 0 stevel {null_resolve, null_stat_plugin, null_mklog, null_get_cond }, 345 0 stevel {resolve_v1, stat_plugin_v1, mklog_v1, get_cond_v1 }, 346 0 stevel {resolve_v2, stat_plugin_v2, mklog_v2, get_cond_v2 } 347 0 stevel 348 0 stevel }; 349 0 stevel #define VERS_ARRAY_SZ (sizeof (cfga_vers_ops)/sizeof (cfga_vers_ops[0])) 350 0 stevel 351 0 stevel 352 0 stevel /* 353 0 stevel * Public interfaces for libcfgadm, as documented in config_admin.3x 354 0 stevel */ 355 0 stevel 356 0 stevel /* 357 0 stevel * config_change_state 358 0 stevel */ 359 0 stevel 360 0 stevel cfga_err_t 361 0 stevel config_change_state( 362 0 stevel cfga_cmd_t state_change_cmd, 363 0 stevel int num_ap_ids, 364 0 stevel char *const *ap_id, 365 0 stevel const char *options, 366 0 stevel struct cfga_confirm *confp, 367 0 stevel struct cfga_msg *msgp, 368 0 stevel char **errstring, 369 0 stevel cfga_flags_t flags) 370 0 stevel { 371 0 stevel /* 372 0 stevel * for each arg - 373 0 stevel * load hs library, 374 0 stevel * if force 375 0 stevel * call cfga_state_change_func 376 0 stevel * return status 377 0 stevel * else 378 0 stevel * call it's cfga_stat 379 0 stevel * check condition 380 0 stevel * call cfga_state_change_func 381 0 stevel * return status 382 0 stevel */ 383 0 stevel int i; 384 0 stevel lib_loc_t libloc; 385 0 stevel plugin_lib_t *libp; 386 0 stevel cfga_cond_t cond; 387 0 stevel 388 0 stevel cfga_err_t retval = CFGA_OK; 389 0 stevel 390 0 stevel /* Sanity checks */ 391 0 stevel if (state_change_cmd == CFGA_CMD_NONE) 392 0 stevel return (retval); 393 0 stevel 394 0 stevel if ((state_change_cmd < CFGA_CMD_NONE) || 395 0 stevel (state_change_cmd > CFGA_CMD_UNCONFIGURE)) 396 0 stevel return (CFGA_INVAL); 397 0 stevel 398 0 stevel if (errstring != NULL) { 399 0 stevel *errstring = NULL; 400 0 stevel } 401 0 stevel 402 0 stevel if (check_flags(flags, CFGA_FLAG_FORCE | CFGA_FLAG_VERBOSE, errstring) 403 0 stevel != CFGA_OK) { 404 0 stevel return (CFGA_ERROR); 405 0 stevel } 406 0 stevel 407 0 stevel if (check_apids(num_ap_ids, ap_id, errstring) != CFGA_OK) { 408 0 stevel return (CFGA_ERROR); 409 0 stevel } 410 0 stevel 411 0 stevel /* 412 0 stevel * operate on each ap_id 413 0 stevel */ 414 0 stevel for (i = 0; (i < num_ap_ids) && (retval == CFGA_OK); i++) { 415 0 stevel libloc.libp = NULL; 416 0 stevel if ((retval = config_get_lib(ap_id[i], &libloc, errstring)) != 417 0 stevel CFGA_OK) { 418 0 stevel break; 419 0 stevel } 420 0 stevel 421 0 stevel libp = libloc.libp; 422 0 stevel if ((flags & CFGA_FLAG_FORCE) || 423 0 stevel (state_change_cmd == CFGA_CMD_UNLOAD) || 424 0 stevel (state_change_cmd == CFGA_CMD_DISCONNECT) || 425 0 stevel (state_change_cmd == CFGA_CMD_UNCONFIGURE)) { 426 0 stevel errno = 0; 427 0 stevel retval = (*libp->cfga_change_state_p) 428 0 stevel (state_change_cmd, libloc.ap_physical, options, 429 0 stevel confp, msgp, errstring, flags); 430 0 stevel } else { 431 0 stevel /* 432 0 stevel * Need to check condition before proceeding in 433 0 stevel * the "configure direction" 434 0 stevel */ 435 0 stevel if ((retval = libp->vers_ops->get_cond(&libloc, &cond, 436 0 stevel errstring)) != CFGA_OK) { 437 0 stevel break; 438 0 stevel } 439 0 stevel 440 0 stevel if (cond == CFGA_COND_OK || cond == CFGA_COND_UNKNOWN) { 441 0 stevel errno = 0; 442 0 stevel retval = 443 0 stevel (*libp->cfga_change_state_p)( 444 0 stevel state_change_cmd, 445 0 stevel libloc.ap_physical, options, 446 0 stevel confp, msgp, errstring, 447 0 stevel flags); 448 0 stevel } else { 449 0 stevel retval = CFGA_INSUFFICENT_CONDITION; 450 0 stevel } 451 0 stevel } 452 0 stevel rele_lib(libp); 453 0 stevel } 454 0 stevel 455 0 stevel return (retval); 456 0 stevel } 457 0 stevel 458 0 stevel /* 459 0 stevel * config_private_func 460 0 stevel */ 461 0 stevel 462 0 stevel cfga_err_t 463 0 stevel config_private_func( 464 0 stevel const char *function, 465 0 stevel int num_ap_ids, 466 0 stevel char *const *ap_ids, 467 0 stevel const char *options, 468 0 stevel struct cfga_confirm *confp, 469 0 stevel struct cfga_msg *msgp, 470 0 stevel char **errstring, 471 0 stevel cfga_flags_t flags) 472 0 stevel { 473 0 stevel int i; 474 0 stevel lib_loc_t libloc; 475 0 stevel cfga_err_t retval = CFGA_OK; 476 0 stevel 477 0 stevel 478 0 stevel if (errstring != NULL) { 479 0 stevel *errstring = NULL; 480 0 stevel } 481 0 stevel 482 0 stevel if (check_flags(flags, CFGA_FLAG_FORCE | CFGA_FLAG_VERBOSE, errstring) 483 0 stevel != CFGA_OK) { 484 0 stevel return (CFGA_ERROR); 485 0 stevel } 486 0 stevel 487 0 stevel if (check_apids(num_ap_ids, ap_ids, errstring) != CFGA_OK) { 488 0 stevel return (CFGA_ERROR); 489 0 stevel } 490 0 stevel 491 0 stevel /* 492 0 stevel * operate on each ap_id 493 0 stevel */ 494 0 stevel for (i = 0; (i < num_ap_ids) && (retval == CFGA_OK); i++) { 495 0 stevel libloc.libp = NULL; 496 0 stevel if ((retval = config_get_lib(ap_ids[i], &libloc, errstring)) != 497 0 stevel CFGA_OK) { 498 0 stevel return (retval); 499 0 stevel } 500 0 stevel 501 0 stevel errno = 0; 502 0 stevel retval = (*libloc.libp->cfga_private_func_p)(function, 503 0 stevel libloc.ap_physical, options, confp, msgp, errstring, 504 0 stevel flags); 505 0 stevel rele_lib(libloc.libp); 506 0 stevel } 507 0 stevel 508 0 stevel return (retval); 509 0 stevel } 510 0 stevel 511 0 stevel 512 0 stevel /* 513 0 stevel * config_test 514 0 stevel */ 515 0 stevel 516 0 stevel cfga_err_t 517 0 stevel config_test( 518 0 stevel int num_ap_ids, 519 0 stevel char *const *ap_ids, 520 0 stevel const char *options, 521 0 stevel struct cfga_msg *msgp, 522 0 stevel char **errstring, 523 0 stevel cfga_flags_t flags) 524 0 stevel { 525 0 stevel int i; 526 0 stevel lib_loc_t libloc; 527 0 stevel cfga_err_t retval = CFGA_OK; 528 0 stevel 529 0 stevel if (errstring != NULL) { 530 0 stevel *errstring = NULL; 531 0 stevel } 532 0 stevel 533 0 stevel if (check_flags(flags, CFGA_FLAG_FORCE | CFGA_FLAG_VERBOSE, errstring) 534 0 stevel != CFGA_OK) { 535 0 stevel return (CFGA_ERROR); 536 0 stevel } 537 0 stevel 538 0 stevel if (check_apids(num_ap_ids, ap_ids, errstring) != CFGA_OK) { 539 0 stevel return (CFGA_ERROR); 540 0 stevel } 541 0 stevel 542 0 stevel /* 543 0 stevel * operate on each ap_id 544 0 stevel */ 545 0 stevel for (i = 0; (i < num_ap_ids) && (retval == CFGA_OK); i++) { 546 0 stevel libloc.libp = NULL; 547 0 stevel if ((retval = config_get_lib(ap_ids[i], &libloc, errstring)) != 548 0 stevel CFGA_OK) { 549 0 stevel return (retval); 550 0 stevel } 551 0 stevel 552 0 stevel errno = 0; 553 0 stevel retval = (*libloc.libp->cfga_test_p)(libloc.ap_physical, 554 0 stevel options, msgp, errstring, flags); 555 0 stevel rele_lib(libloc.libp); 556 0 stevel } 557 0 stevel 558 0 stevel return (retval); 559 0 stevel } 560 0 stevel 561 0 stevel cfga_err_t 562 0 stevel config_stat( 563 0 stevel int num_ap_ids, 564 0 stevel char *const *ap_ids, 565 0 stevel struct cfga_stat_data *buf, 566 0 stevel const char *options, 567 0 stevel char **errstring) 568 0 stevel { 569 0 stevel int nstat, n, i; 570 0 stevel list_stat_t lstat = {NULL}; 571 0 stevel cfga_err_t rc = CFGA_OK; 572 0 stevel 573 0 stevel if (check_apids(num_ap_ids, ap_ids, errstring) != CFGA_OK) { 574 0 stevel return (CFGA_ERROR); 575 0 stevel } 576 0 stevel 577 0 stevel /* 578 0 stevel * V1 entry points don't support dynamic attachment points 579 0 stevel */ 580 0 stevel for (i = 0; i < num_ap_ids; i++) { 581 0 stevel if (GET_DYN(ap_ids[i]) != NULL) { 582 0 stevel return (CFGA_APID_NOEXIST); 583 0 stevel } 584 0 stevel } 585 0 stevel 586 0 stevel 587 0 stevel nstat = n = 0; 588 0 stevel lstat.countp = &nstat; 589 0 stevel lstat.opts = options; 590 0 stevel lstat.errstr = errstring; 591 10923 Evan lstat.shp_errstr = NULL; 592 0 stevel /* 593 0 stevel * This is a V1 interface which can use only V1 plugins 594 0 stevel */ 595 0 stevel lstat.use_vers.v_max = lstat.use_vers.v_min = CFGA_HSL_V1; 596 0 stevel 597 0 stevel rc = stat_common(num_ap_ids, ap_ids, NULL, &lstat); 598 0 stevel if (rc == CFGA_OK) { 599 0 stevel assert(*lstat.countp == num_ap_ids); 600 0 stevel rc = realloc_data(&buf, &n, &lstat); 601 0 stevel } 602 0 stevel 603 0 stevel return (rc); 604 0 stevel } 605 0 stevel 606 0 stevel /* 607 0 stevel * config_list 608 0 stevel */ 609 0 stevel cfga_err_t 610 0 stevel config_list( 611 0 stevel struct cfga_stat_data **ap_id_list, 612 0 stevel int *nlistp, 613 0 stevel const char *options, 614 0 stevel char **errstring) 615 0 stevel { 616 0 stevel int nstat; 617 0 stevel list_stat_t lstat = {NULL}; 618 0 stevel cfga_err_t retval = CFGA_ERROR; 619 0 stevel 620 0 stevel if (errstring != NULL) { 621 0 stevel *errstring = NULL; 622 0 stevel } 623 0 stevel 624 0 stevel nstat = 0; 625 0 stevel lstat.countp = &nstat; 626 0 stevel lstat.opts = options; 627 0 stevel lstat.errstr = errstring; 628 10923 Evan lstat.shp_errstr = NULL; 629 0 stevel /* 630 0 stevel * This is a V1 interface which can use only V1 plugins 631 0 stevel */ 632 0 stevel lstat.use_vers.v_max = lstat.use_vers.v_min = CFGA_HSL_V1; 633 0 stevel 634 0 stevel 635 0 stevel *ap_id_list = NULL; 636 0 stevel *nlistp = 0; 637 0 stevel 638 0 stevel /* 639 0 stevel * V1 interfaces don't support prefiltering, no class 640 0 stevel * specified. 641 0 stevel */ 642 0 stevel retval = list_common(&lstat, NULL); 643 0 stevel if (retval == CFGA_OK) { 644 0 stevel retval = realloc_data(ap_id_list, nlistp, &lstat); 645 0 stevel } 646 0 stevel 647 0 stevel assert((ap_id_list != NULL && *nlistp != 0) || 648 0 stevel (ap_id_list == NULL && *nlistp == 0)); 649 0 stevel 650 0 stevel if (retval == CFGA_OK && *nlistp == 0) { 651 0 stevel return (CFGA_NOTSUPP); 652 0 stevel } else { 653 0 stevel return (retval); 654 0 stevel } 655 0 stevel } 656 0 stevel 657 0 stevel 658 0 stevel /* 659 0 stevel * config_list_ext 660 0 stevel */ 661 0 stevel cfga_err_t 662 0 stevel config_list_ext( 663 0 stevel int num_ap_ids, 664 0 stevel char *const *ap_ids, 665 0 stevel struct cfga_list_data **ap_id_list, 666 0 stevel int *nlistp, 667 0 stevel const char *options, 668 0 stevel const char *listopts, 669 0 stevel char **errstring, 670 0 stevel cfga_flags_t flags) 671 0 stevel { 672 0 stevel int nstat, list, prefilter; 673 0 stevel list_stat_t lstat = {NULL}; 674 0 stevel char *class; 675 0 stevel 676 0 stevel cfga_err_t rc = CFGA_ERROR; 677 0 stevel 678 0 stevel *nlistp = 0; 679 0 stevel *ap_id_list = NULL; 680 0 stevel 681 0 stevel if (errstring != NULL) { 682 0 stevel *errstring = NULL; 683 0 stevel } 684 0 stevel 685 0 stevel if (check_flags(flags, CFGA_FLAG_LIST_ALL, errstring) != CFGA_OK) { 686 0 stevel return (CFGA_ERROR); 687 0 stevel } 688 0 stevel 689 0 stevel class = NULL; 690 0 stevel if ((rc = parse_listopt((char *)listopts, &class, errstring)) 691 0 stevel != CFGA_OK) { 692 0 stevel return (rc); 693 0 stevel } 694 0 stevel 695 0 stevel prefilter = (class == NULL) ? 0 : 1; 696 0 stevel 697 0 stevel nstat = 0; 698 0 stevel lstat.countp = &nstat; 699 0 stevel lstat.opts = options; 700 0 stevel lstat.errstr = errstring; 701 10923 Evan lstat.shp_errstr = NULL; 702 0 stevel lstat.flags = flags; 703 0 stevel /* 704 0 stevel * We support both V1 and V2 plugins through this entry 705 0 stevel * point. 706 0 stevel */ 707 0 stevel lstat.use_vers.v_min = CFGA_HSL_V1; 708 0 stevel lstat.use_vers.v_max = CFGA_HSL_V2; 709 0 stevel 710 0 stevel list = 0; 711 0 stevel if (num_ap_ids == 0 && ap_ids == NULL) { 712 0 stevel /* 713 0 stevel * discover and stat all attachment points 714 0 stevel */ 715 0 stevel list = 1; 716 0 stevel rc = list_common(&lstat, class); 717 0 stevel } else if (num_ap_ids > 0 && ap_ids != NULL) { 718 0 stevel /* 719 0 stevel * Stat specified attachment points. With dynamic expansion 720 0 stevel * more data may be returned than was specified by user. 721 0 stevel */ 722 0 stevel rc = stat_common(num_ap_ids, ap_ids, class, &lstat); 723 0 stevel } else { 724 0 stevel rc = CFGA_ERROR; 725 0 stevel } 726 0 stevel 727 0 stevel S_FREE(class); 728 0 stevel 729 0 stevel if (rc != CFGA_OK) { 730 0 stevel return (rc); 731 0 stevel } 732 0 stevel 733 0 stevel rc = realloc_data_ext(ap_id_list, nlistp, &lstat); 734 0 stevel 735 0 stevel assert((ap_id_list != NULL && *nlistp != 0) || 736 0 stevel (ap_id_list == NULL && *nlistp == 0)); 737 0 stevel 738 0 stevel /* 739 0 stevel * For the list command notify user if no attachment 740 0 stevel * point is found in the system. 741 0 stevel * 742 0 stevel */ 743 0 stevel if (list && rc == CFGA_OK && *nlistp == 0) { 744 0 stevel /* 745 0 stevel * If attachment points are being prefiltered, absence of data 746 0 stevel * does not imply that config. admin. is not 747 0 stevel * supported by the system. 748 0 stevel */ 749 0 stevel if (prefilter) { 750 0 stevel /* 751 0 stevel * Prefiltering: requested class is absent 752 0 stevel */ 753 0 stevel return (CFGA_APID_NOEXIST); 754 0 stevel } else { 755 0 stevel /* 756 0 stevel * No attachment points in system 757 0 stevel */ 758 0 stevel return (CFGA_NOTSUPP); 759 0 stevel } 760 0 stevel } else { 761 0 stevel return (rc); 762 0 stevel } 763 0 stevel } 764 0 stevel 765 0 stevel 766 0 stevel /* 767 0 stevel * config_unload_libs 768 0 stevel * 769 0 stevel * Attempts to remove all libs on the plugin list. 770 0 stevel */ 771 0 stevel void 772 0 stevel config_unload_libs() 773 0 stevel { 774 0 stevel plugin_lib_t *libp, *prev = &plugin_list, *next = NULL; 775 0 stevel 776 0 stevel /* destroy cache entries to remove refcnt agains plugins */ 777 0 stevel destroy_cache(); 778 0 stevel 779 0 stevel (void) mutex_lock(&plugin_list_lock); 780 0 stevel for (libp = plugin_list.next; libp != NULL; libp = next) { 781 0 stevel next = libp->next; 782 0 stevel (void) mutex_lock(&libp->lock); 783 0 stevel if (libp->refcnt) { 784 0 stevel (void) mutex_unlock(&libp->lock); 785 0 stevel prev = libp; 786 0 stevel continue; 787 0 stevel } 788 0 stevel (void) mutex_unlock(&libp->lock); 789 0 stevel prev->next = next; 790 0 stevel (void) dlclose(libp->handle); 791 0 stevel (void) mutex_destroy(&libp->lock); 792 0 stevel free(libp); 793 0 stevel } 794 0 stevel (void) mutex_unlock(&plugin_list_lock); 795 0 stevel } 796 0 stevel 797 0 stevel /* 798 0 stevel * config_ap_id_cmp 799 0 stevel */ 800 0 stevel int 801 0 stevel config_ap_id_cmp( 802 0 stevel const cfga_ap_log_id_t ap1, 803 0 stevel const cfga_ap_log_id_t ap2) 804 0 stevel { 805 0 stevel int ret; 806 0 stevel lib_loc_t libloc; 807 0 stevel char apstat1[CFGA_PHYS_EXT_LEN]; 808 0 stevel char apstat2[CFGA_PHYS_EXT_LEN]; 809 0 stevel char *sep1, *sep2; 810 0 stevel 811 0 stevel /* 812 0 stevel * Extract static ap_ids 813 0 stevel */ 814 0 stevel (void) strlcpy(apstat1, ap1, sizeof (apstat1)); 815 0 stevel (void) strlcpy(apstat2, ap2, sizeof (apstat2)); 816 0 stevel 817 0 stevel sep1 = GET_DYN(apstat1); 818 0 stevel sep2 = GET_DYN(apstat2); 819 0 stevel 820 0 stevel if (sep1) 821 0 stevel *sep1 = '\0'; 822 0 stevel if (sep2) 823 0 stevel *sep2 = '\0'; 824 0 stevel 825 0 stevel /* 826 0 stevel * Use the default comparator for static ap_ids 827 0 stevel */ 828 0 stevel ret = default_ap_id_cmp(apstat1, apstat2); 829 0 stevel if (ret) 830 0 stevel return (ret); 831 0 stevel 832 0 stevel /* 833 0 stevel * static components match. They belong to 834 0 stevel * the same static ap_id. Check if both are dynamic 835 0 stevel * If not, static < dynamic. 836 0 stevel */ 837 0 stevel if ((sep1 == NULL) ^ (sep2 == NULL)) 838 0 stevel return (sep1 ? 1 : -1); 839 0 stevel 840 0 stevel /* 841 0 stevel * If both are static, then ap1 = ap2 842 0 stevel */ 843 0 stevel if (sep1 == NULL) 844 0 stevel return (0); 845 0 stevel 846 0 stevel /* 847 0 stevel * Both are dynamic and belong to same static ap_id. 848 0 stevel * Use the plugin comparator 849 0 stevel */ 850 0 stevel libloc.libp = NULL; 851 0 stevel if (config_get_lib(ap1, &libloc, NULL) != CFGA_OK) { 852 0 stevel return (strncmp(sep1, sep2, CFGA_PHYS_EXT_LEN)); 853 0 stevel } 854 0 stevel 855 0 stevel ret = (*libloc.libp->cfga_ap_id_cmp_p)(ap1, ap2); 856 0 stevel 857 0 stevel rele_lib(libloc.libp); 858 0 stevel 859 0 stevel return (ret); 860 0 stevel } 861 0 stevel 862 0 stevel /* 863 0 stevel * config_strerror 864 0 stevel */ 865 0 stevel 866 0 stevel const char * 867 0 stevel config_strerror(cfga_err_t cfgerrnum) 868 0 stevel { 869 0 stevel const char *ep = NULL; 870 0 stevel 871 0 stevel if ((cfgerrnum < CFGA_OK) || (cfgerrnum > CFGA_ATTR_INVAL)) 872 0 stevel return (NULL); 873 0 stevel 874 0 stevel ep = __config_strerror(cfgerrnum); 875 0 stevel 876 0 stevel return ((ep != NULL) ? dgettext(TEXT_DOMAIN, ep) : NULL); 877 0 stevel } 878 0 stevel 879 0 stevel /* 880 0 stevel * config_help 881 0 stevel */ 882 0 stevel cfga_err_t 883 0 stevel config_help( 884 0 stevel int num_ap_ids, 885 0 stevel char *const *ap_ids, 886 0 stevel struct cfga_msg *msgp, 887 0 stevel const char *options, 888 0 stevel cfga_flags_t flags) 889 0 stevel { 890 0 stevel int i; 891 0 stevel lib_loc_t libloc; 892 0 stevel cfga_err_t retval = CFGA_OK; 893 0 stevel 894 0 stevel if (check_flags(flags, CFGA_FLAG_FORCE | CFGA_FLAG_VERBOSE, NULL) 895 0 stevel != CFGA_OK) { 896 0 stevel return (CFGA_ERROR); 897 0 stevel } 898 0 stevel 899 0 stevel if (num_ap_ids < 0) { 900 0 stevel return (CFGA_ERROR); 901 0 stevel } 902 0 stevel 903 0 stevel if (num_ap_ids > 0 && ap_ids == NULL) { 904 0 stevel return (CFGA_ERROR); 905 0 stevel } 906 0 stevel 907 0 stevel /* 908 0 stevel * operate on each ap_id 909 0 stevel */ 910 0 stevel for (i = 0; (i < num_ap_ids) && (retval == CFGA_OK); i++) { 911 0 stevel libloc.libp = NULL; 912 0 stevel if ((retval = config_get_lib(ap_ids[i], &libloc, 913 0 stevel NULL)) != CFGA_OK) { 914 0 stevel return (retval); 915 0 stevel } 916 0 stevel 917 0 stevel errno = 0; 918 0 stevel retval = (*libloc.libp->cfga_help_p)(msgp, options, flags); 919 0 stevel rele_lib(libloc.libp); 920 0 stevel } 921 0 stevel return (retval); 922 0 stevel } 923 0 stevel 924 0 stevel /* 925 0 stevel * Private support routines for the public interfaces 926 0 stevel */ 927 0 stevel 928 0 stevel static const char * 929 0 stevel __config_strerror(cfga_err_t cfgerrnum) 930 0 stevel { 931 0 stevel const char *ep = NULL; 932 0 stevel 933 0 stevel switch (cfgerrnum) { 934 0 stevel case CFGA_OK: 935 0 stevel ep = "Configuration operation succeeded"; 936 0 stevel break; 937 0 stevel case CFGA_NACK: 938 0 stevel ep = "Configuration operation cancelled"; 939 0 stevel break; 940 0 stevel case CFGA_INVAL: 941 0 stevel ep = "Configuration operation invalid"; 942 0 stevel break; 943 0 stevel case CFGA_NOTSUPP: 944 0 stevel ep = "Configuration administration not supported"; 945 0 stevel break; 946 0 stevel case CFGA_OPNOTSUPP: 947 0 stevel ep = "Configuration operation not supported"; 948 0 stevel break; 949 0 stevel case CFGA_PRIV: 950 0 stevel ep = "Insufficient privileges"; 951 0 stevel break; 952 0 stevel case CFGA_BUSY: 953 0 stevel ep = "Component system is busy, try again"; 954 0 stevel break; 955 0 stevel case CFGA_SYSTEM_BUSY: 956 0 stevel ep = "System is busy, try again"; 957 0 stevel break; 958 0 stevel case CFGA_DATA_ERROR: 959 0 stevel ep = "Data error"; 960 0 stevel break; 961 0 stevel case CFGA_LIB_ERROR: 962 0 stevel ep = "Library error"; 963 0 stevel break; 964 0 stevel case CFGA_NO_LIB: 965 0 stevel ep = "No Library found"; 966 0 stevel break; 967 0 stevel case CFGA_INSUFFICENT_CONDITION: 968 0 stevel ep = "Insufficient condition"; 969 0 stevel break; 970 0 stevel case CFGA_ERROR: 971 0 stevel ep = "Hardware specific failure"; 972 0 stevel break; 973 0 stevel case CFGA_APID_NOEXIST: 974 0 stevel ep = "Attachment point not found"; 975 0 stevel break; 976 0 stevel case CFGA_ATTR_INVAL: 977 0 stevel ep = "No attachment point with specified attributes found"; 978 0 stevel break; 979 0 stevel default: 980 0 stevel ep = NULL; 981 0 stevel break; 982 0 stevel } 983 0 stevel return (ep); 984 0 stevel } 985 0 stevel 986 0 stevel /* 987 0 stevel * listopts is a string in the getsubopt(3C) style: 988 0 stevel * name1=value1,name2=value2, 989 0 stevel */ 990 0 stevel static cfga_err_t 991 0 stevel parse_listopt(char *listopts, char **classpp, char **errstring) 992 0 stevel { 993 0 stevel char *bufp, *optp, *val = NULL; 994 0 stevel cfga_err_t rc = CFGA_ERROR; 995 0 stevel 996 0 stevel *classpp = NULL; 997 0 stevel 998 0 stevel /* 999 0 stevel * NULL is a legal value for listopts 1000 0 stevel */ 1001 0 stevel if (listopts == NULL) { 1002 0 stevel return (CFGA_OK); 1003 0 stevel } 1004 0 stevel 1005 0 stevel if ((bufp = config_calloc_check(1, strlen(listopts) + 1, errstring)) 1006 0 stevel == NULL) { 1007 0 stevel return (CFGA_LIB_ERROR); 1008 0 stevel } 1009 0 stevel (void) strcpy(bufp, listopts); 1010 0 stevel 1011 0 stevel optp = bufp; /* getsubopt() modifies its argument */ 1012 0 stevel while (*optp != '\0') { 1013 0 stevel switch (getsubopt(&optp, listopt_array, &val)) { 1014 0 stevel case LISTOPT_CLASS: 1015 0 stevel if (val == NULL || *classpp != NULL) { 1016 0 stevel rc = CFGA_ERROR; 1017 0 stevel goto out; 1018 0 stevel } 1019 0 stevel if ((*classpp = config_calloc_check(1, strlen(val) + 1, 1020 0 stevel errstring)) == NULL) { 1021 0 stevel rc = CFGA_LIB_ERROR; 1022 0 stevel goto out; 1023 0 stevel } 1024 0 stevel (void) strcpy(*classpp, val); 1025 0 stevel break; 1026 0 stevel default: 1027 0 stevel rc = CFGA_ERROR; 1028 0 stevel goto out; 1029 0 stevel } 1030 0 stevel } 1031 0 stevel 1032 0 stevel rc = CFGA_OK; 1033 0 stevel /*FALLTHRU*/ 1034 0 stevel out: 1035 0 stevel S_FREE(bufp); 1036 0 stevel if (rc != CFGA_OK) { 1037 0 stevel S_FREE(*classpp); 1038 0 stevel } 1039 0 stevel return (rc); 1040 0 stevel } 1041 0 stevel 1042 0 stevel /*ARGSUSED*/ 1043 0 stevel static cfga_err_t 1044 0 stevel null_mklog( 1045 0 stevel di_node_t node, 1046 0 stevel di_minor_t minor, 1047 0 stevel plugin_lib_t *libp, 1048 0 stevel lib_loc_t *liblocp) 1049 0 stevel { 1050 0 stevel return (CFGA_OK); 1051 0 stevel } 1052 0 stevel 1053 0 stevel static cfga_err_t 1054 0 stevel mklog_v1( 1055 0 stevel di_node_t node, 1056 0 stevel di_minor_t minor, 1057 0 stevel plugin_lib_t *libp, 1058 0 stevel lib_loc_t *liblocp) 1059 0 stevel { 1060 0 stevel const size_t len = CFGA_AP_LOG_ID_LEN; 1061 0 stevel 1062 0 stevel assert(len <= sizeof (liblocp->ap_logical)); 1063 0 stevel 1064 0 stevel if (libp->plugin_vers != CFGA_HSL_V1) { 1065 0 stevel return (CFGA_LIB_ERROR); 1066 0 stevel } 1067 0 stevel 1068 0 stevel return (mklog_common(node, minor, liblocp, len)); 1069 0 stevel } 1070 0 stevel 1071 0 stevel 1072 0 stevel /* 1073 0 stevel * Obtain the devlink from a /devices path 1074 0 stevel */ 1075 0 stevel static int 1076 0 stevel get_link(di_devlink_t devlink, void *arg) 1077 0 stevel { 1078 0 stevel char *linkp = (char *)arg; 1079 0 stevel 1080 0 stevel (void) snprintf(linkp, CFGA_LOG_EXT_LEN, "%s", 1081 0 stevel di_devlink_path(devlink)); 1082 0 stevel return (DI_WALK_TERMINATE); 1083 0 stevel } 1084 0 stevel 1085 0 stevel static cfga_err_t 1086 0 stevel mklog_v2( 1087 0 stevel di_node_t node, 1088 0 stevel di_minor_t minor, 1089 0 stevel plugin_lib_t *libp, 1090 0 stevel lib_loc_t *liblocp) 1091 0 stevel { 1092 0 stevel const size_t len = CFGA_LOG_EXT_LEN; 1093 0 stevel di_devlink_handle_t hdl; 1094 0 stevel 1095 0 stevel assert(len <= sizeof (liblocp->ap_logical)); 1096 0 stevel 1097 0 stevel if (libp->plugin_vers != CFGA_HSL_V2) { 1098 0 stevel return (CFGA_LIB_ERROR); 1099 0 stevel } 1100 0 stevel 1101 0 stevel /* open devlink database */ 1102 0 stevel if ((hdl = di_devlink_init(NULL, 0)) == NULL) { 1103 0 stevel return (CFGA_LIB_ERROR); 1104 0 stevel } 1105 0 stevel 1106 0 stevel liblocp->ap_logical[0] = '\0'; 1107 0 stevel (void) di_devlink_walk(hdl, NULL, 1108 0 stevel liblocp->ap_physical + strlen(DEVICES_DIR), 1109 0 stevel DI_PRIMARY_LINK, (void *)liblocp->ap_logical, get_link); 1110 0 stevel 1111 0 stevel (void) di_devlink_fini(&hdl); 1112 0 stevel 1113 0 stevel if (liblocp->ap_logical[0] != '\0') 1114 0 stevel return (CFGA_OK); 1115 0 stevel return (mklog_common(node, minor, liblocp, len)); 1116 0 stevel } 1117 0 stevel 1118 0 stevel /* 1119 0 stevel * mklog_common - make a logical name from the driver and instance 1120 0 stevel */ 1121 0 stevel static cfga_err_t 1122 0 stevel mklog_common( 1123 0 stevel di_node_t node, 1124 0 stevel di_minor_t minor, 1125 0 stevel lib_loc_t *libloc_p, 1126 0 stevel size_t len) 1127 0 stevel { 1128 0 stevel int inst; 1129 0 stevel char *drv, *minor_name; 1130 0 stevel 1131 0 stevel drv = di_driver_name(node); 1132 0 stevel inst = di_instance(node); 1133 0 stevel minor_name = di_minor_name(minor); 1134 0 stevel 1135 0 stevel errno = 0; 1136 0 stevel if (drv != NULL && inst != -1 && minor_name != NULL && 1137 0 stevel snprintf(libloc_p->ap_logical, len, "%s%d:%s", drv, inst, 1138 0 stevel minor_name) < len) { /* snprintf returns strlen */ 1139 0 stevel return (CFGA_OK); 1140 0 stevel } 1141 0 stevel 1142 0 stevel return (CFGA_LIB_ERROR); 1143 0 stevel } 1144 0 stevel 1145 0 stevel /* 1146 10923 Evan * mklog_common - make a logical name from the driver and instance 1147 10923 Evan */ 1148 10923 Evan /*ARGSUSED*/ 1149 10923 Evan static cfga_err_t 1150 10923 Evan mklog_hp( 1151 10923 Evan di_node_t node, 1152 10923 Evan di_hp_t hp, 1153 10923 Evan plugin_lib_t *libp, 1154 10923 Evan lib_loc_t *liblocp) 1155 10923 Evan { 1156 10923 Evan const size_t len = CFGA_LOG_EXT_LEN; 1157 10923 Evan int inst; 1158 10923 Evan char *drv, *hp_name; 1159 10923 Evan 1160 10923 Evan drv = di_driver_name(node); 1161 10923 Evan inst = di_instance(node); 1162 10923 Evan hp_name = di_hp_name(hp); 1163 10923 Evan 1164 10923 Evan errno = 0; 1165 10923 Evan if (drv != NULL && inst != -1 && hp_name != NULL && 1166 10923 Evan snprintf(liblocp->ap_logical, len, "%s%d:%s", drv, inst, 1167 10923 Evan hp_name) < len) { /* snprintf returns strlen */ 1168 10923 Evan return (CFGA_OK); 1169 10923 Evan } 1170 10923 Evan 1171 10923 Evan return (CFGA_LIB_ERROR); 1172 10923 Evan } 1173 10923 Evan 1174 10923 Evan /* 1175 0 stevel * resolve_lib_ref - relocate to use plugin lib 1176 0 stevel */ 1177 0 stevel static cfga_err_t 1178 0 stevel resolve_lib_ref( 1179 0 stevel plugin_lib_t *libp, 1180 0 stevel lib_loc_t *libloc_p) 1181 0 stevel { 1182 0 stevel void *sym; 1183 0 stevel void *libhdlp = libp->handle; 1184 0 stevel int plug_vers; 1185 0 stevel 1186 0 stevel if ((sym = dlsym(libhdlp, "cfga_version")) == NULL) { 1187 0 stevel /* 1188 0 stevel * Version symbol not defined, must be the first version 1189 0 stevel */ 1190 0 stevel plug_vers = CFGA_HSL_V1; 1191 0 stevel } else { 1192 0 stevel plug_vers = *((int *)sym); 1193 0 stevel } 1194 0 stevel 1195 0 stevel /* 1196 0 stevel * Check if plugin version matches request. 1197 0 stevel */ 1198 0 stevel if (!compat_plugin(&libloc_p->vers_req, plug_vers)) { 1199 0 stevel return (CFGA_NO_LIB); 1200 0 stevel } 1201 0 stevel 1202 0 stevel /* 1203 0 stevel * Record the plugin version and setup version dependant routines 1204 0 stevel */ 1205 0 stevel assert(plug_vers < VERS_ARRAY_SZ); 1206 0 stevel libp->plugin_vers = plug_vers; 1207 0 stevel libp->vers_ops = &cfga_vers_ops[plug_vers]; 1208 0 stevel 1209 0 stevel /* resolve symbols common to all versions */ 1210 0 stevel if ((sym = dlsym(libhdlp, "cfga_change_state")) == NULL) { 1211 0 stevel perror("dlsym: cfga_change_state"); 1212 0 stevel return (CFGA_LIB_ERROR); 1213 0 stevel } else 1214 0 stevel libp->cfga_change_state_p = (cfga_err_t (*)(cfga_cmd_t, 1215 0 stevel const char *, const char *, struct cfga_confirm *, 1216 0 stevel struct cfga_msg *, char **, cfga_flags_t)) sym; 1217 0 stevel 1218 0 stevel if ((sym = dlsym(libhdlp, "cfga_private_func")) == NULL) { 1219 0 stevel perror("dlsym: cfga_private_func"); 1220 0 stevel return (CFGA_LIB_ERROR); 1221 0 stevel } else 1222 0 stevel libp->cfga_private_func_p = (cfga_err_t (*)(const char *, 1223 0 stevel const char *, const char *, struct cfga_confirm *, 1224 0 stevel struct cfga_msg *, char **, cfga_flags_t))sym; 1225 0 stevel 1226 0 stevel if ((sym = dlsym(libhdlp, "cfga_test")) == NULL) { 1227 0 stevel perror("dlsym: cfga_test"); 1228 0 stevel return (CFGA_LIB_ERROR); 1229 0 stevel } else 1230 0 stevel libp->cfga_test_p = (cfga_err_t (*)(const char *, const char *, 1231 0 stevel struct cfga_msg *, char **, cfga_flags_t))sym; 1232 0 stevel 1233 0 stevel if ((sym = dlsym(libhdlp, "cfga_help")) == NULL) { 1234 0 stevel perror("dlsym: cfga_help"); 1235 0 stevel return (CFGA_LIB_ERROR); 1236 0 stevel } else 1237 0 stevel libp->cfga_help_p = (cfga_err_t (*)(struct cfga_msg *, 1238 0 stevel const char *, cfga_flags_t))sym; 1239 0 stevel 1240 0 stevel if ((sym = dlsym(libhdlp, "cfga_ap_id_cmp")) == NULL) { 1241 0 stevel libp->cfga_ap_id_cmp_p = default_ap_id_cmp; 1242 0 stevel } else 1243 0 stevel libp->cfga_ap_id_cmp_p = (int (*)(const 1244 0 stevel cfga_ap_log_id_t, const cfga_ap_log_id_t))sym; 1245 0 stevel 1246 0 stevel /* Resolve version specific symbols */ 1247 0 stevel return (libp->vers_ops->resolve_lib(libp)); 1248 0 stevel } 1249 0 stevel 1250 0 stevel /*ARGSUSED*/ 1251 0 stevel static cfga_err_t 1252 0 stevel null_resolve(plugin_lib_t *libp) 1253 0 stevel { 1254 0 stevel return (CFGA_OK); 1255 0 stevel } 1256 0 stevel 1257 0 stevel static cfga_err_t 1258 0 stevel resolve_v1(plugin_lib_t *libp) 1259 0 stevel { 1260 0 stevel void *sym, *libhdlp = libp->handle; 1261 0 stevel 1262 0 stevel 1263 0 stevel if (libp->plugin_vers != CFGA_HSL_V1) { 1264 0 stevel return (CFGA_NO_LIB); 1265 0 stevel } 1266 0 stevel 1267 0 stevel if ((sym = dlsym(libhdlp, "cfga_stat")) == NULL) { 1268 0 stevel perror("dlsym: cfga_stat"); 1269 0 stevel return (CFGA_LIB_ERROR); 1270 0 stevel } else 1271 0 stevel libp->cfga_stat_p = (cfga_err_t (*)(const char *, 1272 0 stevel struct cfga_stat_data *, const char *, 1273 0 stevel char **))sym; 1274 0 stevel 1275 0 stevel if ((sym = dlsym(libhdlp, "cfga_list")) == NULL) { 1276 0 stevel perror("dlsym: cfga_list"); 1277 0 stevel return (CFGA_LIB_ERROR); 1278 0 stevel } else 1279 0 stevel libp->cfga_list_p = (cfga_err_t (*)(struct cfga_stat_data **, 1280 0 stevel int *, const char *, char **))sym; 1281 0 stevel 1282 0 stevel return (CFGA_OK); 1283 0 stevel } 1284 0 stevel 1285 0 stevel static cfga_err_t 1286 0 stevel resolve_v2(plugin_lib_t *libp) 1287 0 stevel { 1288 0 stevel void *sym; 1289 0 stevel 1290 0 stevel 1291 0 stevel if (libp->plugin_vers != CFGA_HSL_V2) { 1292 0 stevel return (CFGA_NO_LIB); 1293 0 stevel } 1294 0 stevel 1295 0 stevel if ((sym = dlsym(libp->handle, "cfga_list_ext")) == NULL) { 1296 0 stevel perror("dlsym: cfga_list_ext"); 1297 0 stevel return (CFGA_LIB_ERROR); 1298 0 stevel } else { 1299 0 stevel libp->cfga_list_ext_p = (cfga_err_t (*)(const char *, 1300 0 stevel struct cfga_list_data **, int *, const char *, 1301 0 stevel const char *, char **, cfga_flags_t))sym; 1302 0 stevel return (CFGA_OK); 1303 0 stevel } 1304 0 stevel } 1305 0 stevel 1306 0 stevel /* 1307 0 stevel * config_calloc_check - perform allocation, check result and 1308 0 stevel * set error string 1309 0 stevel */ 1310 0 stevel static void * 1311 0 stevel config_calloc_check( 1312 0 stevel size_t nelem, 1313 0 stevel size_t elsize, 1314 0 stevel char **errstring) 1315 0 stevel { 1316 0 stevel void *p; 1317 0 stevel 1318 0 stevel p = calloc(nelem, elsize); 1319 0 stevel if (p == NULL) { 1320 0 stevel config_err(0, ALLOC_FAILED, errstring); 1321 0 stevel } 1322 0 stevel 1323 0 stevel return (p); 1324 0 stevel } 1325 0 stevel 1326 0 stevel 1327 0 stevel /* 1328 0 stevel * config_get_lib - given an ap_id find the library name 1329 0 stevel * If successful, the plugin library is held. 1330 0 stevel */ 1331 0 stevel static cfga_err_t 1332 0 stevel config_get_lib( 1333 0 stevel const char *ap_id, 1334 0 stevel lib_loc_t *lib_loc_p, 1335 0 stevel char **errstring) 1336 0 stevel { 1337 0 stevel char *dyncomp, path[PATH_MAX]; 1338 0 stevel char *apdup; 1339 0 stevel cfga_ap_types_t type = UNKNOWN_AP; 1340 0 stevel cfga_err_t ret = CFGA_ERROR; 1341 0 stevel 1342 0 stevel if (ap_id == NULL) { 1343 0 stevel config_err(0, INVALID_ARGS, errstring); 1344 0 stevel return (ret); 1345 0 stevel } 1346 0 stevel 1347 0 stevel lib_loc_p->libp = NULL; 1348 0 stevel 1349 0 stevel if ((apdup = config_calloc_check(1, strlen(ap_id) + 1, errstring)) 1350 0 stevel == NULL) { 1351 0 stevel return (CFGA_LIB_ERROR); 1352 0 stevel } 1353 0 stevel (void) strcpy(apdup, ap_id); 1354 0 stevel 1355 0 stevel /* 1356 0 stevel * Separate into base and dynamic components 1357 0 stevel */ 1358 0 stevel if ((ret = split_apid(apdup, &dyncomp, errstring)) != CFGA_OK) { 1359 0 stevel goto out; 1360 0 stevel } 1361 0 stevel 1362 0 stevel /* 1363 0 stevel * No upper limit on version 1364 0 stevel */ 1365 0 stevel lib_loc_p->vers_req.v_max = CFGA_HSL_VERS; 1366 0 stevel if (dyncomp != NULL) { 1367 0 stevel /* 1368 0 stevel * We need atleast version 2 of the plug-in library 1369 0 stevel * interface since the ap_id has a dynamic component. 1370 0 stevel */ 1371 0 stevel 1372 0 stevel lib_loc_p->vers_req.v_min = CFGA_HSL_V2; 1373 0 stevel } else { 1374 0 stevel lib_loc_p->vers_req.v_min = CFGA_HSL_V1; 1375 0 stevel } 1376 0 stevel 1377 0 stevel /* 1378 0 stevel * If the ap_id is a devlink in CFGA_DEV_DIR, follow link 1379 0 stevel * to get the physical ap_id. 1380 0 stevel */ 1381 0 stevel if ((type = find_arg_type(apdup)) == LOGICAL_LINK_AP) { 1382 0 stevel (void) snprintf(lib_loc_p->ap_base, sizeof (lib_loc_p->ap_base), 1383 0 stevel "%s%s", CFGA_DEV_DIR SLASH, apdup); 1384 0 stevel } 1385 0 stevel 1386 0 stevel path[sizeof (path) - 1] = '\0'; 1387 0 stevel if (type == LOGICAL_LINK_AP && realpath(lib_loc_p->ap_base, path) 1388 0 stevel != NULL) { 1389 0 stevel (void) snprintf(lib_loc_p->ap_base, sizeof (lib_loc_p->ap_base), 1390 0 stevel "%s", path); 1391 0 stevel } else { 1392 0 stevel (void) snprintf(lib_loc_p->ap_base, sizeof (lib_loc_p->ap_base), 1393 0 stevel "%s", apdup); 1394 0 stevel } 1395 0 stevel 1396 0 stevel 1397 0 stevel /* 1398 0 stevel * find and load the library 1399 0 stevel * The base component of the ap_id is used to locate the plug-in 1400 10923 Evan * 1401 10923 Evan * NOTE that PCIE/PCISHPC connectors also have minor nodes & 1402 10923 Evan * dev links created for now. 1403 0 stevel */ 1404 0 stevel if ((type = find_arg_type(lib_loc_p->ap_base)) == PHYSICAL_AP) { 1405 0 stevel /* 1406 0 stevel * physical ap_id: Use ap_base as root for tree walk 1407 0 stevel * A link based apid (logical) will resolve to a physical 1408 0 stevel * ap_id. 1409 0 stevel */ 1410 0 stevel ret = find_ap_common(lib_loc_p, lib_loc_p->ap_base, 1411 10923 Evan check_ap_phys, check_ap_phys_hp, errstring); 1412 0 stevel } else if ((type == LOGICAL_DRV_AP) || 1413 0 stevel (type == AP_TYPE && dyncomp == NULL)) { 1414 0 stevel /* 1415 0 stevel * logical ap_id or ap_type: Use "/" as root for tree walk 1416 0 stevel * Note: an aptype cannot have a dynamic component 1417 0 stevel */ 1418 10923 Evan ret = find_ap_common(lib_loc_p, "/", check_ap, 1419 10923 Evan check_ap_hp, errstring); 1420 0 stevel } else { 1421 0 stevel ret = CFGA_APID_NOEXIST; 1422 0 stevel } 1423 0 stevel 1424 0 stevel if (ret == CFGA_OK) { 1425 0 stevel #ifndef NDEBUG 1426 0 stevel /* 1427 0 stevel * variables used by assert() only which is disabled 1428 0 stevel * by defining NDEBUG (see top of this file) 1429 0 stevel */ 1430 0 stevel plugin_lib_t *libp; 1431 0 stevel 1432 0 stevel libp = lib_loc_p->libp; 1433 0 stevel #endif /* NDEBUG */ 1434 0 stevel 1435 0 stevel assert(strcmp(libp->libpath, lib_loc_p->pathname) == 0); 1436 0 stevel assert(VALID_HSL_VERS(libp->plugin_vers)); 1437 0 stevel 1438 0 stevel /* 1439 0 stevel * If a dynamic component was present, v1 plug-ins are not 1440 0 stevel * acceptable. 1441 0 stevel */ 1442 0 stevel assert(dyncomp == NULL || libp->plugin_vers >= CFGA_HSL_V2); 1443 0 stevel 1444 0 stevel /* 1445 0 stevel * ap_physical is passed to plugins as their ap_id argument. 1446 0 stevel * Append dynamic component if any. 1447 0 stevel */ 1448 0 stevel append_dyn(lib_loc_p->ap_physical, dyncomp, 1449 0 stevel sizeof (lib_loc_p->ap_physical)); 1450 0 stevel } 1451 0 stevel 1452 0 stevel /* cleanup */ 1453 0 stevel lib_loc_p->vers_req.v_min = INVALID_VERSION; 1454 0 stevel lib_loc_p->vers_req.v_max = INVALID_VERSION; 1455 0 stevel *lib_loc_p->ap_base = '\0'; 1456 0 stevel 1457 0 stevel /*FALLTHRU*/ 1458 0 stevel out: 1459 0 stevel S_FREE(apdup); 1460 0 stevel S_FREE(dyncomp); 1461 0 stevel if (ret != CFGA_OK) { 1462 0 stevel lib_loc_p->libp = NULL; 1463 0 stevel } 1464 0 stevel 1465 0 stevel assert(ret != CFGA_OK || lib_loc_p->libp != NULL); 1466 0 stevel 1467 0 stevel return (ret); 1468 0 stevel } 1469 0 stevel 1470 10923 Evan /* load_lib - load library for non-SHP attachment point node */ 1471 0 stevel static cfga_err_t 1472 0 stevel load_lib( 1473 0 stevel di_node_t node, 1474 0 stevel di_minor_t minor, 1475 0 stevel lib_loc_t *libloc_p) 1476 0 stevel { 1477 10923 Evan return (load_lib_impl(node, minor, NULL, libloc_p)); 1478 10923 Evan } 1479 10923 Evan 1480 10923 Evan /* load_lib_hp - load library for SHP attachment point node */ 1481 10923 Evan static cfga_err_t 1482 10923 Evan load_lib_hp( 1483 10923 Evan di_node_t node, 1484 10923 Evan di_hp_t hp, 1485 10923 Evan lib_loc_t *libloc_p) 1486 10923 Evan { 1487 10923 Evan return (load_lib_impl(node, NULL, hp, libloc_p)); 1488 10923 Evan } 1489 10923 Evan 1490 10923 Evan /* 1491 10923 Evan * load_lib_impl - Given a library pathname, create a entry for it 1492 10923 Evan * in the library list, * if one does not already exist, and read 1493 10923 Evan * lock it to keep it there. 1494 10923 Evan */ 1495 10923 Evan static cfga_err_t 1496 10923 Evan load_lib_impl( 1497 10923 Evan di_node_t node, 1498 10923 Evan di_minor_t minor, 1499 10923 Evan di_hp_t hp, 1500 10923 Evan lib_loc_t *libloc_p) 1501 10923 Evan { 1502 0 stevel plugin_lib_t *libp, *list_libp; 1503 0 stevel char *devfs_path; 1504 10923 Evan char *name; 1505 10923 Evan 1506 10923 Evan if (minor != DI_MINOR_NIL && hp != DI_HP_NIL) 1507 10923 Evan return (CFGA_LIB_ERROR); 1508 10923 Evan 1509 10923 Evan if (minor != DI_MINOR_NIL) 1510 10923 Evan name = di_minor_name(minor); 1511 10923 Evan else 1512 10923 Evan name = di_hp_name(hp); 1513 0 stevel 1514 0 stevel /* 1515 0 stevel * lock the library list 1516 0 stevel */ 1517 0 stevel (void) mutex_lock(&plugin_list_lock); 1518 0 stevel 1519 0 stevel /* 1520 0 stevel * see if lib exist in list, if not, allocate a new one 1521 0 stevel */ 1522 0 stevel list_libp = lib_in_list(libloc_p->pathname); 1523 0 stevel if (list_libp != NULL) { 1524 0 stevel hold_lib(list_libp); 1525 0 stevel (void) mutex_unlock(&plugin_list_lock); 1526 0 stevel 1527 0 stevel /* fill in logical and physical name in libloc_p */ 1528 0 stevel libloc_p->libp = libp = list_libp; 1529 10923 Evan if (minor != DI_MINOR_NIL) { 1530 10923 Evan if (libp->vers_ops->mklog(node, minor, libp, libloc_p) 1531 10923 Evan != CFGA_OK) { 1532 10923 Evan rele_lib(list_libp); 1533 10923 Evan return (CFGA_LIB_ERROR); 1534 10923 Evan } 1535 10923 Evan } else { 1536 10923 Evan if (mklog_hp(node, hp, libp, libloc_p) != CFGA_OK) { 1537 10923 Evan rele_lib(list_libp); 1538 10923 Evan return (CFGA_LIB_ERROR); 1539 10923 Evan } 1540 0 stevel } 1541 0 stevel 1542 0 stevel devfs_path = di_devfs_path(node); 1543 0 stevel (void) snprintf(libloc_p->ap_physical, MAXPATHLEN, "%s%s:%s", 1544 10923 Evan DEVICES_DIR, devfs_path, name); 1545 0 stevel di_devfs_path_free(devfs_path); 1546 0 stevel 1547 0 stevel return (CFGA_OK); 1548 0 stevel } 1549 0 stevel 1550 0 stevel /* allocate a new plugin_lib_t structure */ 1551 0 stevel libp = config_calloc_check(1, sizeof (plugin_lib_t), NULL); 1552 0 stevel if (libp == NULL) { 1553 0 stevel (void) mutex_unlock(&plugin_list_lock); 1554 0 stevel return (CFGA_LIB_ERROR); 1555 0 stevel } 1556 0 stevel 1557 0 stevel (void) snprintf(libp->libpath, sizeof (libp->libpath), "%s", 1558 0 stevel libloc_p->pathname); 1559 0 stevel 1560 0 stevel /* 1561 0 stevel * ensure that the lib is open and linked in 1562 0 stevel */ 1563 0 stevel libp->handle = dlopen(libp->libpath, RTLD_NOW); 1564 0 stevel if (libp->handle == NULL) { 1565 0 stevel (void) mutex_unlock(&plugin_list_lock); 1566 0 stevel free(libp); 1567 0 stevel return (CFGA_NO_LIB); 1568 0 stevel } 1569 0 stevel 1570 10923 Evan if (minor != DI_MINOR_NIL) { 1571 10923 Evan if (resolve_lib_ref(libp, libloc_p) != CFGA_OK || 1572 10923 Evan libp->vers_ops->mklog(node, minor, libp, libloc_p) 1573 10923 Evan != CFGA_OK) { 1574 10923 Evan (void) mutex_unlock(&plugin_list_lock); 1575 10923 Evan (void) dlclose(libp->handle); 1576 10923 Evan free(libp); 1577 10923 Evan return (CFGA_NO_LIB); 1578 10923 Evan } 1579 10923 Evan } else { 1580 10923 Evan if (resolve_lib_ref(libp, libloc_p) != CFGA_OK || 1581 10923 Evan mklog_hp(node, hp, libp, libloc_p) != CFGA_OK) { 1582 10923 Evan (void) mutex_unlock(&plugin_list_lock); 1583 10923 Evan (void) dlclose(libp->handle); 1584 10923 Evan free(libp); 1585 10923 Evan return (CFGA_NO_LIB); 1586 10923 Evan } 1587 0 stevel } 1588 0 stevel 1589 0 stevel /* 1590 0 stevel * link in new entry to the end of list 1591 0 stevel */ 1592 0 stevel list_libp = &plugin_list; 1593 0 stevel while (list_libp->next != NULL) 1594 0 stevel list_libp = list_libp->next; 1595 0 stevel libp->next = list_libp->next; 1596 0 stevel list_libp->next = libp; 1597 0 stevel 1598 0 stevel /* Initialize refcnt to 1 */ 1599 0 stevel libp->refcnt = 1; 1600 0 stevel (void) mutex_init(&libp->lock, USYNC_THREAD, NULL); 1601 0 stevel 1602 0 stevel (void) mutex_unlock(&plugin_list_lock); 1603 0 stevel 1604 0 stevel /* 1605 0 stevel * record libp and physical node name in the libloc struct 1606 0 stevel */ 1607 0 stevel libloc_p->libp = libp; 1608 0 stevel devfs_path = di_devfs_path(node); 1609 0 stevel (void) snprintf(libloc_p->ap_physical, MAXPATHLEN, "%s%s:%s", 1610 10923 Evan DEVICES_DIR, devfs_path, name); 1611 0 stevel di_devfs_path_free(devfs_path); 1612 0 stevel 1613 0 stevel return (CFGA_OK); 1614 0 stevel } 1615 0 stevel 1616 0 stevel 1617 0 stevel #define NUM_LIB_NAMES 2 1618 0 stevel 1619 0 stevel /* 1620 10923 Evan * find_lib - find library for non-SHP attachment point node 1621 0 stevel */ 1622 0 stevel static cfga_err_t 1623 0 stevel find_lib( 1624 0 stevel di_node_t node, 1625 0 stevel di_minor_t minor, 1626 0 stevel lib_loc_t *libloc_p) 1627 0 stevel { 1628 0 stevel char name[NUM_LIB_NAMES][MAXPATHLEN]; 1629 0 stevel char *class = NULL, *drv = NULL; 1630 10923 Evan int i; 1631 0 stevel 1632 0 stevel 1633 0 stevel /* Make sure pathname and class is null if we fail */ 1634 10923 Evan *libloc_p->ap_class = *libloc_p->pathname = '\0'; 1635 0 stevel 1636 0 stevel /* 1637 0 stevel * Initialize possible library tags. 1638 0 stevel */ 1639 0 stevel 1640 0 stevel drv = di_driver_name(node); 1641 0 stevel class = get_class(minor); 1642 0 stevel 1643 0 stevel if (drv == NULL || class == NULL) { 1644 0 stevel return (CFGA_LIB_ERROR); 1645 0 stevel } 1646 0 stevel 1647 0 stevel i = 0; 1648 0 stevel (void) snprintf(&name[i++][0], sizeof (name[0]), "%s", drv); 1649 0 stevel (void) snprintf(&name[i++][0], sizeof (name[0]), "%s", class); 1650 0 stevel 1651 0 stevel /* 1652 0 stevel * Cycle through the array of names to find the library. 1653 0 stevel */ 1654 0 stevel for (i = 0; i < NUM_LIB_NAMES; i++) { 1655 0 stevel 1656 0 stevel /* Attachment points may not have a class (i.e. are generic) */ 1657 0 stevel if (name[i][0] == '\0') { 1658 0 stevel continue; 1659 1957 dnielsen } 1660 1957 dnielsen 1661 10923 Evan if (find_lib_impl(name[i], libloc_p) == CFGA_OK) 1662 10923 Evan goto found; 1663 10923 Evan } 1664 1957 dnielsen 1665 10923 Evan return (CFGA_NO_LIB); 1666 10923 Evan 1667 10923 Evan found: 1668 10923 Evan 1669 10923 Evan /* Record class name (if any) */ 1670 10923 Evan (void) snprintf(libloc_p->ap_class, sizeof (libloc_p->ap_class), "%s", 1671 10923 Evan class); 1672 10923 Evan 1673 10923 Evan return (CFGA_OK); 1674 10923 Evan } 1675 10923 Evan 1676 10923 Evan /* 1677 10923 Evan * find_lib_hp - find library for SHP attachment point 1678 10923 Evan */ 1679 10923 Evan /*ARGSUSED*/ 1680 10923 Evan static cfga_err_t 1681 10923 Evan find_lib_hp( 1682 10923 Evan di_node_t node, 1683 10923 Evan di_hp_t hp, 1684 10923 Evan lib_loc_t *libloc_p) 1685 10923 Evan { 1686 10923 Evan char name[MAXPATHLEN]; 1687 10923 Evan char *class = NULL; 1688 10923 Evan 1689 10923 Evan 1690 10923 Evan /* Make sure pathname and class is null if we fail */ 1691 10923 Evan *libloc_p->ap_class = *libloc_p->pathname = '\0'; 1692 10923 Evan 1693 10923 Evan /* 1694 10923 Evan * Initialize possible library tags. 1695 10923 Evan * 1696 10923 Evan * Only support PCI class for now, this will need to be 1697 10923 Evan * changed as other plugins are migrated to SHP plugin. 1698 10923 Evan */ 1699 10923 Evan class = "pci"; 1700 10923 Evan #if 0 1701 10923 Evan /* 1702 10923 Evan * No type check for now as PCI is the only class SHP plugin 1703 10923 Evan * supports. In the future we'll need to enable the type check 1704 10923 Evan * and set class accordingly, when non PCI plugins are migrated 1705 10923 Evan * to SHP. In that case we'll probably need to add an additional 1706 10923 Evan * interface between libcfgadm and the plugins, and SHP plugin will 1707 10923 Evan * implement this interface which will translate the bus specific 1708 10923 Evan * strings to standard classes that libcfgadm can recognize, for 1709 10923 Evan * all the buses it supports, e.g. for pci/pcie it will translate 1710 10923 Evan * PCIE_NATIVE_HP_TYPE to string "pci". We'll also need to bump up 1711 10923 Evan * SHP plugin version to 3 to use the new interface. 1712 10923 Evan */ 1713 10923 Evan class = di_hp_type(hp); 1714 10923 Evan if ((strcmp(class, PCIE_NATIVE_HP_TYPE) == 0) || 1715 10923 Evan (strcmp(class, PCIE_ACPI_HP_TYPE) == 0) || 1716 10923 Evan (strcmp(class, PCIE_PCI_HP_TYPE) == 0)) { 1717 10923 Evan class = "pci"; 1718 10923 Evan } else { 1719 10923 Evan goto fail; 1720 10923 Evan } 1721 10923 Evan #endif 1722 10923 Evan (void) snprintf(&name[0], sizeof (name), "%s", "shp"); 1723 10923 Evan 1724 10923 Evan if (find_lib_impl(name, libloc_p) == CFGA_OK) 1725 10923 Evan goto found; 1726 10923 Evan fail: 1727 10923 Evan return (CFGA_NO_LIB); 1728 10923 Evan 1729 10923 Evan found: 1730 10923 Evan 1731 10923 Evan /* Record class name (if any) */ 1732 10923 Evan (void) snprintf(libloc_p->ap_class, sizeof (libloc_p->ap_class), "%s", 1733 10923 Evan class); 1734 10923 Evan 1735 10923 Evan return (CFGA_OK); 1736 10923 Evan } 1737 10923 Evan 1738 10923 Evan /* 1739 10923 Evan * find_lib_impl - Given an attachment point node find it's library 1740 10923 Evan */ 1741 10923 Evan static cfga_err_t 1742 10923 Evan find_lib_impl( 1743 10923 Evan char *name, 1744 10923 Evan lib_loc_t *libloc_p) 1745 10923 Evan { 1746 10923 Evan char lib[MAXPATHLEN]; 1747 10923 Evan struct stat lib_stat; 1748 10923 Evan void *dlhandle = NULL; 1749 10923 Evan static char plat_name[SYSINFO_LENGTH]; 1750 10923 Evan static char machine_name[SYSINFO_LENGTH]; 1751 10923 Evan static char arch_name[SYSINFO_LENGTH]; 1752 10923 Evan 1753 10923 Evan /* 1754 10923 Evan * Initialize machine name and arch name 1755 10923 Evan */ 1756 10923 Evan if (strncmp("", machine_name, MAXPATHLEN) == 0) { 1757 10923 Evan if (sysinfo(SI_PLATFORM, plat_name, SYSINFO_LENGTH) == -1) { 1758 10923 Evan return (CFGA_ERROR); 1759 0 stevel } 1760 10923 Evan if (sysinfo(SI_ARCHITECTURE, arch_name, SYSINFO_LENGTH) == -1) { 1761 10923 Evan return (CFGA_ERROR); 1762 0 stevel } 1763 10923 Evan if (sysinfo(SI_MACHINE, machine_name, SYSINFO_LENGTH) == -1) { 1764 10923 Evan return (CFGA_ERROR); 1765 0 stevel } 1766 0 stevel } 1767 0 stevel 1768 10923 Evan /* 1769 10923 Evan * Try path based upon platform name 1770 10923 Evan */ 1771 10923 Evan (void) snprintf(lib, sizeof (lib), "%s%s%s%s%s", 1772 10923 Evan LIB_PATH_BASE1, plat_name, LIB_PATH_MIDDLE, 1773 10923 Evan name, LIB_PATH_TAIL); 1774 0 stevel 1775 10923 Evan if (stat(lib, &lib_stat) == 0) { 1776 10923 Evan /* file exists, is it a lib */ 1777 10923 Evan dlhandle = dlopen(lib, RTLD_LAZY); 1778 10923 Evan if (dlhandle != NULL) { 1779 10923 Evan goto found; 1780 10923 Evan } 1781 10923 Evan } 1782 10923 Evan 1783 10923 Evan /* 1784 10923 Evan * Try path based upon machine name 1785 10923 Evan */ 1786 10923 Evan (void) snprintf(lib, sizeof (lib), "%s%s%s%s%s", 1787 10923 Evan LIB_PATH_BASE1, machine_name, LIB_PATH_MIDDLE, 1788 10923 Evan name, LIB_PATH_TAIL); 1789 10923 Evan 1790 10923 Evan 1791 10923 Evan if (stat(lib, &lib_stat) == 0) { 1792 10923 Evan /* file exists, is it a lib */ 1793 10923 Evan dlhandle = dlopen(lib, RTLD_LAZY); 1794 10923 Evan if (dlhandle != NULL) { 1795 10923 Evan goto found; 1796 10923 Evan } 1797 10923 Evan } 1798 10923 Evan 1799 10923 Evan /* 1800 10923 Evan * Try path based upon arch name 1801 10923 Evan */ 1802 10923 Evan (void) snprintf(lib, sizeof (lib), "%s%s%s%s%s", 1803 10923 Evan LIB_PATH_BASE1, arch_name, LIB_PATH_MIDDLE, 1804 10923 Evan name, LIB_PATH_TAIL); 1805 10923 Evan 1806 10923 Evan if (stat(lib, &lib_stat) == 0) { 1807 10923 Evan /* file exists, is it a lib */ 1808 10923 Evan dlhandle = dlopen(lib, RTLD_LAZY); 1809 10923 Evan if (dlhandle != NULL) { 1810 10923 Evan goto found; 1811 10923 Evan } 1812 10923 Evan 1813 10923 Evan } 1814 10923 Evan 1815 10923 Evan /* 1816 10923 Evan * Try generic location 1817 10923 Evan */ 1818 10923 Evan (void) snprintf(lib, sizeof (lib), "%s%s%s%s", 1819 10923 Evan LIB_PATH_BASE2, LIB_PATH_MIDDLE, name, LIB_PATH_TAIL); 1820 10923 Evan 1821 10923 Evan if (stat(lib, &lib_stat) == 0) { 1822 10923 Evan /* file exists, is it a lib */ 1823 10923 Evan dlhandle = dlopen(lib, RTLD_LAZY); 1824 10923 Evan if (dlhandle != NULL) { 1825 10923 Evan goto found; 1826 10923 Evan } 1827 10923 Evan 1828 10923 Evan } 1829 0 stevel return (CFGA_NO_LIB); 1830 0 stevel 1831 0 stevel found: 1832 0 stevel /* we got one! */ 1833 0 stevel (void) snprintf(libloc_p->pathname, sizeof (libloc_p->pathname), "%s", 1834 0 stevel lib); 1835 0 stevel 1836 0 stevel (void) dlclose(dlhandle); 1837 0 stevel 1838 0 stevel return (CFGA_OK); 1839 0 stevel } 1840 0 stevel 1841 0 stevel static cfga_err_t 1842 0 stevel lookup_cache(lib_loc_t *libloc_p) 1843 0 stevel { 1844 0 stevel lib_cache_t *entry; 1845 0 stevel (void) mutex_lock(&lib_cache_lock); 1846 0 stevel entry = lib_cache; 1847 0 stevel while (entry) { 1848 0 stevel if (strcmp(entry->lc_ap_id, libloc_p->ap_base) == 0) { 1849 0 stevel plugin_lib_t *libp = entry->lc_libp; 1850 0 stevel libloc_p->libp = libp; 1851 0 stevel hold_lib(libp); 1852 0 stevel (void) strcpy(libloc_p->pathname, libp->libpath); 1853 0 stevel (void) strcpy(libloc_p->ap_physical, 1854 0 stevel entry->lc_ap_physical); 1855 0 stevel (void) strcpy(libloc_p->ap_logical, 1856 0 stevel entry->lc_ap_logical); 1857 0 stevel (void) mutex_unlock(&lib_cache_lock); 1858 0 stevel return (CFGA_OK); 1859 0 stevel } 1860 0 stevel entry = entry->lc_next; 1861 0 stevel } 1862 0 stevel (void) mutex_unlock(&lib_cache_lock); 1863 0 stevel 1864 0 stevel return (CFGA_ERROR); 1865 0 stevel } 1866 0 stevel 1867 0 stevel static void 1868 0 stevel update_cache(lib_loc_t *libloc_p) 1869 0 stevel { 1870 0 stevel lib_cache_t *entry; 1871 0 stevel entry = config_calloc_check(1, sizeof (lib_cache_t), NULL); 1872 0 stevel if (entry == NULL) 1873 0 stevel return; 1874 0 stevel 1875 0 stevel entry->lc_ap_id = strdup(libloc_p->ap_base); 1876 0 stevel entry->lc_ap_physical = strdup(libloc_p->ap_physical); 1877 0 stevel entry->lc_ap_logical = strdup(libloc_p->ap_logical); 1878 0 stevel if ((entry->lc_ap_id == NULL) || (entry->lc_ap_physical == NULL) || 1879 0 stevel (entry->lc_ap_logical == NULL)) { 1880 0 stevel free(entry->lc_ap_id); 1881 0 stevel free(entry->lc_ap_physical); 1882 0 stevel free(entry->lc_ap_logical); 1883 0 stevel free(entry); 1884 0 stevel return; 1885 0 stevel } 1886 0 stevel 1887 0 stevel (void) mutex_lock(&lib_cache_lock); 1888 0 stevel entry->lc_libp = libloc_p->libp; 1889 0 stevel entry->lc_next = lib_cache; 1890 0 stevel lib_cache = entry; 1891 0 stevel hold_lib(entry->lc_libp); /* prevent stale cache */ 1892 0 stevel (void) mutex_unlock(&lib_cache_lock); 1893 0 stevel } 1894 0 stevel 1895 0 stevel static void 1896 0 stevel destroy_cache() 1897 0 stevel { 1898 0 stevel lib_cache_t *entry, *next; 1899 0 stevel (void) mutex_lock(&lib_cache_lock); 1900 0 stevel entry = lib_cache; 1901 0 stevel while (entry) { 1902 0 stevel next = entry->lc_next; 1903 0 stevel rele_lib(entry->lc_libp); 1904 0 stevel free(entry->lc_ap_id); 1905 0 stevel free(entry->lc_ap_physical); 1906 0 stevel free(entry->lc_ap_logical); 1907 0 stevel free(entry); 1908 0 stevel entry = next; 1909 0 stevel } 1910 0 stevel (void) mutex_unlock(&lib_cache_lock); 1911 0 stevel } 1912 0 stevel 1913 0 stevel /* 1914 0 stevel * find_ap_common - locate a particular attachment point 1915 0 stevel */ 1916 0 stevel static cfga_err_t 1917 0 stevel find_ap_common( 1918 0 stevel lib_loc_t *libloc_p, 1919 0 stevel const char *physpath, 1920 0 stevel int (*fcn)(di_node_t node, di_minor_t minor, void *arg), 1921 10923 Evan int (*fcn_hp)(di_node_t node, di_hp_t hp, void *arg), 1922 0 stevel char **errstring) 1923 0 stevel { 1924 6852 cth di_node_t rnode, wnode; 1925 0 stevel char *cp, *rpath; 1926 0 stevel size_t len; 1927 0 stevel 1928 0 stevel if (lookup_cache(libloc_p) == CFGA_OK) 1929 0 stevel return (CFGA_OK); 1930 0 stevel 1931 0 stevel if ((rpath = config_calloc_check(1, strlen(physpath) + 1, 1932 0 stevel errstring)) == NULL) { 1933 0 stevel return (CFGA_LIB_ERROR); 1934 0 stevel } 1935 0 stevel 1936 0 stevel (void) strcpy(rpath, physpath); 1937 0 stevel 1938 0 stevel /* Remove devices prefix (if any) */ 1939 0 stevel len = strlen(DEVICES_DIR); 1940 0 stevel if (strncmp(rpath, DEVICES_DIR SLASH, len + strlen(SLASH)) == 0) { 1941 0 stevel (void) memmove(rpath, rpath + len, 1942 0 stevel strlen(rpath + len) + 1); 1943 0 stevel } 1944 0 stevel 1945 0 stevel /* Remove dynamic component if any */ 1946 0 stevel if ((cp = GET_DYN(rpath)) != NULL) { 1947 0 stevel *cp = '\0'; 1948 0 stevel } 1949 0 stevel 1950 0 stevel /* Remove minor name (if any) */ 1951 0 stevel if ((cp = strrchr(rpath, ':')) != NULL) { 1952 0 stevel *cp = '\0'; 1953 0 stevel } 1954 0 stevel 1955 0 stevel /* 1956 0 stevel * begin walk of device tree 1957 10923 Evan * 1958 10923 Evan * Since we create minor nodes & dev links for both all PCI/PCIE 1959 10923 Evan * connectors, but only create hp nodes for PCIE/PCISHPC connectors 1960 10923 Evan * of the new framework, we should first match with hp nodes. If 1961 10923 Evan * the ap_id refers to a PCIE/PCISHPC connector, we'll be able to 1962 10923 Evan * find it here. 1963 0 stevel */ 1964 10923 Evan rnode = di_init("/", DINFOSUBTREE | DINFOHP); 1965 6852 cth if (rnode) 1966 6852 cth wnode = di_lookup_node(rnode, rpath); 1967 6852 cth else 1968 6852 cth wnode = DI_NODE_NIL; 1969 0 stevel 1970 6852 cth if (wnode == DI_NODE_NIL) { 1971 6852 cth if (rnode == DI_NODE_NIL) { 1972 10923 Evan S_FREE(rpath); 1973 0 stevel config_err(errno, DI_INIT_FAILED, errstring); 1974 0 stevel return (CFGA_LIB_ERROR); 1975 6852 cth } else { 1976 6852 cth /* 1977 10923 Evan * di_lookup_node() may fail, either because the 1978 10923 Evan * ap_id does not exist, or because the ap_id refers 1979 10923 Evan * to a legacy PCI slot, thus we'll not able to 1980 10923 Evan * find node using DINFOHP, try to see if we can 1981 10923 Evan * find one using DINFOCACHE. 1982 6852 cth */ 1983 6852 cth di_fini(rnode); 1984 10923 Evan goto find_minor; 1985 0 stevel } 1986 0 stevel } 1987 0 stevel 1988 0 stevel libloc_p->libp = NULL; 1989 0 stevel libloc_p->status = CFGA_APID_NOEXIST; 1990 0 stevel 1991 10923 Evan (void) di_walk_hp(wnode, NULL, DI_HP_CONNECTOR, 1992 10923 Evan libloc_p, fcn_hp); 1993 0 stevel 1994 0 stevel di_fini(rnode); 1995 10923 Evan 1996 10923 Evan /* 1997 10923 Evan * Failed to find a matching hp node, try minor node. 1998 10923 Evan */ 1999 10923 Evan if (libloc_p->libp == NULL) { 2000 10923 Evan find_minor: 2001 10923 Evan rnode = di_init("/", DINFOCACHE); 2002 10923 Evan if (rnode) 2003 10923 Evan wnode = di_lookup_node(rnode, rpath); 2004 10923 Evan else 2005 10923 Evan wnode = DI_NODE_NIL; 2006 10923 Evan 2007 10923 Evan if (wnode == DI_NODE_NIL) { 2008 10923 Evan if (rnode == DI_NODE_NIL) { 2009 10923 Evan S_FREE(rpath); 2010 10923 Evan config_err(errno, DI_INIT_FAILED, errstring); 2011 10923 Evan return (CFGA_LIB_ERROR); 2012 10923 Evan } else { 2013 10923 Evan /* 2014 10923 Evan * di_lookup_node() may fail, because the 2015 10923 Evan * ap_id does not exist. 2016 10923 Evan */ 2017 10923 Evan S_FREE(rpath); 2018 10923 Evan di_fini(rnode); 2019 10923 Evan return (CFGA_APID_NOEXIST); 2020 10923 Evan } 2021 10923 Evan } 2022 10923 Evan 2023 10923 Evan libloc_p->libp = NULL; 2024 10923 Evan libloc_p->status = CFGA_APID_NOEXIST; 2025 10923 Evan 2026 10923 Evan (void) di_walk_minor(wnode, "ddi_ctl:attachment_point", 2027 10923 Evan DI_CHECK_ALIAS|DI_CHECK_INTERNAL_PATH, 2028 10923 Evan libloc_p, fcn); 2029 10923 Evan 2030 10923 Evan di_fini(rnode); 2031 10923 Evan } 2032 10923 Evan 2033 10923 Evan S_FREE(rpath); 2034 0 stevel 2035 0 stevel if (libloc_p->libp != NULL) { 2036 0 stevel update_cache(libloc_p); 2037 0 stevel return (CFGA_OK); 2038 0 stevel } else { 2039 0 stevel return (libloc_p->status); 2040 0 stevel } 2041 0 stevel } 2042 0 stevel 2043 0 stevel /* 2044 10923 Evan * check_ap - called for each non-SHP attachment point found 2045 10923 Evan */ 2046 10923 Evan static int 2047 10923 Evan check_ap( 2048 10923 Evan di_node_t node, 2049 10923 Evan di_minor_t minor, 2050 10923 Evan void *arg) 2051 10923 Evan { 2052 10923 Evan return (check_ap_impl(node, minor, NULL, arg)); 2053 10923 Evan } 2054 10923 Evan 2055 10923 Evan /* 2056 10923 Evan * check_ap_hp - called for each SHP attachment point found 2057 10923 Evan */ 2058 10923 Evan static int 2059 10923 Evan check_ap_hp( 2060 10923 Evan di_node_t node, 2061 10923 Evan di_hp_t hp, 2062 10923 Evan void *arg) 2063 10923 Evan { 2064 10923 Evan return (check_ap_impl(node, NULL, hp, arg)); 2065 10923 Evan } 2066 10923 Evan 2067 10923 Evan /* 2068 10923 Evan * check_ap_impl - called for each attachment point found 2069 0 stevel * 2070 0 stevel * This is used in cases where a particular attachment point 2071 0 stevel * or type of attachment point is specified via a logical name or ap_type. 2072 0 stevel * Not used for physical names or in the list case with no 2073 0 stevel * ap's specified. 2074 0 stevel */ 2075 0 stevel static int 2076 10923 Evan check_ap_impl( 2077 0 stevel di_node_t node, 2078 0 stevel di_minor_t minor, 2079 10923 Evan di_hp_t hp, 2080 0 stevel void *arg) 2081 0 stevel { 2082 0 stevel char *cp = NULL; 2083 0 stevel char aptype[MAXPATHLEN]; 2084 0 stevel char *recep_id = NULL; 2085 0 stevel char *node_minor; 2086 0 stevel char *drv_name; 2087 0 stevel char inst[MAXPATHLEN]; 2088 0 stevel char inst2[MAXPATHLEN]; 2089 0 stevel lib_loc_t *libloc_p; 2090 0 stevel int comparison_test; 2091 0 stevel int instance; 2092 0 stevel cfga_ap_types_t type; 2093 0 stevel 2094 10923 Evan if (minor != DI_MINOR_NIL && hp != DI_HP_NIL) 2095 10923 Evan return (DI_WALK_CONTINUE); 2096 0 stevel 2097 0 stevel libloc_p = (lib_loc_t *)arg; 2098 0 stevel 2099 0 stevel (void) snprintf(aptype, sizeof (aptype), "%s", libloc_p->ap_base); 2100 0 stevel 2101 0 stevel /* 2102 0 stevel * This routime handles only aptypes and driver based logical apids. 2103 0 stevel */ 2104 0 stevel type = find_arg_type(aptype); 2105 0 stevel if (type == LOGICAL_DRV_AP) { 2106 0 stevel cp = strchr(aptype, ':'); 2107 0 stevel *cp = '\0'; 2108 0 stevel recep_id = cp+1; 2109 0 stevel cp--; 2110 0 stevel while (isdigit(*cp) && cp != aptype) 2111 0 stevel cp--; 2112 0 stevel cp++; 2113 0 stevel 2114 0 stevel (void) snprintf(inst, sizeof (inst), "%s", cp); 2115 0 stevel 2116 0 stevel *cp = '\0'; 2117 0 stevel } else if (type != AP_TYPE) { 2118 0 stevel libloc_p->status = CFGA_APID_NOEXIST; 2119 0 stevel return (DI_WALK_CONTINUE); 2120 0 stevel } 2121 0 stevel 2122 10923 Evan if (minor != DI_MINOR_NIL) 2123 10923 Evan node_minor = di_minor_name(minor); 2124 10923 Evan else 2125 10923 Evan node_minor = di_hp_name(hp); 2126 10923 Evan 2127 0 stevel drv_name = di_driver_name(node); 2128 0 stevel instance = di_instance(node); 2129 0 stevel 2130 0 stevel if (node_minor == NULL || drv_name == NULL || instance == -1) { 2131 0 stevel libloc_p->status = CFGA_APID_NOEXIST; 2132 0 stevel return (DI_WALK_CONTINUE); 2133 0 stevel } 2134 0 stevel 2135 0 stevel (void) sprintf(inst2, "%d", instance); 2136 0 stevel 2137 0 stevel /* 2138 0 stevel * If the base matches driver and instance try and find a lib for it, 2139 0 stevel * then load it. On any failure we continue the walk. 2140 0 stevel * 2141 0 stevel * driver based logical ap_ids are derived from driver name + instance. 2142 0 stevel * Ap_types are just partial driver names. 2143 0 stevel * 2144 0 stevel */ 2145 0 stevel 2146 0 stevel comparison_test = 0; 2147 0 stevel if (type == AP_TYPE) { 2148 0 stevel if (strncmp(aptype, drv_name, strlen(aptype)) == 0) { 2149 0 stevel comparison_test = 1; 2150 0 stevel } 2151 0 stevel } else { 2152 0 stevel if (strcmp(aptype, drv_name) == 0 && 2153 0 stevel strcmp(recep_id, node_minor) == 0 && 2154 0 stevel strcmp(inst, inst2) == 0) { 2155 0 stevel comparison_test = 1; 2156 0 stevel } 2157 0 stevel } 2158 0 stevel 2159 0 stevel if (comparison_test) { 2160 0 stevel /* 2161 0 stevel * save the correct type of error so user does not get confused 2162 0 stevel */ 2163 10923 Evan if (minor != DI_MINOR_NIL) { 2164 10923 Evan if (find_lib(node, minor, libloc_p) != CFGA_OK) { 2165 10923 Evan libloc_p->status = CFGA_NO_LIB; 2166 10923 Evan return (DI_WALK_CONTINUE); 2167 10923 Evan } 2168 10923 Evan if (load_lib(node, minor, libloc_p) != CFGA_OK) { 2169 10923 Evan libloc_p->status = CFGA_LIB_ERROR; 2170 10923 Evan return (DI_WALK_CONTINUE); 2171 10923 Evan } 2172 10923 Evan } else { 2173 10923 Evan if (find_lib_hp(node, hp, libloc_p) != CFGA_OK) { 2174 10923 Evan libloc_p->status = CFGA_NO_LIB; 2175 10923 Evan return (DI_WALK_CONTINUE); 2176 10923 Evan } 2177 10923 Evan if (load_lib_hp(node, hp, libloc_p) != CFGA_OK) { 2178 10923 Evan libloc_p->status = CFGA_LIB_ERROR; 2179 10923 Evan return (DI_WALK_CONTINUE); 2180 10923 Evan } 2181 0 stevel } 2182 0 stevel libloc_p->status = CFGA_OK; 2183 0 stevel return (DI_WALK_TERMINATE); 2184 0 stevel } else { 2185 0 stevel libloc_p->status = CFGA_APID_NOEXIST; 2186 0 stevel return (DI_WALK_CONTINUE); 2187 0 stevel } 2188 0 stevel } 2189 0 stevel 2190 0 stevel 2191 0 stevel /* 2192 10923 Evan * check_ap_phys - called for each non-SHP attachment point found 2193 10923 Evan */ 2194 10923 Evan static int 2195 10923 Evan check_ap_phys( 2196 10923 Evan di_node_t node, 2197 10923 Evan di_minor_t minor, 2198 10923 Evan void *arg) 2199 10923 Evan { 2200 10923 Evan return (check_ap_phys_impl(node, minor, DI_HP_NIL, arg)); 2201 10923 Evan } 2202 10923 Evan 2203 10923 Evan /* 2204 10923 Evan * check_ap_phys_hp - called for each SHP attachment point found 2205 10923 Evan */ 2206 10923 Evan static int 2207 10923 Evan check_ap_phys_hp( 2208 10923 Evan di_node_t node, 2209 10923 Evan di_hp_t hp, 2210 10923 Evan void *arg) 2211 10923 Evan { 2212 10923 Evan return (check_ap_phys_impl(node, DI_HP_NIL, hp, arg)); 2213 10923 Evan } 2214 10923 Evan 2215 10923 Evan /* 2216 10923 Evan * check_ap_phys_impl - called for each attachment point found 2217 0 stevel * 2218 0 stevel * This is used in cases where a particular attachment point 2219 0 stevel * is specified via a physical name. If the name matches then 2220 0 stevel * we try and find and load the library for it. 2221 0 stevel */ 2222 0 stevel static int 2223 10923 Evan check_ap_phys_impl( 2224 0 stevel di_node_t node, 2225 0 stevel di_minor_t minor, 2226 10923 Evan di_hp_t hp, 2227 0 stevel void *arg) 2228 0 stevel { 2229 0 stevel lib_loc_t *libloc_p; 2230 0 stevel char phys_name[MAXPATHLEN]; 2231 0 stevel char *devfs_path; 2232 0 stevel char *minor_name; 2233 0 stevel 2234 10923 Evan if (minor != DI_MINOR_NIL && hp != DI_HP_NIL) 2235 10923 Evan return (DI_WALK_CONTINUE); 2236 10923 Evan 2237 0 stevel libloc_p = (lib_loc_t *)arg; 2238 0 stevel devfs_path = di_devfs_path(node); 2239 10923 Evan if (minor != DI_MINOR_NIL) 2240 10923 Evan minor_name = di_minor_name(minor); 2241 10923 Evan else 2242 10923 Evan minor_name = di_hp_name(hp); 2243 0 stevel 2244 0 stevel if (devfs_path == NULL || minor_name == NULL) { 2245 0 stevel libloc_p->status = CFGA_APID_NOEXIST; 2246 0 stevel return (DI_WALK_CONTINUE); 2247 0 stevel } 2248 0 stevel 2249 0 stevel (void) snprintf(phys_name, sizeof (phys_name), "%s%s:%s", 2250 0 stevel DEVICES_DIR, devfs_path, minor_name); 2251 0 stevel 2252 0 stevel di_devfs_path_free(devfs_path); 2253 0 stevel 2254 0 stevel if (strcmp(phys_name, libloc_p->ap_base) == 0) { 2255 10923 Evan if (minor != DI_MINOR_NIL) { 2256 10923 Evan if (find_lib(node, minor, libloc_p) != CFGA_OK) { 2257 10923 Evan libloc_p->status = CFGA_NO_LIB; 2258 10923 Evan return (DI_WALK_CONTINUE); 2259 10923 Evan } 2260 10923 Evan if (load_lib(node, minor, libloc_p) != CFGA_OK) { 2261 10923 Evan libloc_p->status = CFGA_LIB_ERROR; 2262 10923 Evan return (DI_WALK_CONTINUE); 2263 10923 Evan } 2264 10923 Evan } else { 2265 10923 Evan if (find_lib_hp(node, hp, libloc_p) != CFGA_OK) { 2266 10923 Evan libloc_p->status = CFGA_NO_LIB; 2267 10923 Evan return (DI_WALK_CONTINUE); 2268 10923 Evan } 2269 10923 Evan if (load_lib_hp(node, hp, libloc_p) != CFGA_OK) { 2270 10923 Evan libloc_p->status = CFGA_LIB_ERROR; 2271 10923 Evan return (DI_WALK_CONTINUE); 2272 10923 Evan } 2273 0 stevel } 2274 10923 Evan 2275 0 stevel libloc_p->status = CFGA_OK; 2276 0 stevel return (DI_WALK_TERMINATE); 2277 0 stevel } else { 2278 0 stevel libloc_p->status = CFGA_APID_NOEXIST; 2279 0 stevel return (DI_WALK_CONTINUE); 2280 0 stevel } 2281 0 stevel } 2282 0 stevel 2283 0 stevel /* 2284 0 stevel * lib_in_list 2285 0 stevel * 2286 0 stevel * See if library, as specified by the full pathname and controller 2287 0 stevel * instance number is already represented in the plugin library list. 2288 0 stevel * If the instance number is -1 it is ignored. 2289 0 stevel */ 2290 0 stevel static plugin_lib_t * 2291 0 stevel lib_in_list(char *libpath) 2292 0 stevel { 2293 0 stevel plugin_lib_t *libp = NULL; 2294 0 stevel 2295 0 stevel for (libp = plugin_list.next; libp != NULL; libp = libp->next) { 2296 0 stevel if (strncmp(libpath, libp->libpath, MAXPATHLEN) == 0) { 2297 0 stevel return (libp); 2298 0 stevel } 2299 0 stevel } 2300 0 stevel return (NULL); 2301 0 stevel } 2302 0 stevel 2303 0 stevel 2304 0 stevel 2305 0 stevel 2306 0 stevel /* 2307 0 stevel * Coalesce stat and list data into single array 2308 0 stevel */ 2309 0 stevel static cfga_err_t 2310 0 stevel realloc_data_ext( 2311 0 stevel cfga_list_data_t **ap_id_list, 2312 0 stevel int *nlistp, 2313 0 stevel list_stat_t *lstatp) 2314 0 stevel { 2315 0 stevel int i, j; 2316 0 stevel stat_data_list_t *slp; 2317 0 stevel cfga_list_data_t *cldp; 2318 0 stevel array_list_t *alp; 2319 0 stevel cfga_err_t rc = CFGA_OK; 2320 0 stevel 2321 0 stevel 2322 0 stevel assert(*lstatp->countp >= 0); 2323 0 stevel 2324 0 stevel if (*lstatp->countp == 0) { 2325 0 stevel *ap_id_list = NULL; 2326 0 stevel *nlistp = 0; 2327 0 stevel return (CFGA_OK); 2328 0 stevel } 2329 0 stevel 2330 0 stevel /* 2331 0 stevel * allocate the array 2332 0 stevel */ 2333 0 stevel if ((cldp = config_calloc_check(*lstatp->countp, 2334 0 stevel sizeof (cfga_list_data_t), lstatp->errstr)) == NULL) { 2335 0 stevel rc = CFGA_LIB_ERROR; 2336 0 stevel goto out; 2337 0 stevel } 2338 0 stevel 2339 0 stevel /* 2340 0 stevel * copy all the stat elements (if any) into the array 2341 0 stevel */ 2342 0 stevel slp = lstatp->sdl; 2343 0 stevel for (i = 0; slp != NULL; i++) { 2344 0 stevel if (i >= *lstatp->countp) { 2345 0 stevel rc = CFGA_LIB_ERROR; 2346 0 stevel goto out; 2347 0 stevel } 2348 0 stevel stat_to_list(&cldp[i], &slp->stat_data); 2349 0 stevel slp = slp->next; 2350 0 stevel } 2351 0 stevel 2352 0 stevel /* 2353 0 stevel * copy all the list elements (if any) into the array 2354 0 stevel */ 2355 0 stevel alp = lstatp->al; 2356 0 stevel for (; alp != NULL; ) { 2357 0 stevel if (i + alp->nelem > *lstatp->countp) { 2358 0 stevel rc = CFGA_LIB_ERROR; 2359 0 stevel goto out; 2360 0 stevel } 2361 0 stevel 2362 0 stevel for (j = 0; j < alp->nelem; i++, j++) { 2363 0 stevel cldp[i] = alp->array[j]; 2364 0 stevel } 2365 0 stevel alp = alp->next; 2366 0 stevel } 2367 0 stevel 2368 0 stevel if (i != *lstatp->countp) { 2369 0 stevel rc = CFGA_LIB_ERROR; 2370 0 stevel } else { 2371 0 stevel rc = CFGA_OK; 2372 0 stevel } 2373 0 stevel 2374 0 stevel /*FALLTHRU*/ 2375 0 stevel 2376 0 stevel out: 2377 0 stevel /* clean up */ 2378 0 stevel lstat_free(lstatp); 2379 0 stevel 2380 0 stevel if (rc == CFGA_OK) { 2381 0 stevel *ap_id_list = cldp; 2382 0 stevel *nlistp = *lstatp->countp; 2383 0 stevel } else { 2384 0 stevel S_FREE(cldp); 2385 0 stevel *ap_id_list = NULL; 2386 0 stevel *nlistp = 0; 2387 0 stevel } 2388 0 stevel return (rc); 2389 0 stevel } 2390 0 stevel 2391 0 stevel /* 2392 0 stevel * The caller of this routine may supply a buffer through 2393 0 stevel * ap_id_list for returning data. Otherwise, this routine allocates the 2394 0 stevel * buffer. 2395 0 stevel */ 2396 0 stevel static cfga_err_t 2397 0 stevel realloc_data(cfga_stat_data_t **ap_id_list, int *nlistp, list_stat_t *lstatp) 2398 0 stevel { 2399 0 stevel int i; 2400 0 stevel stat_data_list_t *slp; 2401 0 stevel cfga_stat_data_t *csdp, *buf; 2402 0 stevel cfga_err_t rc; 2403 0 stevel 2404 0 stevel 2405 0 stevel assert(*lstatp->countp >= 0); 2406 0 stevel 2407 0 stevel if (*lstatp->countp == 0) { 2408 0 stevel *nlistp = 0; 2409 0 stevel return (CFGA_OK); 2410 0 stevel } 2411 0 stevel 2412 0 stevel 2413 0 stevel /* 2414 0 stevel * allocate the array if caller does not supply one. 2415 0 stevel */ 2416 0 stevel if (*ap_id_list == NULL) { 2417 0 stevel if ((buf = config_calloc_check(*lstatp->countp, 2418 0 stevel sizeof (cfga_stat_data_t), lstatp->errstr)) == NULL) { 2419 0 stevel rc = CFGA_LIB_ERROR; 2420 0 stevel goto out; 2421 0 stevel } 2422 0 stevel } else { 2423 0 stevel buf = *ap_id_list; 2424 0 stevel } 2425 0 stevel 2426 0 stevel /* 2427 0 stevel * copy the stat elements into the array 2428 0 stevel */ 2429 0 stevel csdp = buf; 2430 0 stevel slp = lstatp->sdl; 2431 0 stevel for (i = 0; slp != NULL; i++) { 2432 0 stevel if (i >= *lstatp->countp) { 2433 0 stevel rc = CFGA_LIB_ERROR; 2434 0 stevel goto out; 2435 0 stevel } 2436 0 stevel *csdp++ = slp->stat_data; 2437 0 stevel slp = slp->next; 2438 0 stevel } 2439 0 stevel 2440 0 stevel rc = CFGA_OK; 2441 0 stevel 2442 0 stevel out: 2443 0 stevel if (rc == CFGA_OK) { 2444 0 stevel *nlistp = *lstatp->countp; 2445 0 stevel *ap_id_list = buf; 2446 0 stevel } else { 2447 0 stevel /* 2448 0 stevel * Free buffer only if we allocated it. 2449 0 stevel */ 2450 0 stevel if (*ap_id_list == NULL) { 2451 0 stevel free(buf); 2452 0 stevel } 2453 0 stevel *nlistp = 0; 2454 0 stevel } 2455 0 stevel 2456 0 stevel assert(lstatp->al == NULL); 2457 0 stevel lstat_free(lstatp); 2458 0 stevel 2459 0 stevel return (rc); 2460 0 stevel } 2461 0 stevel 2462 0 stevel 2463 0 stevel /* 2464 0 stevel * list_common - walk the device tree and stat all attachment points. 2465 0 stevel */ 2466 0 stevel static cfga_err_t 2467 0 stevel list_common(list_stat_t *lstatp, const char *class) 2468 0 stevel { 2469 0 stevel di_node_t rnode; 2470 0 stevel char nodetype[MAXPATHLEN]; 2471 0 stevel const char *l_class, *l_sep; 2472 0 stevel 2473 0 stevel /* 2474 0 stevel * May walk a subset of all attachment points in the device tree if 2475 0 stevel * a class is specified 2476 0 stevel */ 2477 0 stevel if (class != NULL) { 2478 0 stevel l_sep = ":"; 2479 0 stevel l_class = class; 2480 0 stevel } else { 2481 0 stevel l_sep = l_class = ""; 2482 0 stevel } 2483 0 stevel 2484 0 stevel (void) snprintf(nodetype, sizeof (nodetype), "%s%s%s", 2485 0 stevel DDI_NT_ATTACHMENT_POINT, l_sep, l_class); 2486 0 stevel 2487 10923 Evan /* 2488 10923 Evan * Walk all hp nodes 2489 10923 Evan */ 2490 10923 Evan if ((rnode = di_init("/", DINFOSUBTREE | DINFOHP)) == DI_NODE_NIL) { 2491 10923 Evan config_err(errno, DI_INIT_FAILED, lstatp->errstr); 2492 10923 Evan return (CFGA_LIB_ERROR); 2493 10923 Evan } 2494 10923 Evan /* No need to filter on class for now */ 2495 10923 Evan (void) di_walk_hp(rnode, NULL, DI_HP_CONNECTOR, 2496 10923 Evan lstatp, do_list_common_hp); 2497 10923 Evan 2498 10923 Evan di_fini(rnode); 2499 10923 Evan 2500 10923 Evan /* 2501 10923 Evan * Walk all minor nodes 2502 10923 Evan * but exclude PCIE/PCIESHPC connectors which have been walked above. 2503 10923 Evan */ 2504 10923 Evan if ((rnode = di_init("/", DINFOCACHE)) == DI_NODE_NIL) { 2505 10923 Evan config_err(errno, DI_INIT_FAILED, lstatp->errstr); 2506 10923 Evan return (CFGA_LIB_ERROR); 2507 10923 Evan } 2508 0 stevel (void) di_walk_minor(rnode, nodetype, 2509 0 stevel DI_CHECK_ALIAS|DI_CHECK_INTERNAL_PATH, lstatp, do_list_common); 2510 10923 Evan 2511 0 stevel di_fini(rnode); 2512 10923 Evan 2513 10923 Evan if (lstatp->shp_errstr != NULL) { 2514 10923 Evan *(lstatp->errstr) = strdup(lstatp->shp_errstr); 2515 10923 Evan free(lstatp->shp_errstr); 2516 10923 Evan lstatp->shp_errstr = NULL; 2517 10923 Evan } 2518 0 stevel 2519 0 stevel return (CFGA_OK); 2520 0 stevel } 2521 0 stevel 2522 0 stevel static void 2523 0 stevel config_err(int errnum, int err_type, char **errstring) 2524 0 stevel { 2525 0 stevel char *p = NULL, *q = NULL; 2526 0 stevel char *syserr = NULL; 2527 0 stevel char syserr_num[20]; 2528 0 stevel int len = 0; 2529 0 stevel 2530 0 stevel /* 2531 0 stevel * If errstring is null it means user in not interested in getting 2532 0 stevel * error status. So we don't do all the work 2533 0 stevel */ 2534 0 stevel if (errstring == NULL) { 2535 0 stevel return; 2536 0 stevel } 2537 0 stevel 2538 0 stevel if (errnum != 0) { 2539 0 stevel syserr = strerror(errnum); 2540 0 stevel if (syserr == NULL) { 2541 0 stevel (void) sprintf(syserr_num, "errno=%d", errnum); 2542 0 stevel syserr = syserr_num; 2543 0 stevel } 2544 0 stevel } else 2545 0 stevel syserr = NULL; 2546 0 stevel 2547 0 stevel q = dgettext(TEXT_DOMAIN, err_strings[err_type]); 2548 0 stevel 2549 0 stevel len = strlen(q); 2550 0 stevel if (syserr != NULL) { 2551 0 stevel len += strlen(err_sep) + strlen(syserr); 2552 0 stevel } 2553 0 stevel 2554 0 stevel p = malloc(len + 1); 2555 0 stevel if (p == NULL) { 2556 0 stevel *errstring = NULL; 2557 0 stevel return; 2558 0 stevel } 2559 0 stevel 2560 0 stevel (void) strcpy(p, q); 2561 0 stevel if (syserr != NULL) { 2562 0 stevel (void) strcat(p, err_sep); 2563 0 stevel (void) strcat(p, syserr); 2564 0 stevel } 2565 0 stevel 2566 0 stevel *errstring = p; 2567 0 stevel } 2568 0 stevel 2569 0 stevel /* 2570 10923 Evan * do_list_common - list non-SHP attachment point 2571 0 stevel */ 2572 0 stevel static int 2573 0 stevel do_list_common( 2574 0 stevel di_node_t node, 2575 0 stevel di_minor_t minor, 2576 0 stevel void *arg) 2577 0 stevel { 2578 10923 Evan di_node_t rnode; 2579 10923 Evan di_hp_t hp; 2580 10923 Evan char *minor_name; 2581 10923 Evan 2582 10923 Evan minor_name = di_minor_name(minor); 2583 10923 Evan 2584 10923 Evan /* 2585 10923 Evan * since PCIE/PCIHSHPC connectors have both hp nodes and minor nodes 2586 10923 Evan * created for now, we need to specifically exclude these connectors 2587 10923 Evan * during walking minor nodes. 2588 10923 Evan */ 2589 10923 Evan if ((rnode = di_init(di_devfs_path(node), DINFOSUBTREE | DINFOHP)) 2590 10923 Evan == DI_NODE_NIL) { 2591 10923 Evan return (DI_WALK_CONTINUE); 2592 10923 Evan } 2593 10923 Evan 2594 10923 Evan for (hp = DI_HP_NIL; (hp = di_hp_next(rnode, hp)) != DI_HP_NIL; ) { 2595 10923 Evan if (strcmp(di_hp_name(hp), minor_name) == 0) { 2596 10923 Evan di_fini(rnode); 2597 10923 Evan return (DI_WALK_CONTINUE); 2598 10923 Evan } 2599 10923 Evan } 2600 10923 Evan 2601 10923 Evan di_fini(rnode); 2602 10923 Evan 2603 10923 Evan return (do_list_common_impl(node, minor, NULL, arg)); 2604 10923 Evan } 2605 10923 Evan 2606 10923 Evan /* 2607 10923 Evan * do_list_common_hp - list SHP attachment point 2608 10923 Evan */ 2609 10923 Evan static int 2610 10923 Evan do_list_common_hp( 2611 10923 Evan di_node_t node, 2612 10923 Evan di_hp_t hp, 2613 10923 Evan void *arg) 2614 10923 Evan { 2615 10923 Evan return (do_list_common_impl(node, NULL, hp, arg)); 2616 10923 Evan } 2617 10923 Evan 2618 10923 Evan /* 2619 10923 Evan * do_list_common_impl - Routine to list attachment point as part of 2620 10923 Evan * a config_list opertion. Used by both v1 and v2 interfaces. 2621 10923 Evan * This is somewhat similar to config_get_lib() and its helper routines 2622 10923 Evan * except that the ap_ids are always physical and don't have dynamic 2623 10923 Evan * components. 2624 10923 Evan */ 2625 10923 Evan static int 2626 10923 Evan do_list_common_impl( 2627 10923 Evan di_node_t node, 2628 10923 Evan di_minor_t minor, 2629 10923 Evan di_hp_t hp, 2630 10923 Evan void *arg) 2631 10923 Evan { 2632 0 stevel lib_loc_t lib_loc; 2633 0 stevel plugin_lib_t *libp; 2634 0 stevel list_stat_t *lstatp = NULL; 2635 0 stevel cfga_err_t ret = CFGA_ERROR; 2636 0 stevel 2637 10923 Evan if (minor != DI_MINOR_NIL && hp != DI_HP_NIL) 2638 10923 Evan return (DI_WALK_CONTINUE); 2639 0 stevel 2640 0 stevel lstatp = (list_stat_t *)arg; 2641 0 stevel 2642 0 stevel lib_loc.libp = NULL; 2643 0 stevel /* 2644 0 stevel * try and find a lib for this node 2645 0 stevel */ 2646 10923 Evan if (minor != DI_MINOR_NIL) { 2647 10923 Evan ret = find_lib(node, minor, &lib_loc); 2648 10923 Evan } else { 2649 10923 Evan ret = find_lib_hp(node, hp, &lib_loc); 2650 10923 Evan } 2651 10923 Evan if (ret != CFGA_OK) { 2652 0 stevel return (DI_WALK_CONTINUE); 2653 0 stevel } 2654 0 stevel 2655 0 stevel /* 2656 0 stevel * Load all plugins. We will check compatibility later in this 2657 0 stevel * routine. 2658 0 stevel */ 2659 0 stevel lib_loc.vers_req.v_min = CFGA_HSL_V1; 2660 0 stevel lib_loc.vers_req.v_max = CFGA_HSL_VERS; 2661 0 stevel 2662 10923 Evan if (minor != DI_MINOR_NIL) { 2663 10923 Evan ret = load_lib(node, minor, &lib_loc); 2664 10923 Evan } else { 2665 10923 Evan ret = load_lib_hp(node, hp, &lib_loc); 2666 10923 Evan } 2667 0 stevel if (ret != CFGA_OK) { 2668 0 stevel return (DI_WALK_CONTINUE); 2669 0 stevel } 2670 0 stevel 2671 0 stevel libp = lib_loc.libp; 2672 0 stevel assert(libp != NULL); 2673 0 stevel 2674 0 stevel /* 2675 0 stevel * Note: For list type routines (list all attachment points in 2676 0 stevel * device tree) we don't pass errstring to the plugin, nor do we 2677 0 stevel * stop the walk if an error occurs in the plugin. 2678 0 stevel */ 2679 0 stevel if (compat_plugin(&lstatp->use_vers, libp->plugin_vers)) { 2680 10923 Evan if (minor != DI_MINOR_NIL) { 2681 10923 Evan (void) libp->vers_ops->stat_plugin(lstatp, 2682 10923 Evan &lib_loc, NULL); 2683 10923 Evan } else { 2684 10923 Evan /* 2685 10923 Evan * If the underlying hotplug daemon is not enabled, 2686 10923 Evan * the SHP attach points will not be shown, this 2687 10923 Evan * could confuse the uesrs. We specifically pass the 2688 10923 Evan * errstring to SHP plugin so that it can set the 2689 10923 Evan * errstring accordingly in this case, giving users 2690 10923 Evan * a hint. 2691 10923 Evan */ 2692 10923 Evan ret = libp->vers_ops->stat_plugin(lstatp, 2693 10923 Evan &lib_loc, lstatp->errstr); 2694 10923 Evan if (ret == CFGA_NOTSUPP && *(lstatp->errstr) != NULL) { 2695 10923 Evan if (lstatp->shp_errstr == NULL) { 2696 10923 Evan lstatp->shp_errstr = 2697 10923 Evan strdup(*(lstatp->errstr)); 2698 10923 Evan } 2699 10923 Evan } 2700 10923 Evan 2701 10923 Evan if (*(lstatp->errstr) != NULL) { 2702 10923 Evan free(*(lstatp->errstr)); 2703 10923 Evan *(lstatp->errstr) = NULL; 2704 10923 Evan } 2705 10923 Evan } 2706 0 stevel } 2707 0 stevel rele_lib(libp); 2708 0 stevel 2709 0 stevel return (DI_WALK_CONTINUE); 2710 0 stevel } 2711 0 stevel 2712 0 stevel /* 2713 0 stevel * stat_common - stat a user specified set of attachment points. 2714 0 stevel */ 2715 0 stevel static cfga_err_t 2716 0 stevel stat_common( 2717 0 stevel int num_ap_ids, 2718 0 stevel char *const *ap_ids, 2719 0 stevel const char *class, 2720 0 stevel list_stat_t *lstatp) 2721 0 stevel { 2722 0 stevel int i; 2723 0 stevel lib_loc_t libloc; 2724 0 stevel plugin_lib_t *libp; 2725 0 stevel cfga_err_t rc = CFGA_OK; 2726 0 stevel 2727 0 stevel 2728 0 stevel /* 2729 0 stevel * operate on each ap_id 2730 0 stevel */ 2731 0 stevel for (i = 0; i < num_ap_ids; i++) { 2732 0 stevel libloc.libp = NULL; 2733 0 stevel if ((rc = config_get_lib(ap_ids[i], &libloc, 2734 0 stevel lstatp->errstr)) != CFGA_OK) { 2735 0 stevel break; 2736 0 stevel } 2737 0 stevel assert(libloc.libp != NULL); 2738 0 stevel libp = libloc.libp; 2739 0 stevel 2740 0 stevel /* 2741 0 stevel * do pre-filtering if requested 2742 0 stevel */ 2743 0 stevel if (class != NULL && strcmp(libloc.ap_class, class)) { 2744 0 stevel rele_lib(libp); 2745 0 stevel continue; 2746 0 stevel } 2747 0 stevel 2748 0 stevel /* 2749 0 stevel * Unlike list type routines, while stat'ing specific 2750 0 stevel * attachment points we pass errstring to the plugins 2751 0 stevel * and halt if an error occurs in the plugin. 2752 0 stevel */ 2753 0 stevel rc = libp->vers_ops->stat_plugin(lstatp, &libloc, 2754 0 stevel lstatp->errstr); 2755 0 stevel rele_lib(libp); 2756 0 stevel if (rc != CFGA_OK) { 2757 0 stevel break; 2758 0 stevel } 2759 0 stevel } 2760 0 stevel 2761 0 stevel if (rc != CFGA_OK) { 2762 0 stevel lstat_free(lstatp); 2763 0 stevel } 2764 0 stevel return (rc); 2765 0 stevel } 2766 0 stevel 2767 0 stevel /*ARGSUSED*/ 2768 0 stevel static cfga_err_t 2769 0 stevel null_stat_plugin(list_stat_t *lstatp, lib_loc_t *libloc_p, char **errstring) 2770 0 stevel { 2771 0 stevel return (CFGA_OK); 2772 0 stevel } 2773 0 stevel 2774 0 stevel /* 2775 0 stevel * Pass errstring as a separate argument. Some higher level routines need 2776 0 stevel * it to be NULL. 2777 0 stevel */ 2778 0 stevel static cfga_err_t 2779 0 stevel stat_plugin_v1(list_stat_t *lstatp, lib_loc_t *libloc_p, char **errstring) 2780 0 stevel { 2781 0 stevel stat_data_list_t *slp, *slp2 = NULL; 2782 0 stevel cfga_err_t rc; 2783 0 stevel 2784 0 stevel /* 2785 0 stevel * allocate stat data buffer and list element 2786 0 stevel */ 2787 0 stevel if ((slp = config_calloc_check(1, sizeof (stat_data_list_t), 2788 0 stevel errstring)) == NULL) { 2789 0 stevel return (CFGA_LIB_ERROR); 2790 0 stevel } 2791 0 stevel 2792 0 stevel /* 2793 0 stevel * Do the stat 2794 0 stevel */ 2795 0 stevel errno = 0; 2796 0 stevel if ((rc = (*(libloc_p->libp->cfga_stat_p))(libloc_p->ap_physical, 2797 0 stevel &slp->stat_data, lstatp->opts, errstring)) != CFGA_OK) { 2798 0 stevel S_FREE(slp); 2799 0 stevel return (rc); 2800 0 stevel } 2801 0 stevel slp->next = NULL; 2802 0 stevel 2803 0 stevel /* 2804 0 stevel * Set up the logical and physical id's. 2805 0 stevel * For v1 interfaces, the generic library (libcfgadm) creates the 2806 0 stevel * ap_ids. mklog() is assumed to have been called in 2807 0 stevel * the caller of this routine. 2808 0 stevel */ 2809 0 stevel (void) snprintf(slp->stat_data.ap_log_id, CFGA_AP_LOG_ID_LEN, "%s", 2810 0 stevel libloc_p->ap_logical); 2811 0 stevel 2812 0 stevel (void) snprintf(slp->stat_data.ap_phys_id, CFGA_AP_PHYS_ID_LEN, "%s", 2813 0 stevel libloc_p->ap_physical); 2814 0 stevel 2815 0 stevel /* 2816 0 stevel * link it in 2817 0 stevel */ 2818 0 stevel if ((slp2 = lstatp->sdl) == NULL) { 2819 0 stevel lstatp->sdl = slp; 2820 0 stevel } else { 2821 0 stevel while (slp2->next != NULL) 2822 0 stevel slp2 = slp2->next; 2823 0 stevel slp2->next = slp; 2824 0 stevel } 2825 0 stevel 2826 0 stevel /* keep count */ 2827 0 stevel (*lstatp->countp)++; 2828 0 stevel 2829 0 stevel return (CFGA_OK); 2830 0 stevel } 2831 0 stevel 2832 0 stevel static cfga_err_t 2833 0 stevel stat_plugin_v2(list_stat_t *lstatp, lib_loc_t *libloc_p, char **errstring) 2834 0 stevel { 2835 0 stevel int i; 2836 0 stevel array_list_t *alp, *alp2 = NULL; 2837 0 stevel cfga_err_t rc; 2838 0 stevel char *class; 2839 0 stevel 2840 0 stevel /* 2841 0 stevel * allocate array list 2842 0 stevel */ 2843 0 stevel if ((alp = config_calloc_check(1, sizeof (array_list_t), 2844 0 stevel errstring)) == NULL) { 2845 0 stevel return (CFGA_LIB_ERROR); 2846 0 stevel } 2847 0 stevel 2848 0 stevel alp->array = NULL; 2849 0 stevel alp->nelem = 0; 2850 0 stevel 2851 0 stevel /* 2852 0 stevel * The listopts argument is currently unused. Use NULL 2853 0 stevel */ 2854 0 stevel errno = 0; 2855 0 stevel if ((rc = (*(libloc_p->libp->cfga_list_ext_p))( 2856 0 stevel libloc_p->ap_physical, &alp->array, &alp->nelem, lstatp->opts, NULL, 2857 0 stevel errstring, lstatp->flags)) != CFGA_OK || alp->nelem <= 0) { 2858 0 stevel S_FREE(alp); 2859 0 stevel return (rc); 2860 0 stevel } 2861 0 stevel alp->next = NULL; 2862 0 stevel 2863 0 stevel /* 2864 0 stevel * Set up the logical and physical id's if necessary. 2865 0 stevel * For v2 interfaces, the generic library (libcfgadm) creates the 2866 0 stevel * ap_ids only if there are no dynamic attachment points and the 2867 0 stevel * plug-in does not create the name itself. mklog() is 2868 0 stevel * assumed to have been called in the caller of this routine. 2869 0 stevel */ 2870 0 stevel if (alp->nelem == 1) { 2871 0 stevel char cphys, clog; 2872 0 stevel 2873 0 stevel clog = (alp->array[0]).ap_log_id[0]; 2874 0 stevel cphys = (alp->array[0]).ap_phys_id[0]; 2875 0 stevel 2876 0 stevel if (clog == '\0') { 2877 0 stevel (void) snprintf((alp->array[0]).ap_log_id, 2878 0 stevel sizeof ((alp->array[0]).ap_log_id), "%s", 2879 0 stevel libloc_p->ap_logical); 2880 0 stevel } 2881 0 stevel 2882 0 stevel if (cphys == '\0') { 2883 0 stevel (void) snprintf((alp->array[0]).ap_phys_id, 2884 0 stevel sizeof ((alp->array[0]).ap_phys_id), "%s", 2885 0 stevel libloc_p->ap_physical); 2886 0 stevel } 2887 0 stevel } 2888 0 stevel 2889 0 stevel if (libloc_p->ap_class[0] == '\0') { 2890 0 stevel class = CFGA_NO_CLASS; 2891 0 stevel } else { 2892 0 stevel class = libloc_p->ap_class; 2893 0 stevel } 2894 0 stevel 2895 0 stevel /* Fill in the class information for all list elements */ 2896 0 stevel for (i = 0; i < alp->nelem; i++) { 2897 0 stevel (void) snprintf((alp->array[i]).ap_class, 2898 0 stevel sizeof ((alp->array[i]).ap_class), "%s", class); 2899 0 stevel } 2900 0 stevel 2901 0 stevel /* 2902 0 stevel * link it in 2903 0 stevel */ 2904 0 stevel if ((alp2 = lstatp->al) == NULL) { 2905 0 stevel lstatp->al = alp; 2906 0 stevel } else { 2907 0 stevel while (alp2->next != NULL) 2908 0 stevel alp2 = alp2->next; 2909 0 stevel alp2->next = alp; 2910 0 stevel } 2911 0 stevel 2912 0 stevel /* keep count */ 2913 0 stevel (*lstatp->countp) += alp->nelem; 2914 0 stevel 2915 0 stevel return (CFGA_OK); 2916 0 stevel } 2917 0 stevel 2918 0 stevel /* 2919 0 stevel * Check if a plugin version is within requested limits. 2920 0 stevel */ 2921 0 stevel static int 2922 0 stevel compat_plugin(vers_req_t *reqp, int plugin_vers) 2923 0 stevel { 2924 0 stevel 2925 0 stevel if (!VALID_HSL_VERS(reqp->v_min) || !VALID_HSL_VERS(reqp->v_max) || 2926 0 stevel !VALID_HSL_VERS(plugin_vers)) { 2927 0 stevel return (0); 2928 0 stevel } 2929 0 stevel 2930 0 stevel if (plugin_vers < reqp->v_min || plugin_vers > reqp->v_max) { 2931 0 stevel return (0); 2932 0 stevel } 2933 0 stevel 2934 0 stevel 2935 0 stevel return (1); 2936 0 stevel } 2937 0 stevel 2938 0 stevel /* 2939 0 stevel * find_arg_type - determine if an argument is an ap_id or an ap_type. 2940 0 stevel * Adapted from cfgadm.c 2941 0 stevel */ 2942 0 stevel static cfga_ap_types_t 2943 0 stevel find_arg_type(const char *ap_id) 2944 0 stevel { 2945 0 stevel struct stat sbuf; 2946 0 stevel cfga_ap_types_t type = UNKNOWN_AP; 2947 0 stevel char *mkr = NULL; 2948 0 stevel size_t len; 2949 0 stevel int size_ap = 0, size_mkr = 0, digit = 0, i = 0; 2950 0 stevel char *cp, path[MAXPATHLEN], ap_base[MAXPATHLEN]; 2951 0 stevel 2952 0 stevel 2953 0 stevel /* 2954 0 stevel * sanity checks 2955 0 stevel */ 2956 0 stevel if (ap_id == NULL || *ap_id == '\0') { 2957 0 stevel 2958 0 stevel return (UNKNOWN_AP); 2959 0 stevel } 2960 0 stevel 2961 0 stevel /* 2962 0 stevel * Extract the base component 2963 0 stevel */ 2964 0 stevel if ((cp = GET_DYN(ap_id)) != NULL) { 2965 0 stevel len = cp - ap_id; 2966 0 stevel } else { 2967 0 stevel len = strlen(ap_id); 2968 0 stevel } 2969 0 stevel 2970 0 stevel if (len >= sizeof (ap_base)) { 2971 0 stevel return (UNKNOWN_AP); 2972 0 stevel } 2973 0 stevel 2974 0 stevel /* Copy only the first "len" chars */ 2975 0 stevel (void) strncpy(ap_base, ap_id, len); 2976 0 stevel ap_base[len] = '\0'; 2977 0 stevel 2978 0 stevel /* 2979 0 stevel * If it starts with a slash and is stat-able its a physical. 2980 0 stevel */ 2981 0 stevel if (*ap_base == '/' && stat(ap_base, &sbuf) == 0) { 2982 0 stevel return (PHYSICAL_AP); 2983 0 stevel } 2984 0 stevel 2985 0 stevel /* 2986 0 stevel * Is this a symlink in CFGA_DEV_DIR ? 2987 0 stevel */ 2988 0 stevel (void) snprintf(path, sizeof (path), "%s%s", 2989 0 stevel CFGA_DEV_DIR SLASH, ap_base); 2990 0 stevel 2991 0 stevel if (lstat(path, &sbuf) == 0 && S_ISLNK(sbuf.st_mode) && 2992 0 stevel stat(path, &sbuf) == 0) { 2993 0 stevel return (LOGICAL_LINK_AP); 2994 0 stevel } 2995 0 stevel 2996 0 stevel /* 2997 0 stevel * Check for ":" which is always present in an ap_id 2998 0 stevel * but not in an ap_type. 2999 0 stevel * we need to check that the characters right before the : are digits 3000 0 stevel * since an ap_id is of the form <name><instance>:<specific ap name> 3001 0 stevel */ 3002 0 stevel if ((mkr = strchr(ap_base, ':')) == NULL) { 3003 0 stevel type = AP_TYPE; 3004 0 stevel } else { 3005 0 stevel size_ap = strlen(ap_base); 3006 0 stevel size_mkr = strlen(mkr); 3007 0 stevel mkr = ap_base; 3008 0 stevel 3009 0 stevel digit = 0; 3010 0 stevel for (i = size_ap - size_mkr - 1; i > 0; i--) { 3011 0 stevel if ((int)isdigit(mkr[i])) { 3012 0 stevel digit++; 3013 0 stevel break; 3014 0 stevel } 3015 0 stevel } 3016 0 stevel if (digit == 0) { 3017 0 stevel type = AP_TYPE; 3018 0 stevel } else { 3019 0 stevel type = LOGICAL_DRV_AP; 3020 0 stevel } 3021 0 stevel } 3022 0 stevel 3023 0 stevel return (type); 3024 0 stevel } 3025 0 stevel 3026 0 stevel /*ARGSUSED*/ 3027 0 stevel static cfga_err_t 3028 0 stevel null_get_cond(lib_loc_t *liblocp, cfga_cond_t *condp, char **errstring) 3029 0 stevel { 3030 0 stevel return (CFGA_OK); 3031 0 stevel } 3032 0 stevel 3033 0 stevel static cfga_err_t 3034 0 stevel get_cond_v1(lib_loc_t *liblocp, cfga_cond_t *condp, char **errstring) 3035 0 stevel { 3036 0 stevel plugin_lib_t *libp; 3037 0 stevel cfga_stat_data_t sdbuf; 3038 0 stevel cfga_err_t rc; 3039 0 stevel 3040 0 stevel 3041 0 stevel libp = liblocp->libp; 3042 0 stevel if (libp->plugin_vers != CFGA_HSL_V1) { 3043 0 stevel return (CFGA_LIB_ERROR); 3044 0 stevel } 3045 0 stevel 3046 0 stevel errno = 0; 3047 0 stevel if ((rc = (*liblocp->libp->cfga_stat_p)( 3048 0 stevel liblocp->ap_physical, &sdbuf, NULL, errstring)) 3049 0 stevel == CFGA_OK) { 3050 0 stevel *condp = sdbuf.ap_cond; 3051 0 stevel } else { 3052 0 stevel *condp = CFGA_COND_UNKNOWN; 3053 0 stevel } 3054 0 stevel 3055 0 stevel return (rc); 3056 0 stevel } 3057 0 stevel 3058 0 stevel static cfga_err_t 3059 0 stevel get_cond_v2(lib_loc_t *liblocp, cfga_cond_t *condp, char **errstring) 3060 0 stevel { 3061 0 stevel int nelem; 3062 0 stevel plugin_lib_t *libp; 3063 0 stevel cfga_list_data_t *ldbufp; 3064 0 stevel cfga_err_t rc; 3065 0 stevel 3066 0 stevel 3067 0 stevel libp = liblocp->libp; 3068 0 stevel if (libp->plugin_vers != CFGA_HSL_V2) { 3069 0 stevel return (CFGA_LIB_ERROR); 3070 0 stevel } 3071 0 stevel 3072 0 stevel errno = 0; 3073 0 stevel nelem = 0; 3074 0 stevel ldbufp = NULL; 3075 0 stevel if ((rc = (*liblocp->libp->cfga_list_ext_p)( 3076 0 stevel liblocp->ap_physical, &ldbufp, &nelem, NULL, NULL, 3077 0 stevel errstring, 0)) == CFGA_OK) { 3078 0 stevel assert(nelem == 1 && ldbufp != NULL); 3079 0 stevel 3080 0 stevel *condp = ldbufp->ap_cond; 3081 0 stevel S_FREE(ldbufp); 3082 0 stevel } else { 3083 0 stevel *condp = CFGA_COND_UNKNOWN; 3084 0 stevel } 3085 0 stevel 3086 0 stevel return (rc); 3087 0 stevel } 3088 0 stevel 3089 0 stevel /* mask represents the flags accepted */ 3090 0 stevel static cfga_err_t 3091 0 stevel check_flags(cfga_flags_t flags, cfga_flags_t mask, char **errstring) 3092 0 stevel { 3093 0 stevel if ((flags & ~mask) != 0) { 3094 0 stevel config_err(0, INVALID_ARGS, errstring); 3095 0 stevel return (CFGA_ERROR); 3096 0 stevel } else { 3097 0 stevel return (CFGA_OK); 3098 0 stevel } 3099 0 stevel } 3100 0 stevel 3101 0 stevel static cfga_err_t 3102 0 stevel check_apids(int num_ap_ids, char *const *ap_ids, char **errstring) 3103 0 stevel { 3104 0 stevel if (num_ap_ids <= 0 || ap_ids == NULL) { 3105 0 stevel config_err(0, INVALID_ARGS, errstring); 3106 0 stevel return (CFGA_ERROR); 3107 0 stevel } else { 3108 0 stevel return (CFGA_OK); 3109 0 stevel } 3110 0 stevel } 3111 0 stevel 3112 0 stevel /* 3113 0 stevel * Returns the class or the empty string if attacment point has 3114 0 stevel * no class. 3115 0 stevel */ 3116 0 stevel static char * 3117 0 stevel get_class(di_minor_t minor) 3118 0 stevel { 3119 0 stevel char *cp, c; 3120 0 stevel size_t len; 3121 0 stevel 3122 0 stevel 3123 0 stevel if (minor == DI_MINOR_NIL) { 3124 0 stevel return (NULL); 3125 0 stevel } 3126 0 stevel 3127 0 stevel cp = di_minor_nodetype(minor); 3128 0 stevel if (cp == NULL) { 3129 0 stevel return (NULL); 3130 0 stevel } 3131 0 stevel 3132 0 stevel len = strlen(DDI_NT_ATTACHMENT_POINT); 3133 0 stevel if (strncmp(cp, DDI_NT_ATTACHMENT_POINT, len)) { 3134 0 stevel return (NULL); 3135 0