1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 #include "cfga_fp.h" 28 29 /* 30 * This file contains helper routines for the FP plugin 31 */ 32 33 #if !defined(TEXT_DOMAIN) 34 #define TEXT_DOMAIN "SYS_TEST" 35 #endif 36 37 typedef struct strlist { 38 const char *str; 39 struct strlist *next; 40 } strlist_t; 41 42 typedef struct { 43 fpcfga_ret_t fp_err; 44 cfga_err_t cfga_err; 45 } errcvt_t; 46 47 typedef struct { 48 fpcfga_cmd_t cmd; 49 int type; 50 int (*fcn)(const devctl_hdl_t); 51 } set_state_cmd_t; 52 53 typedef struct { 54 fpcfga_cmd_t cmd; 55 int type; 56 int (*state_fcn)(const devctl_hdl_t, uint_t *); 57 } get_state_cmd_t; 58 59 /* defines for nftw() */ 60 #define NFTW_DEPTH 1 61 #define NFTW_CONTINUE 0 62 #define NFTW_TERMINATE 1 63 #define NFTW_ERROR -1 64 #define MAX_RETRIES 10 65 66 /* Function prototypes */ 67 static int do_recurse_dev(const char *path, const struct stat *sbuf, 68 int type, struct FTW *ftwp); 69 static fpcfga_recur_t lookup_dev(const char *lpath, void *arg); 70 static void msg_common(char **err_msgpp, int append_newline, int l_errno, 71 va_list ap); 72 static void lunlist_free(struct luninfo_list *lunlist); 73 74 /* Globals */ 75 struct { 76 mutex_t mp; 77 void *arg; 78 fpcfga_recur_t (*fcn)(const char *lpath, void *arg); 79 } nftw_arg = {DEFAULTMUTEX}; 80 81 /* 82 * The string table contains most of the strings used by the fp cfgadm plugin. 83 * All strings which are to be internationalized must be in this table. 84 * Some strings which are not internationalized are also included here. 85 * Arguments to messages are NOT internationalized. 86 */ 87 msgcvt_t str_tbl[] = { 88 89 /* 90 * The first element (ERR_UNKNOWN) MUST always be present in the array. 91 */ 92 #define UNKNOWN_ERR_IDX 0 /* Keep the index in sync */ 93 94 95 /* msg_code num_args, I18N msg_string */ 96 97 /* ERRORS */ 98 {ERR_UNKNOWN, 0, 1, "unknown error"}, 99 {ERR_OP_FAILED, 0, 1, "operation failed"}, 100 {ERR_CMD_INVAL, 0, 1, "invalid command"}, 101 {ERR_NOT_BUSAPID, 0, 1, "not a FP bus apid"}, 102 {ERR_APID_INVAL, 0, 1, "invalid FP ap_id"}, 103 {ERR_NOT_BUSOP, 0, 1, "operation not supported for FC bus"}, 104 {ERR_NOT_DEVOP, 0, 1, "operation not supported for FC device"}, 105 {ERR_UNAVAILABLE, 0, 1, "unavailable"}, 106 {ERR_CTRLR_CRIT, 0, 1, "critical partition controlled by FC HBA"}, 107 {ERR_BUS_GETSTATE, 0, 1, "failed to get state for FC bus"}, 108 {ERR_BUS_NOTCONNECTED, 0, 1, "FC bus not connected"}, 109 {ERR_BUS_CONNECTED, 0, 1, "FC bus not disconnected"}, 110 {ERR_BUS_QUIESCE, 0, 1, "FC bus quiesce failed"}, 111 {ERR_BUS_UNQUIESCE, 0, 1, "FC bus unquiesce failed"}, 112 {ERR_BUS_CONFIGURE, 0, 1, "failed to configure devices on FC bus"}, 113 {ERR_BUS_UNCONFIGURE, 0, 1, "failed to unconfigure FC bus"}, 114 {ERR_DEV_CONFIGURE, 0, 1, "failed to configure FC device"}, 115 {ERR_DEV_UNCONFIGURE, 0, 1, "failed to unconfigure FC device"}, 116 {ERR_FCA_CONFIGURE, 0, 1, "failed to configure ANY device on FCA port"}, 117 {ERR_FCA_UNCONFIGURE, 0, 1, "failed to unconfigure ANY device on FCA port"}, 118 {ERR_DEV_REPLACE, 0, 1, "replace operation failed"}, 119 {ERR_DEV_INSERT, 0, 1, "insert operation failed"}, 120 {ERR_DEV_GETSTATE, 0, 1, "failed to get state for FC device"}, 121 {ERR_RESET, 0, 1, "reset failed"}, 122 {ERR_LIST, 0, 1, "list operation failed"}, 123 {ERR_SIG_STATE, 0, 1, "could not restore signal disposition"}, 124 {ERR_MAYBE_BUSY, 0, 1, "device may be busy"}, 125 {ERR_BUS_DEV_MISMATCH, 0, 1, "mismatched FC bus and device"}, 126 {ERR_MEM_ALLOC, 0, 1, "Failed to allocated memory"}, 127 {ERR_DEVCTL_OFFLINE, 0, 1, "failed to offline device"}, 128 {ERR_UPD_REP, 0, 1, "Repository update failed"}, 129 {ERR_CONF_OK_UPD_REP, 0, 1, 130 "Configuration successful, but Repository update failed"}, 131 {ERR_UNCONF_OK_UPD_REP, 0, 1, 132 "Unconfiguration successful, but Repository update failed"}, 133 {ERR_PARTIAL_SUCCESS, 0, 1, 134 "Operation partially successful. Some failures seen"}, 135 {ERR_HBA_LOAD_LIBRARY, 0, 1, 136 "HBA load library failed"}, 137 {ERR_MATCHING_HBA_PORT, 0, 1, 138 "No match HBA port found"}, 139 {ERR_NO_ADAPTER_FOUND, 0, 1, 140 "No Fibre Channel adpaters found"}, 141 142 /* Errors with arguments */ 143 {ERRARG_OPT_INVAL, 1, 1, "invalid option: "}, 144 {ERRARG_HWCMD_INVAL, 1, 1, "invalid command: "}, 145 {ERRARG_DEVINFO, 1, 1, "libdevinfo failed on path: "}, 146 {ERRARG_NOT_IN_DEVLIST, 1, 1, "Device not found in fabric device list: "}, 147 {ERRARG_NOT_IN_DEVINFO, 1, 1, "Could not find entry in devinfo tree: "}, 148 {ERRARG_DI_GET_PROP, 1, 1, "Could not get libdevinfo property: "}, 149 {ERRARG_DC_DDEF_ALLOC, 1, 1, "failed to alloc ddef space: "}, 150 {ERRARG_DC_BYTE_ARRAY, 1, 1, "failed to add property: "}, 151 {ERRARG_DC_BUS_ACQUIRE, 1, 1, "failed to acquire bus handle: "}, 152 {ERRARG_BUS_DEV_CREATE, 1, 1, "failed to create device node: "}, 153 {ERRARG_BUS_DEV_CREATE_UNKNOWN, 1, 1, 154 "failed to create device node... Device may be unconfigurable: "}, 155 {ERRARG_DEV_ACQUIRE, 1, 1, "device acquire operation failed: "}, 156 {ERRARG_DEV_REMOVE, 1, 1, "remove operation failed: "}, 157 158 /* Fibre Channel operation Errors */ 159 {ERR_FC, 0, 1, "FC error"}, 160 {ERR_FC_GET_DEVLIST, 0, 1, "Failed to get fabric device list"}, 161 {ERR_FC_GET_NEXT_DEV, 0, 1, "Failed to get next device on device map"}, 162 {ERR_FC_GET_FIRST_DEV, 0, 1, "Failed to get first device on device map"}, 163 {ERRARG_FC_DEV_MAP_INIT, 1, 1, 164 "Failed to initialize device map for: "}, 165 {ERRARG_FC_PROP_LOOKUP_BYTES, 1, 1, "Failed to get property of "}, 166 {ERRARG_FC_INQUIRY, 1, 1, "inquiry failed: "}, 167 {ERRARG_FC_REP_LUNS, 1, 1, "report LUNs failed: "}, 168 {ERRARG_FC_TOPOLOGY, 1, 1, "failed to get port topology: "}, 169 {ERRARG_PATH_TOO_LONG, 1, 1, "Path length exceeds max possible: "}, 170 {ERRARG_INVALID_PATH, 1, 1, "Invalid path: "}, 171 {ERRARG_OPENDIR, 1, 1, "failure opening directory: "}, 172 173 /* MPXIO Errors */ 174 {ERRARG_VHCI_GET_PATHLIST, 1, 1, "failed to get path list from vHCI: "}, 175 {ERRARG_XPORT_NOT_IN_PHCI_LIST, 1, 1, "Transport not in pHCI list: "}, 176 177 /* RCM Errors */ 178 {ERR_RCM_HANDLE, 0, 1, "cannot get RCM handle"}, 179 {ERRARG_RCM_SUSPEND, 1, 1, "failed to suspend: "}, 180 {ERRARG_RCM_RESUME, 1, 1, "failed to resume: "}, 181 {ERRARG_RCM_OFFLINE, 1, 1, "failed to offline: "}, 182 {ERRARG_RCM_ONLINE, 1, 1, "failed to online: "}, 183 {ERRARG_RCM_REMOVE, 1, 1, "failed to remove: "}, 184 {ERRARG_RCM_INFO, 1, 1, "failed to query: "}, 185 186 /* Commands */ 187 {CMD_INSERT_DEV, 0, 0, "insert_device"}, 188 {CMD_REMOVE_DEV, 0, 0, "remove_device"}, 189 {CMD_REPLACE_DEV, 0, 0, "replace_device"}, 190 {CMD_RESET_DEV, 0, 0, "reset_device"}, 191 {CMD_RESET_BUS, 0, 0, "reset_bus"}, 192 {CMD_RESET_ALL, 0, 0, "reset_all"}, 193 194 /* help messages */ 195 {MSG_HELP_HDR, 0, 1, "\nfp attachment point specific options:\n"}, 196 {MSG_HELP_USAGE, 0, 0, 197 "\t-c configure -o force_update ap_id [ap_id..]\n" 198 "\t-c configure -o no_update ap_id [ap_id...]\n" 199 "\t-c unconfigure -o force_update ap_id [ap_id... ]\n" 200 "\t-c unconfigure -o no_update ap_id [ap_id... ]\n"}, 201 202 /* hotplug messages */ 203 {MSG_INSDEV, 1, 1, "Adding device to FC HBA: "}, 204 {MSG_RMDEV, 1, 1, "Removing FC device: "}, 205 {MSG_REPLDEV, 1, 1, "Replacing FC device: "}, 206 207 /* Hotplugging confirmation prompts */ 208 {CONF_QUIESCE_1, 1, 1, 209 "This operation will suspend activity on FC bus: "}, 210 211 {CONF_QUIESCE_2, 0, 1, "\nContinue"}, 212 213 {CONF_UNQUIESCE, 0, 1, 214 "FC bus quiesced successfully.\n" 215 "It is now safe to proceed with hotplug operation." 216 "\nEnter y if operation is complete or n to abort"}, 217 218 /* Misc. */ 219 {WARN_DISCONNECT, 0, 1, 220 "WARNING: Disconnecting critical partitions may cause system hang." 221 "\nContinue"} 222 }; 223 224 225 #define N_STRS (sizeof (str_tbl) / sizeof (str_tbl[0])) 226 227 #define GET_MSG_NARGS(i) (str_tbl[msg_idx(i)].nargs) 228 #define GET_MSG_INTL(i) (str_tbl[msg_idx(i)].intl) 229 230 static errcvt_t err_cvt_tbl[] = { 231 { FPCFGA_OK, CFGA_OK }, 232 { FPCFGA_LIB_ERR, CFGA_LIB_ERROR }, 233 { FPCFGA_APID_NOEXIST, CFGA_APID_NOEXIST }, 234 { FPCFGA_NACK, CFGA_NACK }, 235 { FPCFGA_BUSY, CFGA_BUSY }, 236 { FPCFGA_SYSTEM_BUSY, CFGA_SYSTEM_BUSY }, 237 { FPCFGA_OPNOTSUPP, CFGA_OPNOTSUPP }, 238 { FPCFGA_PRIV, CFGA_PRIV }, 239 { FPCFGA_UNKNOWN_ERR, CFGA_ERROR }, 240 { FPCFGA_ERR, CFGA_ERROR } 241 }; 242 243 #define N_ERR_CVT_TBL (sizeof (err_cvt_tbl)/sizeof (err_cvt_tbl[0])) 244 245 #define DEV_OP 0 246 #define BUS_OP 1 247 static set_state_cmd_t set_state_cmds[] = { 248 249 { FPCFGA_BUS_QUIESCE, BUS_OP, devctl_bus_quiesce }, 250 { FPCFGA_BUS_UNQUIESCE, BUS_OP, devctl_bus_unquiesce }, 251 { FPCFGA_BUS_CONFIGURE, BUS_OP, devctl_bus_configure }, 252 { FPCFGA_BUS_UNCONFIGURE, BUS_OP, devctl_bus_unconfigure }, 253 { FPCFGA_RESET_BUS, BUS_OP, devctl_bus_reset }, 254 { FPCFGA_RESET_ALL, BUS_OP, devctl_bus_resetall }, 255 { FPCFGA_DEV_CONFIGURE, DEV_OP, devctl_device_online }, 256 { FPCFGA_DEV_UNCONFIGURE, DEV_OP, devctl_device_offline }, 257 { FPCFGA_DEV_REMOVE, DEV_OP, devctl_device_remove }, 258 { FPCFGA_RESET_DEV, DEV_OP, devctl_device_reset } 259 260 }; 261 262 #define N_SET_STATE_CMDS (sizeof (set_state_cmds)/sizeof (set_state_cmds[0])) 263 264 static get_state_cmd_t get_state_cmds[] = { 265 { FPCFGA_BUS_GETSTATE, BUS_OP, devctl_bus_getstate }, 266 { FPCFGA_DEV_GETSTATE, DEV_OP, devctl_device_getstate } 267 }; 268 269 #define N_GET_STATE_CMDS (sizeof (get_state_cmds)/sizeof (get_state_cmds[0])) 270 271 /* Order is important. Earlier directories are searched first */ 272 static const char *dev_dir_hints[] = { 273 CFGA_DEV_DIR, 274 DEV_RMT, 275 DEV_DSK, 276 DEV_RDSK, 277 DEV_DIR 278 }; 279 280 #define N_DEV_DIR_HINTS (sizeof (dev_dir_hints) / sizeof (dev_dir_hints[0])) 281 282 283 /* 284 * Routine to search the /dev directory or a subtree of /dev. 285 * If the entire /dev hierarchy is to be searched, the most likely directories 286 * are searched first. 287 */ 288 fpcfga_ret_t 289 recurse_dev( 290 const char *basedir, 291 void *arg, 292 fpcfga_recur_t (*fcn)(const char *lpath, void *arg)) 293 { 294 int i, rv = NFTW_ERROR; 295 296 (void) mutex_lock(&nftw_arg.mp); 297 298 nftw_arg.arg = arg; 299 nftw_arg.fcn = fcn; 300 301 if (strcmp(basedir, DEV_DIR)) { 302 errno = 0; 303 rv = nftw(basedir, do_recurse_dev, NFTW_DEPTH, FTW_PHYS); 304 goto out; 305 } 306 307 /* 308 * Search certain selected subdirectories first if basedir == "/dev". 309 * Ignore errors as some of these directories may not exist. 310 */ 311 for (i = 0; i < N_DEV_DIR_HINTS; i++) { 312 errno = 0; 313 if ((rv = nftw(dev_dir_hints[i], do_recurse_dev, NFTW_DEPTH, 314 FTW_PHYS)) == NFTW_TERMINATE) { 315 break; 316 } 317 } 318 319 /*FALLTHRU*/ 320 out: 321 (void) mutex_unlock(&nftw_arg.mp); 322 return (rv == NFTW_ERROR ? FPCFGA_ERR : FPCFGA_OK); 323 } 324 325 /*ARGSUSED*/ 326 static int 327 do_recurse_dev( 328 const char *path, 329 const struct stat *sbuf, 330 int type, 331 struct FTW *ftwp) 332 { 333 /* We want only VALID symlinks */ 334 if (type != FTW_SL) { 335 return (NFTW_CONTINUE); 336 } 337 338 assert(nftw_arg.fcn != NULL); 339 340 if (nftw_arg.fcn(path, nftw_arg.arg) == FPCFGA_TERMINATE) { 341 /* terminate prematurely, but may not be error */ 342 errno = 0; 343 return (NFTW_TERMINATE); 344 } else { 345 return (NFTW_CONTINUE); 346 } 347 } 348 349 cfga_err_t 350 err_cvt(fpcfga_ret_t fp_err) 351 { 352 int i; 353 354 for (i = 0; i < N_ERR_CVT_TBL; i++) { 355 if (err_cvt_tbl[i].fp_err == fp_err) { 356 return (err_cvt_tbl[i].cfga_err); 357 } 358 } 359 360 return (CFGA_ERROR); 361 } 362 363 /* 364 * Removes duplicate slashes from a pathname and any trailing slashes. 365 * Returns "/" if input is "/" 366 */ 367 char * 368 pathdup(const char *path, int *l_errnop) 369 { 370 int prev_was_slash = 0; 371 char c, *dp = NULL, *dup = NULL; 372 const char *sp = NULL; 373 374 *l_errnop = 0; 375 376 if (path == NULL) { 377 return (NULL); 378 } 379 380 if ((dup = calloc(1, strlen(path) + 1)) == NULL) { 381 *l_errnop = errno; 382 return (NULL); 383 } 384 385 prev_was_slash = 0; 386 for (sp = path, dp = dup; (c = *sp) != '\0'; sp++) { 387 if (!prev_was_slash || c != '/') { 388 *dp++ = c; 389 } 390 if (c == '/') { 391 prev_was_slash = 1; 392 } else { 393 prev_was_slash = 0; 394 } 395 } 396 397 /* Remove trailing slash except if it is the first char */ 398 if (prev_was_slash && dp != dup && dp - 1 != dup) { 399 *(--dp) = '\0'; 400 } else { 401 *dp = '\0'; 402 } 403 404 return (dup); 405 } 406 407 fpcfga_ret_t 408 apidt_create(const char *ap_id, apid_t *apidp, char **errstring) 409 { 410 char *xport_phys = NULL, *dyn = NULL; 411 char *dyncomp = NULL; 412 struct luninfo_list *lunlistp = NULL; 413 int l_errno = 0; 414 size_t len = 0; 415 fpcfga_ret_t ret; 416 417 if ((xport_phys = pathdup(ap_id, &l_errno)) == NULL) { 418 cfga_err(errstring, l_errno, ERR_OP_FAILED, 0); 419 return (FPCFGA_LIB_ERR); 420 } 421 422 /* Extract the base(hba) and dynamic(device) component if any */ 423 dyncomp = NULL; 424 if ((dyn = GET_DYN(xport_phys)) != NULL) { 425 len = strlen(DYN_TO_DYNCOMP(dyn)) + 1; 426 dyncomp = calloc(1, len); 427 if (dyncomp == NULL) { 428 cfga_err(errstring, errno, ERR_OP_FAILED, 0); 429 ret = FPCFGA_LIB_ERR; 430 goto err; 431 } 432 (void) strcpy(dyncomp, DYN_TO_DYNCOMP(dyn)); 433 if (GET_LUN_DYN(dyncomp)) { 434 ret = FPCFGA_APID_NOEXIST; 435 goto err; 436 } 437 438 /* Remove the dynamic component from the base. */ 439 *dyn = '\0'; 440 } 441 442 /* Get the path of dynamic attachment point if already configured. */ 443 if (dyncomp != NULL) { 444 ret = dyn_apid_to_path(xport_phys, dyncomp, 445 &lunlistp, &l_errno); 446 if ((ret != FPCFGA_OK) && (ret != FPCFGA_APID_NOCONFIGURE)) { 447 cfga_err(errstring, l_errno, ERR_OP_FAILED, 0); 448 goto err; 449 } 450 } 451 452 assert(xport_phys != NULL); 453 454 apidp->xport_phys = xport_phys; 455 apidp->dyncomp = dyncomp; 456 apidp->lunlist = lunlistp; 457 apidp->flags = 0; 458 459 return (FPCFGA_OK); 460 461 err: 462 S_FREE(xport_phys); 463 S_FREE(dyncomp); 464 lunlist_free(lunlistp); 465 return (ret); 466 } 467 468 static void 469 lunlist_free(struct luninfo_list *lunlist) 470 { 471 struct luninfo_list *lunp; 472 473 while (lunlist != NULL) { 474 lunp = lunlist->next; 475 S_FREE(lunlist->path); 476 S_FREE(lunlist); 477 lunlist = lunp; 478 } 479 } 480 481 void 482 apidt_free(apid_t *apidp) 483 { 484 if (apidp == NULL) 485 return; 486 487 S_FREE(apidp->xport_phys); 488 S_FREE(apidp->dyncomp); 489 lunlist_free(apidp->lunlist); 490 } 491 492 fpcfga_ret_t 493 walk_tree( 494 const char *physpath, 495 void *arg, 496 uint_t init_flags, 497 walkarg_t *up, 498 fpcfga_cmd_t cmd, 499 int *l_errnop) 500 { 501 int rv; 502 di_node_t root, tree_root, fpnode; 503 char *root_path, *cp = NULL; 504 char *devfs_fp_path; 505 size_t len; 506 fpcfga_ret_t ret; 507 int found = 0; 508 509 *l_errnop = 0; 510 511 if ((root_path = strdup(physpath)) == NULL) { 512 *l_errnop = errno; 513 return (FPCFGA_LIB_ERR); 514 } 515 516 /* Fix up path for di_init() */ 517 len = strlen(DEVICES_DIR); 518 if (strncmp(root_path, DEVICES_DIR SLASH, 519 len + strlen(SLASH)) == 0) { 520 cp = root_path + len; 521 (void) memmove(root_path, cp, strlen(cp) + 1); 522 } else if (*root_path != '/') { 523 *l_errnop = 0; 524 ret = FPCFGA_ERR; 525 goto out; 526 } 527 528 /* Remove dynamic component if any */ 529 if ((cp = GET_DYN(root_path)) != NULL) { 530 *cp = '\0'; 531 } 532 533 /* Remove minor name if any */ 534 if ((cp = strrchr(root_path, ':')) != NULL) { 535 *cp = '\0'; 536 } 537 538 /* 539 * If force_flag is set 540 * do di_init with DINFOFORCE flag and get to the input fp node 541 * from the device tree. 542 * 543 * In order to get the link between path_info node and scsi_vhci node 544 * it is required to take the snapshot of the whole device tree. 545 * this behavior of libdevinfo is inefficient. For a specific 546 * fca port DINFOPROP was sufficient on the fca path prior to 547 * scsi_vhci node support. 548 * 549 */ 550 if ((up->flags & FLAG_DEVINFO_FORCE) == FLAG_DEVINFO_FORCE) { 551 tree_root = di_init("/", init_flags | DINFOFORCE); 552 } else { 553 tree_root = di_init("/", init_flags); 554 } 555 556 if (tree_root == DI_NODE_NIL) { 557 *l_errnop = errno; 558 ret = FPCFGA_LIB_ERR; 559 goto out; 560 } 561 562 fpnode = di_drv_first_node("fp", tree_root); 563 564 while (fpnode) { 565 devfs_fp_path = di_devfs_path(fpnode); 566 if ((devfs_fp_path) && !(strncmp(devfs_fp_path, 567 root_path, strlen(root_path)))) { 568 found = 1; 569 di_devfs_path_free(devfs_fp_path); 570 break; 571 } 572 di_devfs_path_free(devfs_fp_path); 573 fpnode = di_drv_next_node(fpnode); 574 } 575 if (!(found)) { 576 ret = FPCFGA_LIB_ERR; 577 goto out; 578 } else { 579 root = fpnode; 580 } 581 582 /* Walk the tree */ 583 errno = 0; 584 if (cmd == FPCFGA_WALK_NODE) { 585 rv = di_walk_node(root, up->walkmode.node_args.flags, arg, 586 up->walkmode.node_args.fcn); 587 } else { 588 assert(cmd == FPCFGA_WALK_MINOR); 589 rv = di_walk_minor(root, up->walkmode.minor_args.nodetype, 0, 590 arg, up->walkmode.minor_args.fcn); 591 } 592 593 if (rv != 0) { 594 *l_errnop = errno; 595 ret = FPCFGA_LIB_ERR; 596 } else { 597 if ((up->flags & FLAG_PATH_INFO_WALK) == FLAG_PATH_INFO_WALK) { 598 ret = stat_path_info_node(root, arg, l_errnop); 599 } else { 600 *l_errnop = 0; 601 ret = FPCFGA_OK; 602 } 603 } 604 605 di_fini(tree_root); 606 607 /*FALLTHRU*/ 608 out: 609 S_FREE(root_path); 610 return (ret); 611 } 612 613 614 int 615 msg_idx(msgid_t msgid) 616 { 617 int idx = 0; 618 619 /* The string table index and the error id may or may not be same */ 620 if (msgid >= 0 && msgid <= N_STRS - 1 && 621 str_tbl[msgid].msgid == msgid) { 622 idx = msgid; 623 } else { 624 for (idx = 0; idx < N_STRS; idx++) { 625 if (str_tbl[idx].msgid == msgid) 626 break; 627 } 628 if (idx >= N_STRS) { 629 idx = UNKNOWN_ERR_IDX; 630 } 631 } 632 633 return (idx); 634 } 635 636 /* 637 * cfga_err() accepts a variable number of message IDs and constructs 638 * a corresponding error string which is returned via the errstring argument. 639 * cfga_err() calls dgettext() to internationalize proper messages. 640 * May be called with a NULL argument. 641 */ 642 void 643 cfga_err(char **errstring, int l_errno, ...) 644 { 645 va_list ap; 646 int append_newline = 0; 647 char *tmp_str, *tmp_err_str = NULL; 648 649 if (errstring == NULL) { 650 return; 651 } 652 653 /* 654 * Don't append a newline, the application (for example cfgadm) 655 * should do that. 656 */ 657 append_newline = 0; 658 659 va_start(ap, l_errno); 660 msg_common(&tmp_err_str, append_newline, l_errno, ap); 661 va_end(ap); 662 663 if (*errstring == NULL) { 664 *errstring = tmp_err_str; 665 return; 666 } 667 668 /* 669 * *errstring != NULL 670 * There was something in errstring prior to this call. 671 * So, concatenate the old and new strings 672 */ 673 if ((tmp_str = calloc(1, 674 strlen(*errstring) + strlen(tmp_err_str) + 2)) == NULL) { 675 /* In case of error, retain only the earlier message */ 676 free(tmp_err_str); 677 return; 678 } 679 680 sprintf(tmp_str, "%s\n%s", *errstring, tmp_err_str); 681 free(tmp_err_str); 682 free(*errstring); 683 *errstring = tmp_str; 684 } 685 686 /* 687 * This routine accepts a variable number of message IDs and constructs 688 * a corresponding message string which is printed via the message print 689 * routine argument. 690 */ 691 void 692 cfga_msg(struct cfga_msg *msgp, ...) 693 { 694 char *p = NULL; 695 int append_newline = 0, l_errno = 0; 696 va_list ap; 697 698 if (msgp == NULL || msgp->message_routine == NULL) { 699 return; 700 } 701 702 /* Append a newline after message */ 703 append_newline = 1; 704 l_errno = 0; 705 706 va_start(ap, msgp); 707 msg_common(&p, append_newline, l_errno, ap); 708 va_end(ap); 709 710 (void) (*msgp->message_routine)(msgp->appdata_ptr, p); 711 712 S_FREE(p); 713 } 714 715 /* 716 * Get internationalized string corresponding to message id 717 * Caller must free the memory allocated. 718 */ 719 char * 720 cfga_str(int append_newline, ...) 721 { 722 char *p = NULL; 723 int l_errno = 0; 724 va_list ap; 725 726 va_start(ap, append_newline); 727 msg_common(&p, append_newline, l_errno, ap); 728 va_end(ap); 729 730 return (p); 731 } 732 733 static void 734 msg_common(char **msgpp, int append_newline, int l_errno, va_list ap) 735 { 736 int a = 0; 737 size_t len = 0; 738 int i = 0, n = 0; 739 char *s = NULL, *t = NULL; 740 strlist_t dummy; 741 strlist_t *savep = NULL, *sp = NULL, *tailp = NULL; 742 743 if (*msgpp != NULL) { 744 return; 745 } 746 747 dummy.next = NULL; 748 tailp = &dummy; 749 for (len = 0; (a = va_arg(ap, int)) != 0; ) { 750 n = GET_MSG_NARGS(a); /* 0 implies no additional args */ 751 for (i = 0; i <= n; i++) { 752 sp = calloc(1, sizeof (*sp)); 753 if (sp == NULL) { 754 goto out; 755 } 756 if (i == 0 && GET_MSG_INTL(a)) { 757 sp->str = dgettext(TEXT_DOMAIN, GET_MSG_STR(a)); 758 } else if (i == 0) { 759 sp->str = GET_MSG_STR(a); 760 } else { 761 sp->str = va_arg(ap, char *); 762 } 763 len += (strlen(sp->str)); 764 sp->next = NULL; 765 tailp->next = sp; 766 tailp = sp; 767 } 768 } 769 770 len += 1; /* terminating NULL */ 771 772 s = t = NULL; 773 if (l_errno) { 774 s = dgettext(TEXT_DOMAIN, ": "); 775 t = S_STR(strerror(l_errno)); 776 if (s != NULL && t != NULL) { 777 len += strlen(s) + strlen(t); 778 } 779 } 780 781 if (append_newline) { 782 len++; 783 } 784 785 if ((*msgpp = calloc(1, len)) == NULL) { 786 goto out; 787 } 788 789 **msgpp = '\0'; 790 for (sp = dummy.next; sp != NULL; sp = sp->next) { 791 (void) strcat(*msgpp, sp->str); 792 } 793 794 if (s != NULL && t != NULL) { 795 (void) strcat(*msgpp, s); 796 (void) strcat(*msgpp, t); 797 } 798 799 if (append_newline) { 800 (void) strcat(*msgpp, dgettext(TEXT_DOMAIN, "\n")); 801 } 802 803 /* FALLTHROUGH */ 804 out: 805 sp = dummy.next; 806 while (sp != NULL) { 807 savep = sp->next; 808 S_FREE(sp); 809 sp = savep; 810 } 811 } 812 813 fpcfga_ret_t 814 devctl_cmd( 815 const char *physpath, 816 fpcfga_cmd_t cmd, 817 uint_t *statep, 818 int *l_errnop) 819 { 820 int rv = -1, i, type; 821 devctl_hdl_t hdl = NULL; 822 char *cp = NULL, *path = NULL; 823 int (*func)(const devctl_hdl_t); 824 int (*state_func)(const devctl_hdl_t, uint_t *); 825 826 *l_errnop = 0; 827 828 if (statep != NULL) *statep = 0; 829 830 func = NULL; 831 state_func = NULL; 832 type = 0; 833 834 for (i = 0; i < N_GET_STATE_CMDS; i++) { 835 if (get_state_cmds[i].cmd == cmd) { 836 state_func = get_state_cmds[i].state_fcn; 837 type = get_state_cmds[i].type; 838 assert(statep != NULL); 839 break; 840 } 841 } 842 843 if (state_func == NULL) { 844 for (i = 0; i < N_SET_STATE_CMDS; i++) { 845 if (set_state_cmds[i].cmd == cmd) { 846 func = set_state_cmds[i].fcn; 847 type = set_state_cmds[i].type; 848 assert(statep == NULL); 849 break; 850 } 851 } 852 } 853 854 assert(type == BUS_OP || type == DEV_OP); 855 856 if (func == NULL && state_func == NULL) { 857 return (FPCFGA_ERR); 858 } 859 860 /* 861 * Fix up path for calling devctl. 862 */ 863 if ((path = strdup(physpath)) == NULL) { 864 *l_errnop = errno; 865 return (FPCFGA_LIB_ERR); 866 } 867 868 /* Remove dynamic component if any */ 869 if ((cp = GET_DYN(path)) != NULL) { 870 *cp = '\0'; 871 } 872 873 /* Remove minor name */ 874 if ((cp = strrchr(path, ':')) != NULL) { 875 *cp = '\0'; 876 } 877 878 errno = 0; 879 880 if (type == BUS_OP) { 881 hdl = devctl_bus_acquire(path, 0); 882 } else { 883 hdl = devctl_device_acquire(path, 0); 884 } 885 *l_errnop = errno; 886 887 S_FREE(path); 888 889 if (hdl == NULL) { 890 return (FPCFGA_ERR); 891 } 892 893 errno = 0; 894 /* Only getstate functions require a second argument */ 895 if (func != NULL && statep == NULL) { 896 rv = func(hdl); 897 *l_errnop = errno; 898 } else if (state_func != NULL && statep != NULL) { 899 rv = state_func(hdl, statep); 900 *l_errnop = errno; 901 } else { 902 rv = -1; 903 *l_errnop = 0; 904 } 905 906 devctl_release(hdl); 907 908 return ((rv == -1) ? FPCFGA_ERR : FPCFGA_OK); 909 } 910 911 /* 912 * Is device in a known state ? (One of BUSY, ONLINE, OFFLINE) 913 * BUSY --> One or more device special files are open. Implies online 914 * ONLINE --> driver attached 915 * OFFLINE --> CF1 with offline flag set. 916 * UNKNOWN --> None of the above 917 */ 918 int 919 known_state(di_node_t node) 920 { 921 uint_t state; 922 923 state = di_state(node); 924 925 /* 926 * CF1 without offline flag set is considered unknown state. 927 * We are in a known state if either CF2 (driver attached) or 928 * offline. 929 */ 930 if ((state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE || 931 (state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) { 932 return (1); 933 } 934 935 return (0); 936 } 937 938 void 939 list_free(ldata_list_t **llpp) 940 { 941 ldata_list_t *lp, *olp; 942 943 lp = *llpp; 944 while (lp != NULL) { 945 olp = lp; 946 lp = olp->next; 947 S_FREE(olp); 948 } 949 950 *llpp = NULL; 951 } 952 953 /* 954 * Obtain the devlink from a /devices path 955 */ 956 fpcfga_ret_t 957 physpath_to_devlink( 958 const char *basedir, 959 char *xport_phys, 960 char **xport_logpp, 961 int *l_errnop, 962 int match_minor) 963 { 964 pathm_t pmt = {NULL}; 965 fpcfga_ret_t ret; 966 967 pmt.phys = xport_phys; 968 pmt.ret = FPCFGA_NO_REC; 969 pmt.match_minor = match_minor; 970 971 /* 972 * Search the /dev hierarchy starting at basedir. 973 */ 974 ret = recurse_dev(basedir, &pmt, lookup_dev); 975 if (ret == FPCFGA_OK && (ret = pmt.ret) == FPCFGA_OK) { 976 assert(pmt.log != NULL); 977 *xport_logpp = pmt.log; 978 } else { 979 if (pmt.log != NULL) { 980 S_FREE(pmt.log); 981 } 982 983 *xport_logpp = NULL; 984 *l_errnop = pmt.l_errno; 985 } 986 987 return (ret); 988 } 989 990 static fpcfga_recur_t 991 lookup_dev(const char *lpath, void *arg) 992 { 993 char ppath[PATH_MAX]; 994 pathm_t *pmtp = (pathm_t *)arg; 995 996 if (realpath(lpath, ppath) == NULL) { 997 return (FPCFGA_CONTINUE); 998 } 999 1000 ppath[sizeof (ppath) - 1] = '\0'; 1001 1002 /* Is this the physical path we are looking for */ 1003 if (dev_cmp(ppath, pmtp->phys, pmtp->match_minor)) { 1004 return (FPCFGA_CONTINUE); 1005 } 1006 1007 if ((pmtp->log = strdup(lpath)) == NULL) { 1008 pmtp->l_errno = errno; 1009 pmtp->ret = FPCFGA_LIB_ERR; 1010 } else { 1011 pmtp->ret = FPCFGA_OK; 1012 } 1013 1014 return (FPCFGA_TERMINATE); 1015 } 1016 1017 /* Compare HBA physical ap_id and device path */ 1018 int 1019 hba_dev_cmp(const char *hba, const char *devpath) 1020 { 1021 char *cp = NULL; 1022 int rv; 1023 size_t hba_len, dev_len; 1024 char l_hba[MAXPATHLEN], l_dev[MAXPATHLEN]; 1025 1026 (void) snprintf(l_hba, sizeof (l_hba), "%s", hba); 1027 (void) snprintf(l_dev, sizeof (l_dev), "%s", devpath); 1028 1029 /* Remove dynamic component if any */ 1030 if ((cp = GET_DYN(l_hba)) != NULL) { 1031 *cp = '\0'; 1032 } 1033 1034 if ((cp = GET_DYN(l_dev)) != NULL) { 1035 *cp = '\0'; 1036 } 1037 1038 1039 /* Remove minor names */ 1040 if ((cp = strrchr(l_hba, ':')) != NULL) { 1041 *cp = '\0'; 1042 } 1043 1044 if ((cp = strrchr(l_dev, ':')) != NULL) { 1045 *cp = '\0'; 1046 } 1047 1048 hba_len = strlen(l_hba); 1049 dev_len = strlen(l_dev); 1050 1051 /* Check if HBA path is component of device path */ 1052 if (rv = strncmp(l_hba, l_dev, hba_len)) { 1053 return (rv); 1054 } 1055 1056 /* devpath must have '/' and 1 char in addition to hba path */ 1057 if (dev_len >= hba_len + 2 && l_dev[hba_len] == '/') { 1058 return (0); 1059 } else { 1060 return (-1); 1061 } 1062 } 1063 1064 int 1065 dev_cmp(const char *dev1, const char *dev2, int match_minor) 1066 { 1067 char l_dev1[MAXPATHLEN], l_dev2[MAXPATHLEN]; 1068 char *mn1, *mn2; 1069 int rv; 1070 1071 (void) snprintf(l_dev1, sizeof (l_dev1), "%s", dev1); 1072 (void) snprintf(l_dev2, sizeof (l_dev2), "%s", dev2); 1073 1074 if ((mn1 = GET_DYN(l_dev1)) != NULL) { 1075 *mn1 = '\0'; 1076 } 1077 1078 if ((mn2 = GET_DYN(l_dev2)) != NULL) { 1079 *mn2 = '\0'; 1080 } 1081 1082 /* Separate out the minor names */ 1083 if ((mn1 = strrchr(l_dev1, ':')) != NULL) { 1084 *mn1++ = '\0'; 1085 } 1086 1087 if ((mn2 = strrchr(l_dev2, ':')) != NULL) { 1088 *mn2++ = '\0'; 1089 } 1090 1091 if ((rv = strcmp(l_dev1, l_dev2)) != 0 || !match_minor) { 1092 return (rv); 1093 } 1094 1095 /* 1096 * Compare minor names 1097 */ 1098 if (mn1 == NULL && mn2 == NULL) { 1099 return (0); 1100 } else if (mn1 == NULL) { 1101 return (-1); 1102 } else if (mn2 == NULL) { 1103 return (1); 1104 } else { 1105 return (strcmp(mn1, mn2)); 1106 } 1107 } 1108 1109 /* 1110 * Returns non-zero on failure (aka, HBA_STATUS_ERROR_* 1111 * Will handle retries if applicable. 1112 */ 1113 int 1114 getAdapterAttrs(HBA_HANDLE handle, HBA_ADAPTERATTRIBUTES *attrs) 1115 { 1116 int count = 0; 1117 HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */ 1118 1119 /* Loop as long as we have a retryable error */ 1120 while ((status == HBA_STATUS_ERROR_TRY_AGAIN || 1121 status == HBA_STATUS_ERROR_BUSY) && 1122 count++ < HBA_MAX_RETRIES) { 1123 status = HBA_GetAdapterAttributes(handle, attrs); 1124 if (status == HBA_STATUS_OK) { 1125 break; 1126 } 1127 sleep(1); 1128 } 1129 return (status); 1130 } 1131 1132 /* 1133 * Returns non-zero on failure (aka, HBA_STATUS_ERROR_* 1134 * Will handle retries if applicable. 1135 */ 1136 int 1137 getPortAttrsByWWN(HBA_HANDLE handle, HBA_WWN wwn, HBA_PORTATTRIBUTES *attrs) 1138 { 1139 int count = 0; 1140 HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */ 1141 1142 /* Loop as long as we have a retryable error */ 1143 while ((status == HBA_STATUS_ERROR_TRY_AGAIN || 1144 status == HBA_STATUS_ERROR_BUSY) && 1145 count++ < HBA_MAX_RETRIES) { 1146 status = HBA_GetPortAttributesByWWN(handle, wwn, attrs); 1147 if (status == HBA_STATUS_OK) { 1148 break; 1149 } 1150 1151 /* The odds of this occuring are very slim, but possible. */ 1152 if (status == HBA_STATUS_ERROR_STALE_DATA) { 1153 /* 1154 * If we hit a stale data scenario, 1155 * we'll just tell the user to try again. 1156 */ 1157 status = HBA_STATUS_ERROR_TRY_AGAIN; 1158 break; 1159 } 1160 sleep(1); 1161 } 1162 return (status); 1163 } 1164 1165 /* 1166 * Returns non-zero on failure (aka, HBA_STATUS_ERROR_* 1167 * Will handle retries if applicable. 1168 */ 1169 int 1170 getAdapterPortAttrs(HBA_HANDLE handle, int portIndex, 1171 HBA_PORTATTRIBUTES *attrs) 1172 { 1173 int count = 0; 1174 HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */ 1175 1176 /* Loop as long as we have a retryable error */ 1177 while ((status == HBA_STATUS_ERROR_TRY_AGAIN || 1178 status == HBA_STATUS_ERROR_BUSY) && 1179 count++ < HBA_MAX_RETRIES) { 1180 status = HBA_GetAdapterPortAttributes(handle, portIndex, attrs); 1181 if (status == HBA_STATUS_OK) { 1182 break; 1183 } 1184 1185 /* The odds of this occuring are very slim, but possible. */ 1186 if (status == HBA_STATUS_ERROR_STALE_DATA) { 1187 /* 1188 * If we hit a stale data scenario, 1189 * we'll just tell the user to try again. 1190 */ 1191 status = HBA_STATUS_ERROR_TRY_AGAIN; 1192 break; 1193 } 1194 sleep(1); 1195 } 1196 return (status); 1197 } 1198 1199 /* 1200 * Returns non-zero on failure (aka, HBA_STATUS_ERROR_* 1201 * Will handle retries if applicable. 1202 */ 1203 int 1204 getDiscPortAttrs(HBA_HANDLE handle, int portIndex, int discIndex, 1205 HBA_PORTATTRIBUTES *attrs) 1206 { 1207 int count = 0; 1208 HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */ 1209 1210 /* Loop as long as we have a retryable error */ 1211 while ((status == HBA_STATUS_ERROR_TRY_AGAIN || 1212 status == HBA_STATUS_ERROR_BUSY) && 1213 count++ < HBA_MAX_RETRIES) { 1214 status = HBA_GetDiscoveredPortAttributes(handle, portIndex, 1215 discIndex, attrs); 1216 if (status == HBA_STATUS_OK) { 1217 break; 1218 } 1219 1220 /* The odds of this occuring are very slim, but possible. */ 1221 if (status == HBA_STATUS_ERROR_STALE_DATA) { 1222 /* 1223 * If we hit a stale data scenario, we'll just tell the 1224 * user to try again. 1225 */ 1226 status = HBA_STATUS_ERROR_TRY_AGAIN; 1227 break; 1228 } 1229 sleep(1); 1230 } 1231 return (status); 1232 } 1233 1234 /* 1235 * Find the Adapter port that matches the portPath. 1236 * When the matching port is found the caller have to close handle 1237 * and free library. 1238 */ 1239 fpcfga_ret_t 1240 findMatchingAdapterPort(char *portPath, HBA_HANDLE *matchingHandle, 1241 int *matchingPortIndex, HBA_PORTATTRIBUTES *matchingPortAttrs, 1242 char **errstring) 1243 { 1244 HBA_HANDLE handle; 1245 HBA_ADAPTERATTRIBUTES hbaAttrs; 1246 HBA_PORTATTRIBUTES portAttrs; 1247 HBA_STATUS status = HBA_STATUS_OK; 1248 int count, retry = 0, l_errno = 0; 1249 int adapterIndex, portIndex; 1250 char adapterName[256]; 1251 char *cfg_ptr, *tmpPtr; 1252 char *logical_apid = NULL; 1253 1254 status = HBA_LoadLibrary(); 1255 if (status != HBA_STATUS_OK) { 1256 cfga_err(errstring, 0, ERR_HBA_LOAD_LIBRARY, 0); 1257 return (FPCFGA_LIB_ERR); 1258 } 1259 count = HBA_GetNumberOfAdapters(); 1260 if (count == 0) { 1261 cfga_err(errstring, 0, ERR_NO_ADAPTER_FOUND, 0); 1262 HBA_FreeLibrary(); 1263 return (FPCFGA_LIB_ERR); 1264 } 1265 1266 /* Loop over all HBAs */ 1267 for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) { 1268 status = HBA_GetAdapterName(adapterIndex, (char *)&adapterName); 1269 if (status != HBA_STATUS_OK) { 1270 /* May have been DR'd */ 1271 continue; 1272 } 1273 handle = HBA_OpenAdapter(adapterName); 1274 if (handle == 0) { 1275 /* May have been DR'd */ 1276 continue; 1277 } 1278 1279 do { 1280 if (getAdapterAttrs(handle, &hbaAttrs)) { 1281 /* Should never happen */ 1282 HBA_CloseAdapter(handle); 1283 continue; 1284 } 1285 1286 /* Loop over all HBA Ports */ 1287 for (portIndex = 0; 1288 portIndex < hbaAttrs.NumberOfPorts; portIndex++) { 1289 if ((status = getAdapterPortAttrs(handle, portIndex, 1290 &portAttrs)) != HBA_STATUS_OK) { 1291 /* Need to refresh adapter */ 1292 if (status == HBA_STATUS_ERROR_STALE_DATA) { 1293 HBA_RefreshInformation(handle); 1294 break; 1295 } else { 1296 continue; 1297 } 1298 } 1299 1300 /* 1301 * check to see if OSDeviceName is a /dev/cfg link 1302 * or the physical path 1303 */ 1304 if (strncmp(portAttrs.OSDeviceName, CFGA_DEV_DIR, 1305 strlen(CFGA_DEV_DIR)) != 0) { 1306 tmpPtr = strstr(portAttrs.OSDeviceName, MINOR_SEP); 1307 if (tmpPtr != NULL) { 1308 if (strncmp(portPath, 1309 portAttrs.OSDeviceName, 1310 strlen(portAttrs.OSDeviceName) - 1311 strlen(tmpPtr)) == 0) { 1312 if (matchingHandle) 1313 *matchingHandle = handle; 1314 if (matchingPortIndex) 1315 *matchingPortIndex = portIndex; 1316 if (matchingPortAttrs) 1317 *matchingPortAttrs = portAttrs; 1318 return (FPCFGA_OK); 1319 } 1320 } 1321 } else { 1322 /* 1323 * strip off the /dev/cfg/ portion of the 1324 * OSDeviceName 1325 * make sure that the OSDeviceName is at least 1326 * strlen("/dev/cfg") + 1 + 1 long. 1327 * first 1 is for the / after /dev/cfg 1328 * second 1 is to make sure there is somthing 1329 * after 1330 */ 1331 if (strlen(portAttrs.OSDeviceName) < 1332 (strlen(CFGA_DEV_DIR) + 1 + 1)) 1333 continue; 1334 cfg_ptr = portAttrs.OSDeviceName + 1335 strlen(CFGA_DEV_DIR) + 1; 1336 if (logical_apid == NULL) { 1337 /* get the /dev/cfg link from the portPath */ 1338 if (make_xport_logid(portPath, &logical_apid, 1339 &l_errno) != FPCFGA_OK) { 1340 cfga_err(errstring, l_errno, 1341 ERR_LIST, 0); 1342 HBA_FreeLibrary(); 1343 return (FPCFGA_LIB_ERR); 1344 } 1345 } 1346 /* compare logical ap_id */ 1347 if (strcmp(logical_apid, cfg_ptr) == 0) { 1348 if (matchingHandle) 1349 *matchingHandle = handle; 1350 if (matchingPortIndex) 1351 *matchingPortIndex = portIndex; 1352 if (matchingPortAttrs) 1353 *matchingPortAttrs = portAttrs; 1354 S_FREE(logical_apid); 1355 return (FPCFGA_OK); 1356 } 1357 } 1358 } 1359 if (logical_apid != NULL) 1360 S_FREE(logical_apid); 1361 } while ((status == HBA_STATUS_ERROR_STALE_DATA) && 1362 (retry++ < HBA_MAX_RETRIES)); 1363 1364 HBA_CloseAdapter(handle); 1365 } 1366 free(logical_apid); 1367 1368 /* Got here. No mathcing adatper port found. */ 1369 cfga_err(errstring, 0, ERR_MATCHING_HBA_PORT, 0); 1370 HBA_FreeLibrary(); 1371 return (FPCFGA_LIB_ERR); 1372 } 1373