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 }