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 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include "cfga_ib.h"
  27 
  28 /*
  29  * cfga_ib.c:
  30  *      All cfgadm entry points that are defined in the config_admin(3X)
  31  *      needed for InfiniBand support are described here. These cfgadm
  32  *      interfaces issue ioctl(s) to the IB nexus driver. Attachment points
  33  *      supported are - IOC, VPPA, Port, HCA_SVC and Pseudo dynamic ap_ids,
  34  *      the HCA static ap_id, and the IB static ap_id.
  35  *
  36  *      Given InfiniBand bus is fabric based, #of dynamic ap_ids present are
  37  *      unknown at any given point of time. Hence this plugin uses a
  38  *      packed nvlist data structure to hold ap_id related information.
  39  *      The IB nexus driver allocates the nvlist data in the kernel
  40  *      and this plugin processes the data (it is freed by IB nexus driver).
  41  */
  42 
  43 
  44 /* function prototypes */
  45 static int              ib_get_link(di_devlink_t, void *);
  46 static icfga_ret_t      ib_physpath_to_devlink(char *, char **, int *);
  47 static const char       *ib_get_msg(uint_t, msgcvt_t *, uint_t);
  48 static void             ib_set_msg(char **, ...);
  49 static cfga_err_t       ib_err_msg(char **, cfga_ib_ret_t, const char *, int);
  50 static int              ib_verify_valid_apid(const char *);
  51 static cfga_ib_ret_t    ib_verify_params(const char *, const char *, char **);
  52 static void             ib_cleanup_after_devctl_cmd(devctl_hdl_t, nvlist_t *);
  53 static cfga_ib_ret_t    ib_setup_for_devctl_cmd(char *, boolean_t,
  54                             devctl_hdl_t *, nvlist_t **);
  55 static cfga_ib_ret_t    ib_device_configured(devctl_hdl_t, nvlist_t *,
  56                             ap_rstate_t *);
  57 static cfga_ib_ret_t    ib_device_connected(devctl_hdl_t, nvlist_t *,
  58                             ap_ostate_t *);
  59 static cfga_ib_ret_t    ib_do_control_ioctl(char *, uint_t, uint_t, uint_t,
  60                             void **, size_t *);
  61 cfga_err_t              cfga_change_state(cfga_cmd_t, const char *,
  62                             const char *, struct cfga_confirm *,
  63                             struct cfga_msg *, char **, cfga_flags_t);
  64 cfga_err_t              cfga_private_func(const char *, const char *,
  65                             const char *, struct cfga_confirm *,
  66                             struct cfga_msg *, char **, cfga_flags_t);
  67 cfga_err_t              cfga_test(const char *, const char *, struct cfga_msg *,
  68                             char **, cfga_flags_t);
  69 static cfga_ib_ret_t    ib_fill_static_apids(char *, cfga_list_data_t *);
  70 cfga_err_t              cfga_list_ext(const char *, cfga_list_data_t **, int *,
  71                             const char *, const char *, char **, cfga_flags_t);
  72 void                    cfga_msg(struct cfga_msg *, const char *);
  73 cfga_err_t              cfga_help(struct cfga_msg *, const char *,
  74                             cfga_flags_t);
  75 static int              ib_confirm(struct cfga_confirm *, char *);
  76 static char             *ib_get_devicepath(const char *);
  77 
  78 
  79 /* External function prototypes */
  80 extern cfga_ib_ret_t    ib_rcm_offline(const char *, char **, char *,
  81                             cfga_flags_t);
  82 extern cfga_ib_ret_t    ib_rcm_online(const char *, char **, char *,
  83                             cfga_flags_t);
  84 extern cfga_ib_ret_t    ib_rcm_remove(const char *, char **, char *,
  85                             cfga_flags_t);
  86 extern int              ib_add_service(char **);
  87 extern int              ib_delete_service(char **);
  88 extern int              ib_list_services(struct cfga_msg *, char **);
  89 
  90 
  91 /* Globals */
  92 int             cfga_version = CFGA_HSL_V2;     /* Set the version number for */
  93                                                 /* the cfgadm library's use. */
  94 
  95 static char     *ib_help[] = {  /* Help messages */
  96         NULL,
  97         /* CFGA_IB_HELP_HEADER */       "IB specific commands:\n",
  98         /* CFGA_IB_HELP_CONFIG */       "cfgadm -c [configure|unconfigure] "
  99             "ap_id [ap_id...]\n",
 100         /* CFGA_IB_HELP_LIST */         "cfgadm -x list_clients hca_ap_id "
 101             "[hca_ap_id...]\n",
 102         /* CFGA_IB_HELP_UPD_PKEY */     "cfgadm -x update_pkey_tbls ib\n",
 103         /* CFGA_IB_HELP_CONF_FILE1 */   "cfgadm -o comm=[port|vppa|hca-svc],"
 104             "service=<name> -x [add_service|delete_service] ib\n",
 105         /* CFGA_IB_HELP_CONF_FILE2 */   "cfgadm -x list_services ib\n",
 106         /* CFGA_IB_HELP_UPD_IOC_CONF */ "cfgadm -x update_ioc_config "
 107             "[ib | ioc_apid]\n",
 108         /* CFGA_IB_HELP_UNCFG_CLNTS */  "cfgadm -x unconfig_clients hca_ap_id "
 109             "[hca_ap_id...]\n",
 110         /* CFGA_IB_HELP_UNKNOWN */      "\tunknown command or option: ",
 111         NULL
 112 };
 113 
 114 static msgcvt_t ib_error_msgs[] = {     /* Error messages */
 115         /* CFGA_IB_OK */                { CVT, CFGA_OK, "ok" },
 116         /* CFGA_IB_UNKNOWN */           { CVT, CFGA_LIB_ERROR,
 117             "Unknown message; internal error " },
 118         /* CFGA_IB_INTERNAL_ERR */      { CVT, CFGA_LIB_ERROR,
 119             "Internal error " },
 120         /* CFGA_IB_INVAL_ARG_ERR */     { CVT, CFGA_LIB_ERROR,
 121             "Invalid input args " },
 122         /* CFGA_IB_OPTIONS_ERR */       { CVT, CFGA_ERROR,
 123             "Hardware specific options not supported " },
 124         /* CFGA_IB_AP_ERR */            { CVT, CFGA_APID_NOEXIST, "" },
 125         /* CFGA_IB_DEVCTL_ERR */        { CVT, CFGA_LIB_ERROR,
 126             "Cannot issue devctl to " },
 127         /* CFGA_IB_NOT_CONNECTED */     { CVT, CFGA_INSUFFICENT_CONDITION,
 128             "No device connected to " },
 129         /* CFGA_IB_NOT_CONFIGURED */    { CVT, CFGA_INSUFFICENT_CONDITION,
 130             "No device configured to " },
 131         /* CFGA_IB_ALREADY_CONNECTED */ { CVT, CFGA_INSUFFICENT_CONDITION,
 132             "already connected; cannot connect again " },
 133         /* CFGA_IB_ALREADY_CONFIGURED */ { CVT, CFGA_INSUFFICENT_CONDITION,
 134             "already configured " },
 135         /* CFGA_IB_CONFIG_OP_ERR */     { CVT, CFGA_ERROR,
 136             "configure operation failed " },
 137         /* CFGA_IB_UNCONFIG_OP_ERR */   { CVT, CFGA_ERROR,
 138             "unconfigure operation failed " },
 139         /* CFGA_IB_OPEN_ERR */          { CVT, CFGA_LIB_ERROR, "Cannot open " },
 140         /* CFGA_IB_IOCTL_ERR */         { CVT, CFGA_LIB_ERROR,
 141             "Driver ioctl failed " },
 142         /* CFGA_IB_BUSY_ERR */          { CVT, CFGA_SYSTEM_BUSY, " " },
 143         /* CFGA_IB_ALLOC_FAIL */        { CVT, CFGA_LIB_ERROR,
 144             "Memory allocation failure " },
 145         /* CFGA_IB_OPNOTSUPP */         { CVT, CFGA_OPNOTSUPP,
 146             "Operation not supported " },
 147         /* CFGA_IB_INVAL_APID_ERR */    { CVT, CFGA_LIB_ERROR,
 148             "Invalid ap_id supplied " },
 149         /* CFGA_IB_DEVLINK_ERR */       { CVT, CFGA_LIB_ERROR,
 150             "Could not find /dev/cfg link for " },
 151         /* CFGA_IB_PRIV_ERR */          { CVT, CFGA_PRIV, " " },
 152         /* CFGA_IB_NVLIST_ERR */        { CVT, CFGA_ERROR,
 153             "Internal error (nvlist) " },
 154         /* CFGA_IB_HCA_LIST_ERR */      { CVT, CFGA_ERROR,
 155             "Listing HCA's clients failed " },
 156         /* CFGA_IB_HCA_UNCONFIG_ERR */  { CVT, CFGA_ERROR,
 157             "Unconfiguring HCA's clients failed " },
 158         /* CFGA_IB_UPD_PKEY_TBLS_ERR */ { CVT, CFGA_ERROR,
 159             "Updating P_Key tables failed " },
 160         /* CFGA_IB_RCM_HANDLE_ERR */    { CVT, CFGA_ERROR,
 161             "Opening ib.conf file failed " },
 162         /* CFGA_IB_LOCK_FILE_ERR */     { CVT, CFGA_LIB_ERROR,
 163             "Locking ib.conf file failed " },
 164         /* CFGA_IB_UNLOCK_FILE_ERR */   { CVT, CFGA_LIB_ERROR,
 165             "Unlocking ib.conf file failed " },
 166         /* CFGA_IB_COMM_INVAL_ERR */    { CVT, CFGA_INVAL,
 167             "Communication type incorrectly specified " },
 168         /* CFGA_IB_SVC_INVAL_ERR */     { CVT, CFGA_INVAL,
 169             "Service name incorrectly specified " },
 170         /* CFGA_IB_SVC_LEN_ERR_ERR */   { CVT, CFGA_INVAL,
 171             "Service name len should be <= to 4, " },
 172         /* CFGA_IB_SVC_EXISTS_ERR */    { CVT, CFGA_INVAL, " "},
 173         /* CFGA_IB_SVC_NO_EXIST_ERR */  { CVT, CFGA_INVAL, " " },
 174         /* CFGA_IB_UCFG_CLNTS_ERR */    { CVT, CFGA_INVAL,
 175             "unconfig_clients failed for HCA " },
 176         /* CFGA_IB_INVALID_OP_ERR */    { CVT, CFGA_OPNOTSUPP, "on " },
 177         /* CFGA_IB_RCM_HANDLE */        { CVT, CFGA_ERROR,
 178             "cannot get RCM handle "},
 179         /* CFGA_IB_RCM_ONLINE_ERR */    { CVT, CFGA_SYSTEM_BUSY,
 180             "failed to online: "},
 181         /* CFGA_IB_RCM_OFFLINE_ERR */   { CVT, CFGA_SYSTEM_BUSY,
 182             "failed to offline: "}
 183 };
 184 
 185 /*
 186  * these are the only valid sub-options for services.
 187  */
 188 static char             *ib_service_subopts[] = {
 189                                 "comm",
 190                                 "service",
 191                                 NULL
 192                         };
 193 
 194 /* Communication Service name : "port" or "vppa" or "hca-svc" */
 195 static char             *comm_name = NULL;
 196 
 197 char                    *service_name = NULL;   /* service name */
 198 ib_service_type_t       service_type = IB_NONE; /* service type */
 199 
 200 
 201 /* ========================================================================= */
 202 /*
 203  * The next two funcs are imported from cfgadm_scsi.
 204  * ib_physpath_to_devlink is the only func directly used by cfgadm_ib.
 205  * ib_get_link supports it.
 206  */
 207 
 208 /*
 209  * Function:
 210  *      ib_get_link
 211  * Input:
 212  *      devlink         - devlink for the device path
 213  *      arg             - argument passed to this "walker" function
 214  * Output:
 215  *      NONE
 216  * Returns:
 217  *      Continue "walking" or not
 218  * Description:
 219  *      Routine to search the /dev directory or a subtree of /dev.
 220  */
 221 static int
 222 ib_get_link(di_devlink_t devlink, void *arg)
 223 {
 224         walk_link_t     *larg = (walk_link_t *)arg;
 225 
 226         /*
 227          * When path is specified, it's the node path without minor
 228          * name. Therefore, the ../.. prefixes needs to be stripped.
 229          */
 230         if (larg->path) {
 231                 char *content = (char *)di_devlink_content(devlink);
 232                 char *start = strstr(content, "/devices/");
 233 
 234                 /* line content must have minor node */
 235                 if (start == NULL ||
 236                     strncmp(start, larg->path, larg->len) != 0 ||
 237                     start[larg->len] != ':') {
 238                         return (DI_WALK_CONTINUE);
 239                 }
 240         }
 241 
 242         *(larg->linkpp) = strdup(di_devlink_path(devlink));
 243         return (DI_WALK_TERMINATE);
 244 }
 245 
 246 
 247 /*
 248  * Function:
 249  *      ib_physpath_to_devlink
 250  * Input:
 251  *      node_path       - Physical path of the ap_id node
 252  * Output:
 253  *      logpp           - Logical path to the ap_id node
 254  *      l_errnop        - "errno"
 255  * Returns:
 256  *      ICFGA_OK if everything was fine; otherwise an error with
 257  *      l_errnop set.
 258  * Description:
 259  *      Given a physical path to an ap_id ensure that it exists
 260  */
 261 /* ARGSUSED */
 262 static icfga_ret_t
 263 ib_physpath_to_devlink(char *node_path, char **logpp, int *l_errnop)
 264 {
 265         char                    *minor_path;
 266         walk_link_t             larg;
 267         di_devlink_handle_t     hdl;
 268 
 269         if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
 270                 *l_errnop = errno;
 271                 return (ICFGA_LIB_ERR);
 272         }
 273 
 274         *logpp = NULL;
 275         larg.linkpp = logpp;
 276         minor_path = (char *)node_path + strlen("/devices");
 277         larg.path = NULL;
 278         larg.len = 0;
 279 
 280         (void) di_devlink_walk(hdl, "^cfg/", minor_path, DI_PRIMARY_LINK,
 281             (void *)&larg, ib_get_link);
 282 
 283         di_devlink_fini(&hdl);
 284 
 285         if (*logpp == NULL) {
 286                 *l_errnop = errno;
 287                 return (ICFGA_LIB_ERR);
 288         }
 289 
 290         return (ICFGA_OK);
 291 }
 292 
 293 
 294 /* ========================================================================= */
 295 /* Utilities */
 296 
 297 /*
 298  * Function:
 299  *      ib_get_msg
 300  * Input:
 301  *      msg_index       - Index into the message table
 302  *      msg_tbl         - the message table
 303  *      tbl_size        - size of the message table
 304  * Output:
 305  *      NONE
 306  * Returns:
 307  *      Message string if valid, otherwise an error
 308  * Description:
 309  *      Given the index into a table (msgcvt_t) of messages,
 310  *      get the message string, converting it to the proper
 311  *      locale if necessary.
 312  *
 313  *      NOTE: See cfga_ib.h
 314  */
 315 static const char *
 316 ib_get_msg(uint_t msg_index, msgcvt_t *msg_tbl, uint_t tbl_size)
 317 {
 318         if (msg_index >= tbl_size) {
 319                 DPRINTF("get_error_msg: bad error msg index: %d\n", msg_index);
 320                 msg_index = CFGA_IB_UNKNOWN;
 321         }
 322 
 323         return ((msg_tbl[msg_index].intl) ?
 324             dgettext(TEXT_DOMAIN, msg_tbl[msg_index].msgstr) :
 325             msg_tbl[msg_index].msgstr);
 326 }
 327 
 328 
 329 /*
 330  * Function:
 331  *      ib_set_msg
 332  * Input:
 333  *      NONE
 334  * Output:
 335  *      ret_str - Returned "message" string.
 336  * Returns:
 337  *      NONE
 338  * Description:
 339  *      Allocates and creates a message string (in *ret_str),
 340  *      by concatenating all the (char *) args together, in order.
 341  *      Last arg MUST be NULL.
 342  */
 343 static void
 344 ib_set_msg(char **ret_str, ...)
 345 {
 346         char    *str;
 347         size_t  total_len, ret_str_len;
 348         va_list valist;
 349 
 350         va_start(valist, ret_str);
 351 
 352         total_len = (*ret_str == NULL) ? 0 : strlen(*ret_str);
 353 
 354         while ((str = va_arg(valist, char *)) != NULL) {
 355                 size_t  len = strlen(str);
 356                 char    *old_str = *ret_str;
 357 
 358                 ret_str_len = total_len + len + 1;
 359                 *ret_str = (char *)realloc(*ret_str, ret_str_len);
 360                 if (*ret_str == NULL) {
 361                         free(old_str);
 362                         DPRINTF("ib_set_msg: realloc failed.\n");
 363                         va_end(valist);
 364                         return;
 365                 }
 366 
 367                 (void) strlcpy(*ret_str + total_len, str, ret_str_len);
 368                 total_len += len;
 369         }
 370 
 371         va_end(valist);
 372 }
 373 
 374 
 375 /*
 376  * Function:
 377  *      ib_err_msg
 378  * Input:
 379  *      ap_id           - The attachment point of an IB fabric
 380  * Output:
 381  *      errstring       - Fill in the error msg string
 382  *      l_errno         - The "errno" to be filled in.
 383  * Returns:
 384  *      CFGA_IB_OK if we are able to fill in error msg;
 385  *      otherwise emit an error.
 386  * Description:
 387  *      Error message handling.
 388  *
 389  *      For the rv passed in, looks up the corresponding error message
 390  *      string(s), internationalized it if necessary, and concatenates
 391  *      it into a new memory buffer, and points *errstring to it.
 392  *      Note not all "rv"s will result in an error message return, as
 393  *      not all error conditions warrant a IB-specific error message.
 394  *
 395  *      Some messages may display ap_id or errno, which is why they are
 396  *      passed in.
 397  */
 398 static cfga_err_t
 399 ib_err_msg(char **errstring, cfga_ib_ret_t rv, const char *ap_id, int l_errno)
 400 {
 401         char *errno_str;
 402 
 403         if (errstring == NULL) {
 404                 return (ib_error_msgs[rv].cfga_err);
 405         }
 406 
 407         /* Generate the appropriate IB-specific error message(s) (if any). */
 408         switch (rv) {
 409         case CFGA_IB_OK:        /* Special case - do nothing.  */
 410                 break;
 411         case CFGA_IB_AP_ERR:
 412         case CFGA_IB_UNKNOWN:
 413         case CFGA_IB_INTERNAL_ERR:
 414         case CFGA_IB_OPTIONS_ERR:
 415         case CFGA_IB_ALLOC_FAIL:
 416                 /* These messages require no additional strings passed. */
 417                 ib_set_msg(errstring, ERR_STR(rv), NULL);
 418                 break;
 419         case CFGA_IB_NOT_CONNECTED:
 420         case CFGA_IB_NOT_CONFIGURED:
 421         case CFGA_IB_ALREADY_CONNECTED:
 422         case CFGA_IB_ALREADY_CONFIGURED:
 423         case CFGA_IB_CONFIG_OP_ERR:
 424         case CFGA_IB_UNCONFIG_OP_ERR:
 425         case CFGA_IB_BUSY_ERR:
 426         case CFGA_IB_DEVLINK_ERR:
 427         case CFGA_IB_RCM_HANDLE_ERR:
 428         case CFGA_IB_RCM_ONLINE_ERR:
 429         case CFGA_IB_RCM_OFFLINE_ERR:
 430         case CFGA_IB_DEVCTL_ERR:
 431         case CFGA_IB_COMM_INVAL_ERR:
 432         case CFGA_IB_SVC_INVAL_ERR:
 433         case CFGA_IB_SVC_LEN_ERR:
 434         case CFGA_IB_SVC_EXISTS_ERR:
 435         case CFGA_IB_SVC_NO_EXIST_ERR:
 436         case CFGA_IB_LOCK_FILE_ERR:
 437         case CFGA_IB_CONFIG_FILE_ERR:
 438         case CFGA_IB_UNLOCK_FILE_ERR:
 439         case CFGA_IB_UCFG_CLNTS_ERR:
 440         case CFGA_IB_INVALID_OP_ERR:
 441                 /* These messages also print ap_id.  */
 442                 ib_set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "", NULL);
 443                 break;
 444         case CFGA_IB_IOCTL_ERR: /* These messages also print errno.  */
 445         case CFGA_IB_NVLIST_ERR:
 446                 errno_str = l_errno ? strerror(l_errno) : "";
 447                 ib_set_msg(errstring, ERR_STR(rv), errno_str,
 448                     l_errno ? "\n" : "", NULL);
 449                 break;
 450         case CFGA_IB_OPEN_ERR: /* This messages also prints apid and errno.  */
 451         case CFGA_IB_PRIV_ERR:
 452         case CFGA_IB_HCA_LIST_ERR:
 453         case CFGA_IB_OPNOTSUPP:
 454         case CFGA_IB_INVAL_ARG_ERR:
 455         case CFGA_IB_INVAL_APID_ERR:
 456         case CFGA_IB_HCA_UNCONFIG_ERR:
 457         case CFGA_IB_UPD_PKEY_TBLS_ERR:
 458                 errno_str = l_errno ? strerror(l_errno) : "";
 459                 ib_set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "\n",
 460                     errno_str, l_errno ? "\n" : "", NULL);
 461                 break;
 462         default:
 463                 DPRINTF("ib_err_msg: Unrecognized message index: %d\n", rv);
 464                 ib_set_msg(errstring, ERR_STR(CFGA_IB_INTERNAL_ERR), NULL);
 465         }
 466 
 467         /*
 468          * Determine the proper error code to send back to the cfgadm library.
 469          */
 470         return (ib_error_msgs[rv].cfga_err);
 471 }
 472 
 473 
 474 /*
 475  * Function:
 476  *      ib_verify_valid_apid
 477  * Input:
 478  *      ap_id           - The attachment point of an IB fabric
 479  * Output:
 480  *      NONE
 481  * Returns:
 482  *      0 if ap_id is valid; otherwise -1
 483  * Description:
 484  *      Check if ap_id is valid or not.
 485  *      Ensure the ap_id passed is in the correct (physical ap_id) form:
 486  *      path/device:xx[.xx]+
 487  *      where xx is a one or two-digit number.
 488  *
 489  *      Note the library always calls the plugin with a physical ap_id.
 490  *      Called by ib_verify_params().
 491  */
 492 static int
 493 ib_verify_valid_apid(const char *ap_id)
 494 {
 495         char    *l_ap_id;
 496 
 497         if (ap_id == NULL) {
 498                 return (-1);
 499         }
 500 
 501         l_ap_id = strchr(ap_id, *MINOR_SEP);
 502         l_ap_id++;
 503 
 504         /* fabric apids */
 505         if (strstr((char *)ap_id, IBNEX_FABRIC) != NULL) {
 506                 DPRINTF("ib_valid_apid: l_apid = %s\n", l_ap_id);
 507                 /* if the ap_id is "ib::" then report an error */
 508                 if ((strlen(l_ap_id) == strlen(IBNEX_FABRIC) + 1) ||
 509                     (strlen(l_ap_id) == strlen(IBNEX_FABRIC) + 2)) {
 510                         return (-1);
 511                 }
 512 
 513                 if (strstr(l_ap_id, "...") != NULL) {
 514                         return (-1);
 515                 }
 516 
 517         } else {        /* HCA ap_ids */
 518                 /* ap_id has 1..2 or more than 2 dots */
 519                 if (strstr(l_ap_id, "..") != NULL) {
 520                         return (-1);
 521                 }
 522         }
 523 
 524         return (0);
 525 }
 526 
 527 
 528 /*
 529  * Function:
 530  *      ib_verify_params
 531  * Input:
 532  *      ap_id           - The attachment point of an IB fabric
 533  *      options         - command options passed by the cfgadm(1M)
 534  *      errstring       - This contains error msg if command fails
 535  * Output:
 536  *      NONE
 537  * Returns:
 538  *      CFGA_IB_OK if parameters are valid; otherwise emit an error.
 539  * Description:
 540  *      Check if "options" and "errstring" are valid and if ap_id is
 541  *      valid or not.
 542  */
 543 static cfga_ib_ret_t
 544 ib_verify_params(const char *ap_id, const char *options, char **errstring)
 545 {
 546         if (errstring != NULL) {
 547                 *errstring = NULL;
 548         }
 549 
 550         if (options != NULL) {
 551                 DPRINTF("ib_verify_params: h/w-specific options not "
 552                     "supported.\n");
 553                 return (CFGA_IB_OPTIONS_ERR);
 554         }
 555 
 556         if (ib_verify_valid_apid(ap_id) != 0) {
 557                 DPRINTF("ib_verify_params: not an IB ap_id.\n");
 558                 return (CFGA_IB_AP_ERR);
 559         }
 560         return (CFGA_IB_OK);
 561 }
 562 
 563 
 564 /*
 565  * Function:
 566  *      ib_cleanup_after_devctl_cmd
 567  * Input:
 568  *      devctl_hdl      - Handler to devctl
 569  *      user_nvlistp    - Name-value-pair list pointer
 570  * Output:
 571  *      NONE
 572  * Returns:
 573  *      NONE
 574  * Description:
 575  *      Cleanup an initialization/setup done in the next function i.e.
 576  *      ib_setup_for_devctl_cmd().
 577  */
 578 static void
 579 ib_cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist)
 580 {
 581         if (user_nvlist != NULL) {
 582                 nvlist_free(user_nvlist);
 583         }
 584 
 585         if (devctl_hdl != NULL) {
 586                 devctl_release(devctl_hdl);
 587         }
 588 }
 589 
 590 
 591 /*
 592  * Function:
 593  *      ib_setup_for_devctl_cmd
 594  * Input:
 595  *      ap_id           - Attachment point for the IB device in question
 596  *      use_static_ap_id - Whether to use static ap_id or not flag
 597  * Output:
 598  *      devctl_hdl      - Handler to devctl
 599  *      user_nvlistp    - Name-value-pair list pointer
 600  * Returns:
 601  *      CFGA_IB_OK if it succeeds or an appropriate error.
 602  * Description:
 603  *      For any IB device  that is doing a cfgadm operation this function
 604  *      sets up a devctl_hdl and allocates a nvlist_t. The devctl_hdl
 605  *      is acquired using libdevice APIs. The nvlist_t is filled up with
 606  *      the ap_id (as a string). This nvlist_t is looked up in the kernel
 607  *      to figure out which ap_id we are currently dealing with.
 608  *
 609  *      "use_static_ap_id" flag tells if one should do a devctl_ap_acquire
 610  *      with IB_STATIC_APID or not. NOTE: We need an actual file-system
 611  *      vnode to do a devctl_ap_acquire.
 612  *
 613  *      NOTE: always call ib_cleanup_after_devctl_cmd() after this function.
 614  */
 615 static cfga_ib_ret_t
 616 ib_setup_for_devctl_cmd(char *ap_id, boolean_t use_static_ap_id,
 617     devctl_hdl_t *devctl_hdl, nvlist_t **user_nvlistp)
 618 {
 619         char    *apid = (use_static_ap_id == B_TRUE) ? IB_STATIC_APID : ap_id;
 620 
 621         /* Get a handle to the ap */
 622         if ((*devctl_hdl = devctl_ap_acquire(apid, NULL)) == NULL) {
 623                 DPRINTF("ib_setup_for_devctl_cmd: devctl_ap_acquire "
 624                     "errno: %d\n", errno);
 625                 ib_cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
 626                 return (CFGA_IB_DEVCTL_ERR);
 627         }
 628 
 629         /* Set up to pass dynamic ap_id down to driver */
 630         if (nvlist_alloc(user_nvlistp, NV_UNIQUE_NAME_TYPE, NULL) != 0) {
 631                 DPRINTF("ib_setup_for_devctl: nvlist_alloc errno: %d\n", errno);
 632                 *user_nvlistp = NULL;   /* Prevent possible incorrect free in */
 633                                         /* ib_cleanup_after_devctl_cmd */
 634                 ib_cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
 635                 return (CFGA_IB_NVLIST_ERR);
 636         }
 637 
 638         /* create a "string" entry */
 639         if (nvlist_add_string(*user_nvlistp, IB_APID, ap_id) == -1) {
 640                 DPRINTF("ib_setup_for_devctl_cmd: nvlist_add_string failed. "
 641                     "errno: %d\n", errno);
 642                 ib_cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
 643                 return (CFGA_IB_NVLIST_ERR);
 644         }
 645 
 646         return (CFGA_IB_OK);
 647 }
 648 
 649 
 650 /*
 651  * Function:
 652  *      ib_device_configured
 653  * Input:
 654  *      hdl             - Handler to devctl
 655  *      nvl             - Name-value-pair list pointer
 656  * Output:
 657  *      rstate          - Receptacle state for the apid
 658  * Returns:
 659  *      CFGA_IB_OK if it succeeds or an appropriate error.
 660  * Description:
 661  *      Checks if there is a device actually configured to the ap? If so,
 662  *      issues a "devctl" to get the Receptacle state for that ap_id.
 663  *      If the ap_id is already configured it returns CFGA_IB_OK.
 664  *      Otherwise it returns a failure.
 665  */
 666 static cfga_ib_ret_t
 667 ib_device_configured(devctl_hdl_t hdl, nvlist_t *nvl, ap_rstate_t *rstate)
 668 {
 669         cfga_ib_ret_t           rv;
 670         devctl_ap_state_t       devctl_ap_state;
 671 
 672         /* get ap_id's "devctl_ap_state" first */
 673         if (devctl_ap_getstate(hdl, nvl, &devctl_ap_state) == -1) {
 674                 DPRINTF("ib_device_configured failed, errno: %d\n", errno);
 675                 return (CFGA_IB_DEVCTL_ERR);
 676         }
 677 
 678         rv = CFGA_IB_ALREADY_CONFIGURED;
 679         *rstate = devctl_ap_state.ap_rstate;
 680         if (devctl_ap_state.ap_ostate != AP_OSTATE_CONFIGURED) {
 681                 return (CFGA_IB_NOT_CONFIGURED);
 682         }
 683 
 684         return (rv);
 685 }
 686 
 687 
 688 /*
 689  * Function:
 690  *      ib_device_connected
 691  * Input:
 692  *      hdl             - Handler to devctl
 693  *      nvl             - Name-value-pair list pointer
 694  * Output:
 695  *      ostate          - Occupant state for the apid
 696  * Returns:
 697  *      CFGA_IB_OK if it succeeds or an appropriate error.
 698  * Description:
 699  *      Checks if there is a device actually connected to the ap? If so,
 700  *      issues a "devctl" to get the Occupant state for that ap_id.
 701  *      If the ap_id is already connected it returns CFGA_IB_OK.
 702  *      Otherwise it returns a failure.
 703  */
 704 static cfga_ib_ret_t
 705 ib_device_connected(devctl_hdl_t hdl, nvlist_t *list, ap_ostate_t *ostate)
 706 {
 707         cfga_ib_ret_t           rv = CFGA_IB_ALREADY_CONNECTED;
 708         devctl_ap_state_t       devctl_ap_state;
 709 
 710         if (devctl_ap_getstate(hdl, list, &devctl_ap_state) == -1) {
 711                 DPRINTF("ib_device_connected failed, errno: %d\n", errno);
 712                 return (CFGA_IB_DEVCTL_ERR);
 713         }
 714 
 715         *ostate =  devctl_ap_state.ap_ostate;
 716         if (devctl_ap_state.ap_rstate != AP_RSTATE_CONNECTED) {
 717                 return (CFGA_IB_NOT_CONNECTED);
 718         }
 719 
 720         return (rv);
 721 }
 722 
 723 
 724 /*
 725  * Function:
 726  *      ib_do_control_ioctl
 727  * Input:
 728  *      ap_id           - The dynamic attachment point of an IB device
 729  *      sub_cmd1        - Sub Command 1 to DEVCTL_AP_CONTROL devctl
 730  *      sub_cmd2        - Sub Command 2 to DEVCTL_AP_CONTROL devctl
 731  *                              (Mandatory except for IBNEX_NUM_HCA_NODES,
 732  *                              IBNEX_NUM_DEVICE_NODES,
 733  *                              IBNEX_UPDATE_PKEY_TBLS &
 734  *                              IBNEX_UPDATE_IOC_CONF)
 735  *      misc_arg        - optional arguments to DEVCTL_AP_CONTROL devctl
 736  * Output:
 737  *      descrp          - Buffer containing data back from kernel
 738  *      sizep           - Length of the buffer back from kernel
 739  * Returns:
 740  *      CFGA_IB_OK if it succeeds or an appropriate error.
 741  * Description:
 742  *      Issues DEVCTL_AP_CONTROL devctl with sub_cmd1 first which actually
 743  *      queries the IBNEX module in the kernel on the size of the data to
 744  *      be returned.
 745  *
 746  *      Next issues DEVCTL_AP_CONTROL devctl with a buffer of that much
 747  *      size and gets the actual data back.
 748  *      Passes the data and the size back to caller.
 749  */
 750 static cfga_ib_ret_t
 751 ib_do_control_ioctl(char *ap_id, uint_t sub_cmd1, uint_t sub_cmd2,
 752     uint_t misc_arg, void **descrp, size_t *sizep)
 753 {
 754         int                     fd = -1;
 755         uint32_t                local_size = 0;
 756         cfga_ib_ret_t           rv = CFGA_IB_OK;
 757         struct ibnex_ioctl_data ioctl_data;
 758 
 759         /* try to open the ONLY static ap_id */
 760         if ((fd = open(IB_STATIC_APID, O_RDONLY)) == -1) {
 761                 DPRINTF("ib_do_control_ioctl: open failed: "
 762                     "errno = %d\n", errno);
 763                 /* Provides a more useful error msg */
 764                 rv = (errno == EBUSY) ? CFGA_IB_BUSY_ERR : CFGA_IB_OPEN_ERR;
 765                 return (rv);
 766         }
 767 
 768         /*
 769          * Find out first how large a buffer is needed?
 770          * NOTE: Ioctls only accept/return a 32-bit int for a get_size
 771          * to avoid 32/64 and BE/LE issues.
 772          */
 773         ioctl_data.cmd = sub_cmd1;
 774         ioctl_data.misc_arg = (uint_t)misc_arg;
 775         ioctl_data.buf = (caddr_t)&local_size;
 776         ioctl_data.bufsiz = sizeof (local_size);
 777 
 778         /* Pass "ap_id" up for all other commands */
 779         if (sub_cmd1 != IBNEX_NUM_DEVICE_NODES &&
 780             sub_cmd1 != IBNEX_NUM_HCA_NODES &&
 781             sub_cmd1 != IBNEX_UPDATE_PKEY_TBLS) {
 782                 ioctl_data.ap_id = (caddr_t)ap_id;
 783                 ioctl_data.ap_id_len = strlen(ap_id);
 784 
 785         } else {
 786                 ioctl_data.ap_id = NULL;
 787                 ioctl_data.ap_id_len = 0;
 788         }
 789 
 790         if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
 791                 DPRINTF("ib_do_control_ioctl: size ioctl ERR, errno: %d\n",
 792                     errno);
 793                 (void) close(fd);
 794                 rv = (errno == EBUSY) ? CFGA_IB_BUSY_ERR : CFGA_IB_IOCTL_ERR;
 795                 return (rv);
 796         }
 797         *sizep = local_size;
 798 
 799         /*
 800          * Don't do the second ioctl only in these cases
 801          * (NOTE: the data is returned in the first ioctl itself; if any)
 802          */
 803         if (sub_cmd1 == IBNEX_NUM_DEVICE_NODES ||
 804             sub_cmd1 == IBNEX_NUM_HCA_NODES ||
 805             sub_cmd1 == IBNEX_UPDATE_PKEY_TBLS ||
 806             sub_cmd1 == IBNEX_UPDATE_IOC_CONF) {
 807                 (void) close(fd);
 808                 return (rv);
 809         }
 810 
 811         if (local_size == 0 || (*descrp = malloc(*sizep)) == NULL) {
 812                 DPRINTF("ib_do_control_ioctl: malloc failed\n");
 813                 (void) close(fd);
 814                 return (CFGA_IB_ALLOC_FAIL);
 815         }
 816 
 817         /* Get the data */
 818         ioctl_data.cmd = sub_cmd2;
 819         ioctl_data.buf = (caddr_t)*descrp;
 820         ioctl_data.bufsiz = *sizep;
 821 
 822         if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
 823                 DPRINTF("ib_do_control_ioctl: ioctl failed: errno:%d\n", errno);
 824                 if (*descrp != NULL) {
 825                         free(*descrp);
 826                         *descrp = NULL;
 827                 }
 828                 rv = (errno == EBUSY) ? CFGA_IB_BUSY_ERR : CFGA_IB_IOCTL_ERR;
 829         }
 830 
 831         (void) close(fd);
 832         return (rv);
 833 }
 834 
 835 
 836 /* ========================================================================== */
 837 /* Entry points */
 838 
 839 /*
 840  * Function:
 841  *      cfga_change_state
 842  * Input:
 843  *      state_change_cmd - Argument to the cfgadm -c command
 844  *      ap_id           - The attachment point of an IB fabric
 845  *      options         - State Change command options passed by the cfgadm(1M)
 846  *      confp           - Whether this command requires confirmation?
 847  *      msgp            - cfgadm error message for this plugin
 848  *      errstring       - This contains error msg if command fails
 849  *      flags           - Cfgadm(1m) flags
 850  * Output:
 851  *      NONE
 852  * Returns:
 853  *      If the command succeeded perform the cfgadm -c <cmd>;
 854  *      otherwise emit an error
 855  * Description:
 856  *      Do cfgadm -c <cmd>
 857  */
 858 /*ARGSUSED*/
 859 cfga_err_t
 860 cfga_change_state(cfga_cmd_t state_change_cmd, const char *ap_id,
 861     const char *options, struct cfga_confirm *confp, struct cfga_msg *msgp,
 862     char **errstring, cfga_flags_t flags)
 863 {
 864         int             ret;
 865         char            *devpath;
 866         nvlist_t        *nvl = NULL;
 867         boolean_t       static_ap_id = B_TRUE;
 868         ap_rstate_t     rstate;
 869         ap_ostate_t     ostate;
 870         devctl_hdl_t    hdl = NULL;
 871         cfga_ib_ret_t   rv = CFGA_IB_OK;
 872 
 873         if ((rv = ib_verify_params(ap_id, options, errstring)) != CFGA_IB_OK) {
 874                 (void) cfga_help(msgp, options, flags);
 875                 return (ib_err_msg(errstring, CFGA_IB_INVAL_APID_ERR,
 876                     ap_id, errno));
 877         }
 878 
 879         /*
 880          * All subcommands which can change state of device require
 881          * root privileges.
 882          */
 883         if (geteuid() != 0) {
 884                 return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id, errno));
 885         }
 886 
 887         if (strstr((char *)ap_id, IB_FABRIC_APID_STR) == NULL)
 888                 static_ap_id = B_FALSE;
 889 
 890         if ((rv = ib_setup_for_devctl_cmd((char *)ap_id, static_ap_id,
 891             &hdl, &nvl)) != CFGA_IB_OK) {
 892                 ib_cleanup_after_devctl_cmd(hdl, nvl);
 893                 return (ib_err_msg(errstring, rv, ap_id, errno));
 894         }
 895 
 896         switch (state_change_cmd) {
 897         case CFGA_CMD_CONFIGURE:
 898                 rv = ib_device_connected(hdl, nvl, &ostate);
 899                 if (rv != CFGA_IB_ALREADY_CONNECTED) {
 900                         ret = (rv != CFGA_IB_NOT_CONNECTED) ?
 901                             CFGA_IB_CONFIG_OP_ERR : rv;
 902                         ib_cleanup_after_devctl_cmd(hdl, nvl);
 903                         return (ib_err_msg(errstring, ret, ap_id, errno));
 904                 }
 905 
 906                 if (rv == CFGA_IB_ALREADY_CONNECTED) {
 907                         /*
 908                          * special case handling for
 909                          * SLM based cfgadm disconnects
 910                          */
 911                         if (ostate == AP_OSTATE_CONFIGURED) {
 912                                 ib_cleanup_after_devctl_cmd(hdl, nvl);
 913                                 return (ib_err_msg(errstring,
 914                                     CFGA_IB_ALREADY_CONFIGURED, ap_id,
 915                                     errno));
 916                         }
 917                 }
 918 
 919 
 920                 rv = CFGA_IB_OK;        /* Other status don't matter */
 921 
 922                 if (devctl_ap_configure(hdl, nvl) != 0) {
 923                         DPRINTF("cfga_change_state: devctl_ap_configure "
 924                             "failed. errno: %d\n", errno);
 925                         rv = CFGA_IB_CONFIG_OP_ERR;
 926                         break;
 927                 }
 928 
 929                 devpath = ib_get_devicepath(ap_id);
 930                 if (devpath == NULL) {
 931                         int i;
 932 
 933                         /*
 934                          * try for some time as IB hotplug thread
 935                          * takes a while to create the path
 936                          * and then eventually give up
 937                          */
 938                         for (i = 0;
 939                             i < IB_RETRY_DEVPATH && (devpath == NULL); i++) {
 940                                 sleep(IB_MAX_DEVPATH_DELAY);
 941                                 devpath = ib_get_devicepath(ap_id);
 942                         }
 943 
 944                         if (devpath == NULL) {
 945                                 DPRINTF("cfga_change_state: get device "
 946                                     "path failed i = %d\n", i);
 947                                 rv = CFGA_IB_CONFIG_OP_ERR;
 948                                 break;
 949                         }
 950                 }
 951                 S_FREE(devpath);
 952                 break;
 953 
 954         case CFGA_CMD_UNCONFIGURE:
 955                 if ((rv = ib_device_connected(hdl, nvl, &ostate)) !=
 956                     CFGA_IB_ALREADY_CONNECTED) {
 957                         ib_cleanup_after_devctl_cmd(hdl, nvl);
 958                         if (rv == CFGA_IB_DEVCTL_ERR)
 959                                 rv = CFGA_IB_INVALID_OP_ERR;
 960                         return (ib_err_msg(errstring, rv, ap_id, errno));
 961                 }
 962 
 963                 /* check if it is already unconfigured */
 964                 if ((rv = ib_device_configured(hdl, nvl, &rstate)) ==
 965                     CFGA_IB_NOT_CONFIGURED) {
 966                         ib_cleanup_after_devctl_cmd(hdl, nvl);
 967                         return (ib_err_msg(errstring, rv, ap_id, errno));
 968                 }
 969 
 970                 rv = CFGA_IB_OK;        /* Other statuses don't matter */
 971 
 972                 if (!ib_confirm(confp, IB_CONFIRM1)) {
 973                         ib_cleanup_after_devctl_cmd(hdl, nvl);
 974                         return (CFGA_NACK);
 975                 }
 976 
 977                 devpath = ib_get_devicepath(ap_id);
 978                 if (devpath == NULL) {
 979                         DPRINTF("cfga_change_state: get device path failed\n");
 980                         rv = CFGA_IB_UNCONFIG_OP_ERR;
 981                         break;
 982                 }
 983 
 984                 if ((rv = ib_rcm_offline(ap_id, errstring, devpath, flags)) !=
 985                     CFGA_IB_OK) {
 986                         S_FREE(devpath);
 987                         break;
 988                 }
 989 
 990                 ret = devctl_ap_unconfigure(hdl, nvl);
 991                 if (ret != 0) {
 992                         DPRINTF("cfga_change_state: devctl_ap_unconfigure "
 993                             "failed with errno: %d\n", errno);
 994                         rv = CFGA_IB_UNCONFIG_OP_ERR;
 995                         if (errno == EBUSY) {
 996                                 rv = CFGA_IB_BUSY_ERR;
 997                         }
 998                         (void) ib_rcm_online(ap_id, errstring, devpath, flags);
 999 
1000                 } else {
1001                         (void) ib_rcm_remove(ap_id, errstring, devpath, flags);
1002                 }
1003 
1004                 S_FREE(devpath);
1005                 break;
1006 
1007         case CFGA_CMD_LOAD:
1008         case CFGA_CMD_UNLOAD:
1009         case CFGA_CMD_CONNECT:
1010         case CFGA_CMD_DISCONNECT:
1011                 (void) cfga_help(msgp, options, flags);
1012                 rv = CFGA_IB_OPNOTSUPP;
1013                 break;
1014 
1015         case CFGA_CMD_NONE:
1016         default:
1017                 (void) cfga_help(msgp, options, flags);
1018                 rv = CFGA_IB_INTERNAL_ERR;
1019         }
1020 
1021         ib_cleanup_after_devctl_cmd(hdl, nvl);
1022         return (ib_err_msg(errstring, rv, ap_id, errno));
1023 }
1024 
1025 
1026 /*
1027  * Function:
1028  *      cfga_private_func
1029  * Input:
1030  *      func            - The private function (passed w/ -x option)
1031  *      ap_id           - The attachment point of an IB fabric
1032  *      options         - Private function command options passed
1033  *                              by the cfgadm(1M)
1034  *      confp           - Whether this command requires confirmation?
1035  *      msgp            - cfgadm error message for this plugin
1036  *      errstring       - This contains error msg if command fails
1037  *      flags           - Cfgadm(1m) flags
1038  * Output:
1039  *      NONE
1040  * Returns:
1041  *      If the command succeeded perform the 'cfgadm -x <func>'; otherwise
1042  *      return failure.
1043  * Description:
1044  *      Do cfgadm -x <func>
1045  */
1046 /*ARGSUSED*/
1047 cfga_err_t
1048 cfga_private_func(const char *func, const char *ap_id, const char *options,
1049     struct cfga_confirm *confp, struct cfga_msg *msgp, char **errstring,
1050     cfga_flags_t flags)
1051 {
1052         int             len, ret, count = 0;
1053         char            *clnt_name = NULL, *alt_hca = NULL;
1054         char            *clnt_apid = NULL, *clnt_devpath = NULL;
1055         char            *name, *msg = NULL;
1056         char            *fab_apid = strstr((char *)ap_id, IBNEX_FABRIC);
1057         size_t          info_len = 0;
1058         uchar_t         *info = NULL;
1059         nvlist_t        *nvl;
1060         nvpair_t        *nvp = NULL;
1061         ap_rstate_t     rstate;
1062         devctl_hdl_t    hdl = NULL;
1063         cfga_ib_ret_t   rv;
1064 
1065         if ((rv = ib_verify_params(ap_id, NULL, errstring)) != CFGA_IB_OK) {
1066                 DPRINTF("cfga_private_func: ib_verify_params "
1067                     "failed with rv: %d\n", rv);
1068                 return (ib_err_msg(errstring, rv, ap_id, errno));
1069         }
1070 
1071         if (func == NULL) {
1072                 DPRINTF("cfga_private_func: func is NULL\n");
1073                 return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR, ap_id,
1074                     errno));
1075         }
1076 
1077         /*
1078          * check first if IB static ap_id is "configured" for use
1079          */
1080         if (fab_apid != NULL) {
1081                 if ((rv = ib_setup_for_devctl_cmd(fab_apid, B_TRUE, &hdl,
1082                     &nvl)) != CFGA_IB_OK) {
1083                         ib_cleanup_after_devctl_cmd(hdl, nvl);
1084                         return (ib_err_msg(errstring, rv, ap_id, errno));
1085                 }
1086                 if ((rv = ib_device_configured(hdl, nvl, &rstate)) ==
1087                     CFGA_IB_NOT_CONFIGURED) {
1088                         return (ib_err_msg(errstring, rv, ap_id, errno));
1089                 }
1090                 ib_cleanup_after_devctl_cmd(hdl, nvl);
1091         }
1092 
1093         rv = CFGA_IB_OK;
1094         DPRINTF("cfga_private_func: func is %s\n", func);
1095         if (strcmp(func, IB_LIST_HCA_CLIENTS) == 0) {   /* -x list_clients */
1096 
1097                 /* only supported on HCA ap_ids */
1098                 if (fab_apid != NULL) {
1099                         DPRINTF("cfga_private_func: fabric apid supplied\n");
1100                         return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1101                             ap_id, errno));
1102                 }
1103 
1104                 if ((msg = (char *)calloc(256, 1)) == NULL) {
1105                         DPRINTF("cfga_private_func: malloc for msg failed. "
1106                             "errno: %d\n", errno);
1107                         return (ib_err_msg(errstring, CFGA_IB_ALLOC_FAIL,
1108                             ap_id, errno));
1109                 }
1110 
1111                 if ((rv = ib_do_control_ioctl((char *)ap_id, IBNEX_HCA_LIST_SZ,
1112                     IBNEX_HCA_LIST_INFO, 0, (void **)&info, &info_len)) != 0) {
1113                         DPRINTF("cfga_private_func: "
1114                             "ib_do_control_ioctl list failed :%d\n", rv);
1115                         S_FREE(msg);
1116                         return (ib_err_msg(errstring, CFGA_IB_HCA_LIST_ERR,
1117                             ap_id, errno));
1118                 }
1119 
1120                 if (nvlist_unpack((char *)info, info_len, &nvl, 0)) {
1121                         DPRINTF("cfga_private_func: "
1122                             "nvlist_unpack 2 failed %p\n", info);
1123                         S_FREE(info);
1124                         S_FREE(msg);
1125                         return (ib_err_msg(errstring, CFGA_IB_NVLIST_ERR, ap_id,
1126                             errno));
1127                 }
1128 
1129                 (void) snprintf(msg, 256, "Ap_Id\t\t\t       IB Client\t\t "
1130                     "Alternate HCA\n");
1131                 cfga_msg(msgp, msg);
1132 
1133                 /* Walk the NVPAIR data */
1134                 while (nvp = nvlist_next_nvpair(nvl, nvp)) {
1135                         name = nvpair_name(nvp);
1136                         if (strcmp(name, "Client") == 0) {
1137                                 (void) nvpair_value_string(nvp, &clnt_name);
1138                                 ++count;
1139                         } else if (strcmp(name, "Alt_HCA") == 0) {
1140                                 (void) nvpair_value_string(nvp, &alt_hca);
1141                                 ++count;
1142                         } else if (strcmp(name, "ApID") == 0) {
1143                                 (void) nvpair_value_string(nvp, &clnt_apid);
1144                                 ++count;
1145                         }
1146 
1147                         /* check at the end; print message per client found */
1148                         if (count == 3) {
1149                                 count = 0;
1150                                 (void) snprintf(msg, 256, "%-30s %-25s %s\n",
1151                                     clnt_apid, clnt_name, alt_hca);
1152                                 cfga_msg(msgp, msg);
1153                         }
1154                 } /* end of while */
1155 
1156                 S_FREE(info);
1157                 S_FREE(msg);
1158                 nvlist_free(nvl);
1159 
1160         /* -x unconfig_clients */
1161         } else if (strcmp(func, IB_UNCONFIG_HCA_CLIENTS) == 0) {
1162                 /*
1163                  * -x unconfig_clients changes state by calling into RCM.
1164                  * It needs root privileges.
1165                  */
1166                 if (geteuid() != 0) {
1167                         return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
1168                             errno));
1169                 }
1170 
1171                 /* only supported on HCA ap_ids */
1172                 if (fab_apid != NULL) {
1173                         DPRINTF("cfga_private_func: fabric apid supplied\n");
1174                         return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1175                             ap_id, errno));
1176                 }
1177 
1178                 /*
1179                  * Check w/ user if it is ok to do this operation
1180                  * If the user fails to confirm, bailout
1181                  */
1182                 if (!ib_confirm(confp, IB_CONFIRM3))
1183                         return (CFGA_NACK);
1184 
1185                 /* Get device-paths of all the IOC/Port/Pseudo devices */
1186                 rv = ib_do_control_ioctl((char *)ap_id, IBNEX_UNCFG_CLNTS_SZ,
1187                     IBNEX_UNCFG_CLNTS_INFO, 0, (void **)&info, &info_len);
1188                 if (rv != 0) {
1189                         DPRINTF("cfga_private_func: ib_do_control_ioctl "
1190                             "failed :%d\n", rv);
1191                         return (ib_err_msg(errstring, CFGA_IB_HCA_UNCONFIG_ERR,
1192                             ap_id, errno));
1193                 }
1194 
1195                 if (nvlist_unpack((char *)info, info_len, &nvl, 0)) {
1196                         DPRINTF("cfga_private_func: nvlist_unpack failed %p\n",
1197                             info);
1198                         S_FREE(info);
1199                         return (ib_err_msg(errstring, CFGA_IB_NVLIST_ERR, ap_id,
1200                             errno));
1201                 }
1202 
1203                 ret = 0;
1204 
1205                 /* Call RCM Offline on all device paths */
1206                 while (nvp = nvlist_next_nvpair(nvl, nvp)) {
1207                         name = nvpair_name(nvp);
1208                         if (strcmp(name, "devpath") == 0) {
1209                                 (void) nvpair_value_string(nvp, &clnt_devpath);
1210                                 ++count;
1211                         } else if (strcmp(name, "ApID") == 0) {
1212                                 (void) nvpair_value_string(nvp, &clnt_apid);
1213                                 ++count;
1214                         }
1215 
1216                         /* handle the client unconfigure now */
1217                         if (count == 2) {
1218                                 count = 0;      /* reset count */
1219 
1220                                 DPRINTF("cfga_private_func: client apid = %s, "
1221                                     "DevPath = %s\n", clnt_apid, clnt_devpath);
1222                                 if ((rv = ib_setup_for_devctl_cmd(clnt_apid,
1223                                     B_TRUE, &hdl, &nvl)) != CFGA_IB_OK) {
1224                                         ib_cleanup_after_devctl_cmd(hdl, nvl);
1225                                         return (ib_err_msg(errstring, rv,
1226                                             clnt_apid, errno));
1227                                 }
1228 
1229                                 if ((rv = ib_device_configured(hdl, nvl,
1230                                     &rstate)) == CFGA_IB_NOT_CONFIGURED)
1231                                         continue;
1232 
1233                                 if ((rv = ib_rcm_offline(clnt_apid, errstring,
1234                                     clnt_devpath, flags)) != CFGA_IB_OK) {
1235                                         DPRINTF("cfga_private_func: client rcm "
1236                                             "offline failed for %s, with %d\n",
1237                                             clnt_devpath, rv);
1238                                         ret = rv;
1239                                         continue;
1240                                 }
1241 
1242                                 if (devctl_ap_unconfigure(hdl, nvl) != 0) {
1243                                         DPRINTF("cfga_private_func: client "
1244                                             "unconfigure failed: errno %d\n",
1245                                             errno);
1246                                         ret = CFGA_IB_UNCONFIG_OP_ERR;
1247                                         if (errno == EBUSY)
1248                                                 ret = CFGA_IB_BUSY_ERR;
1249                                         (void) ib_rcm_online(clnt_apid,
1250                                             errstring, clnt_devpath, flags);
1251                                         continue;
1252                                 } else {
1253                                         (void) ib_rcm_remove(clnt_apid,
1254                                             errstring, clnt_devpath, flags);
1255                                 }
1256                                 ib_cleanup_after_devctl_cmd(hdl, nvl);
1257 
1258                         } /* end of if count == 2 */
1259 
1260                 } /* end of while */
1261 
1262                 S_FREE(info);
1263                 nvlist_free(nvl);
1264                 if (ret) {
1265                         DPRINTF("cfga_private_func: unconfig_clients of %s "
1266                             "failed with %d\n", ap_id, ret);
1267                         return (ib_err_msg(errstring, CFGA_IB_UCFG_CLNTS_ERR,
1268                             ap_id, errno));
1269                 }
1270 
1271         /* -x update_pkey_tbls */
1272         } else if (strcmp(func, IB_UPDATE_PKEY_TBLS) == 0) {
1273                 /*
1274                  * Check for root privileges.
1275                  */
1276                 if (geteuid() != 0) {
1277                         return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
1278                             errno));
1279                 }
1280 
1281                 /* CHECK: Only supported on fabric ap_ids */
1282                 if (fab_apid == NULL || strcmp(fab_apid, IBNEX_FABRIC) != 0) {
1283                         DPRINTF("cfga_private_func: fabric apid needed\n");
1284                         return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1285                             ap_id, errno));
1286                 }
1287 
1288                 /* Check w/ user if it is ok to do this operation */
1289                 len = strlen(IB_CONFIRM4) + 10;
1290                 if ((msg = (char *)calloc(len, 1)) != NULL) {
1291                         (void) snprintf(msg, len, "%s\nContinue", IB_CONFIRM4);
1292                 }
1293 
1294                 /* If the user fails to confirm, return */
1295                 if (!ib_confirm(confp, msg)) {
1296                         free(msg);
1297                         return (CFGA_NACK);
1298                 }
1299                 free(msg);
1300 
1301                 /* Update P_Key tables for all ports of all HCAs */
1302                 rv = ib_do_control_ioctl((char *)ap_id, IBNEX_UPDATE_PKEY_TBLS,
1303                     0, 0, 0, &info_len);
1304 
1305                 if (rv != 0) {
1306                         DPRINTF("cfga_private_func: ib_do_control_ioctl "
1307                             "failed :%d\n", rv);
1308                         return (ib_err_msg(errstring, CFGA_IB_UPD_PKEY_TBLS_ERR,
1309                             ap_id, errno));
1310                 }
1311 
1312         /* -x [add_service|delete_service] */
1313         } else if ((strncmp(func, IB_ADD_SERVICE, 12) == 0) ||
1314             (strncmp(func, IB_DELETE_SERVICE, 15) == 0)) {
1315                 char                    *subopts, *val;
1316                 uint8_t                 cmd;
1317 
1318                 /* check: Only supported on fabric ap_ids */
1319                 if (fab_apid == NULL || strcmp(fab_apid, IBNEX_FABRIC) != 0) {
1320                         DPRINTF("cfga_private_func: fabric apid needed\n");
1321                         return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1322                             ap_id, errno));
1323                 }
1324 
1325                 /* Check for root privileges. */
1326                 if (geteuid() != 0) {
1327                         return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
1328                             errno));
1329                 }
1330 
1331                 /* return error if no options are specified */
1332                 subopts = (char *)options;
1333                 if (subopts == (char *)NULL) {
1334                         DPRINTF("cfga_private_func: no sub-options\n");
1335                         (void) cfga_help(msgp, options, flags);
1336                         return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR,
1337                             ap_id, errno));
1338                 }
1339 
1340                 /* parse options specified */
1341                 while (*subopts != '\0') {
1342                         switch (getsubopt(&subopts, ib_service_subopts, &val)) {
1343                         case 0: /* comm */
1344                                 if (val == NULL) {
1345                                         (void) cfga_help(msgp, options, flags);
1346                                         S_FREE(service_name);
1347                                         return (ib_err_msg(errstring,
1348                                             CFGA_IB_INVAL_ARG_ERR,
1349                                             ap_id, errno));
1350                                 } else {
1351                                         comm_name = strdup(val);
1352                                         if (comm_name == NULL) {
1353                                                 DPRINTF("comm sub-opt invalid "
1354                                                     "arg\n");
1355                                                 S_FREE(service_name);
1356                                                 return (ib_err_msg(errstring,
1357                                                     CFGA_IB_COMM_INVAL_ERR,
1358                                                     ap_id, errno));
1359                                         }
1360                                 }
1361                                 break;
1362 
1363                         case 1: /* service */
1364                                 if (val == NULL) {
1365                                         (void) cfga_help(msgp, options, flags);
1366                                         S_FREE(comm_name);
1367                                         return (ib_err_msg(errstring,
1368                                             CFGA_IB_INVAL_ARG_ERR,
1369                                             ap_id, errno));
1370                                 } else {
1371                                         /* service can be upto 4 long */
1372                                         if (strlen(val) == 0 ||
1373                                             strlen(val) > 4) {
1374                                                 DPRINTF("comm sub-opt invalid "
1375                                                     "service passed\n");
1376                                                 S_FREE(comm_name);
1377                                                 return (ib_err_msg(errstring,
1378                                                     CFGA_IB_SVC_LEN_ERR,
1379                                                     ap_id, errno));
1380                                         }
1381                                         service_name = strdup(val);
1382                                         if (service_name == NULL) {
1383                                                 DPRINTF("comm sub-opt "
1384                                                     "internal error\n");
1385                                                 S_FREE(comm_name);
1386                                                 return (ib_err_msg(errstring,
1387                                                     CFGA_IB_SVC_INVAL_ERR,
1388                                                     ap_id, errno));
1389                                         }
1390                                 }
1391                                 break;
1392 
1393                         default:
1394                                 (void) cfga_help(msgp, options, flags);
1395                                 S_FREE(comm_name);
1396                                 S_FREE(service_name);
1397                                 return (ib_err_msg(errstring,
1398                                     CFGA_IB_INVAL_ARG_ERR, ap_id, errno));
1399                         }
1400                 }
1401 
1402                 /* figure out the "operation" */
1403                 if (strncasecmp(func, IB_ADD_SERVICE, 11) == 0)
1404                         cmd = IBCONF_ADD_ENTRY;
1405                 else if (strncasecmp(func, IB_DELETE_SERVICE, 14) == 0)
1406                         cmd = IBCONF_DELETE_ENTRY;
1407                 DPRINTF("Service = %s, Comm = %s, Operation = %s\n",
1408                     service_name, comm_name, func);
1409 
1410                 if (strncasecmp(comm_name, IBNEX_PORT_STR, 4) == 0)
1411                         service_type = IB_PORT_SERVICE;
1412                 else if (strncasecmp(comm_name, IBNEX_VPPA_STR, 4) == 0)
1413                         service_type = IB_VPPA_SERVICE;
1414                 else if (strncasecmp(comm_name, IBNEX_HCASVC_STR, 4) == 0)
1415                         service_type = IB_HCASVC_SERVICE;
1416                 else {
1417                         (void) cfga_help(msgp, options, flags);
1418                         S_FREE(comm_name);
1419                         S_FREE(service_name);
1420                         return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR,
1421                             ap_id, errno));
1422                 }
1423 
1424                 /* do the add/delete entry to the service */
1425                 if (cmd == IBCONF_ADD_ENTRY) {
1426                         if ((rv = ib_add_service(errstring)) != CFGA_IB_OK)
1427                                 DPRINTF("cfga_private_func: add failed\n");
1428                 } else if (cmd == IBCONF_DELETE_ENTRY) {
1429                         if ((rv = ib_delete_service(errstring)) != CFGA_IB_OK)
1430                                 DPRINTF("cfga_private_func: delete failed\n");
1431                 }
1432 
1433                 S_FREE(comm_name);
1434                 S_FREE(service_name);
1435                 return (ib_err_msg(errstring, rv, ap_id, errno));
1436 
1437         } else if (strncmp(func, IB_LIST_SERVICES, 13) == 0) {
1438 
1439                 /* check: Only supported on fabric ap_ids */
1440                 if (fab_apid == NULL || strcmp(fab_apid, IBNEX_FABRIC) != 0) {
1441                         DPRINTF("cfga_private_func: fabric apid needed\n");
1442                         return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1443                             ap_id, errno));
1444                 }
1445 
1446                 /* do the list services */
1447                 rv = ib_list_services(msgp, errstring);
1448                 if (rv != CFGA_IB_OK) {
1449                         DPRINTF("cfga_private_func: ib_list_services failed\n");
1450                         return (ib_err_msg(errstring, rv, ap_id, errno));
1451                 }
1452 
1453         /* -x update_ioc_conf */
1454         } else if (strncmp(func, IB_UPDATE_IOC_CONF, 17) == 0) {
1455                 uint_t misc_arg;
1456 
1457                 /* Supported only with root privilege */
1458                 if (geteuid() != 0) {
1459                         return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
1460                             errno));
1461                 }
1462 
1463                 /*
1464                  * check: Only supported on fabric ap_id or IOC APID
1465                  * IOC APID does not have any commas in it.
1466                  */
1467                 if (fab_apid == NULL ||
1468                     (fab_apid != NULL && strstr(fab_apid, ",") != NULL)) {
1469                         DPRINTF("cfga_private_func: fabric/IOC apid needed\n");
1470                         return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1471                             ap_id, errno));
1472                 }
1473 
1474                 /* Check w/ user if it is ok to do this operation */
1475                 len = strlen(IB_CONFIRM5) + 10;
1476                 if ((msg = (char *)calloc(len, 1)) != NULL) {
1477                         (void) snprintf(msg, len, "%s\nContinue", IB_CONFIRM5);
1478                 }
1479 
1480                 /* If the user fails to confirm, return */
1481                 if (!ib_confirm(confp, msg)) {
1482                         free(msg);
1483                         return (CFGA_NACK);
1484                 }
1485                 free(msg);
1486 
1487                 misc_arg = (strcmp(fab_apid, IBNEX_FABRIC) == 0) ?
1488                     IBNEX_BASE_APID : IBNEX_DYN_APID;
1489 
1490                 /* Reprobe and update IOC(s) configuration */
1491                 rv = ib_do_control_ioctl((char *)ap_id, IBNEX_UPDATE_IOC_CONF,
1492                     0, misc_arg, 0, &info_len);
1493 
1494                 if (rv != 0) {
1495                         DPRINTF("cfga_private_func: ib_do_control_ioctl "
1496                             "failed :%d\n", rv);
1497                         return (ib_err_msg(errstring, CFGA_IB_DEVCTL_ERR,
1498                             ap_id, errno));
1499                 }
1500         } else {
1501                 DPRINTF("cfga_private_func: unrecognized command.\n");
1502                 (void) cfga_help(msgp, options, flags);
1503                 errno = EINVAL;
1504                 return (CFGA_INVAL);
1505         }
1506 
1507         return (ib_err_msg(errstring, rv, ap_id, errno));
1508 }
1509 
1510 
1511 /*
1512  * Function:
1513  *      cfga_test
1514  * Input:
1515  *      ap_id           - The attachment point of an IB fabric
1516  *      options         - Test command options passed by the cfgadm(1M)
1517  *      msgp            - cfgadm error message for this plugin
1518  *      errstring       - This contains error msg if command fails
1519  *      flags           - Cfgadm(1m) flags
1520  * Output:
1521  *      NONE
1522  * Returns:
1523  *      CFGA_OPNOTSUPP
1524  * Description:
1525  *      Do "cfgadm -t"
1526  */
1527 /*ARGSUSED*/
1528 cfga_err_t
1529 cfga_test(const char *ap_id, const char *options, struct cfga_msg *msgp,
1530     char **errstring, cfga_flags_t flags)
1531 {
1532         (void) cfga_help(msgp, options, flags);
1533         return (CFGA_OPNOTSUPP);
1534 }
1535 
1536 
1537 /*
1538  * Function:
1539  *      ib_fill_static_apids
1540  * Input:
1541  *      ap_id           - The static attachment point of an IB device
1542  *      clp             - The returned "list" information array
1543  * Output:
1544  *      NONE
1545  * Returns:
1546  *      Fills up the "list" information array for the static attachment point
1547  * Description:
1548  *      IB fabric supports two types of static attachment points.
1549  *      One is fabric and other is for the HCAs. This fills up
1550  *      "cfga_list_data_t" for static attachment points.
1551  */
1552 static cfga_ib_ret_t
1553 ib_fill_static_apids(char *ap_id, cfga_list_data_t *clp)
1554 {
1555         int     rv, l_err;
1556         char    *ap_id_log = NULL;
1557 
1558         /* Get /dev/cfg path to corresponding to the physical ap_id */
1559         /* Remember ap_id_log must be freed */
1560         if (ib_physpath_to_devlink(ap_id, &ap_id_log,
1561             &l_err) != ICFGA_OK) {
1562                 DPRINTF("ib_fill_static_apids: "
1563                     "ib_physpath_to_devlink failed\n");
1564                 return (CFGA_IB_DEVLINK_ERR);
1565         }
1566         assert(ap_id_log != NULL);
1567 
1568         /* Get logical ap-id corresponding to the physical */
1569         if (strstr(ap_id_log, CFGA_DEV_DIR) == NULL) {
1570                 DPRINTF("ib_fill_static_apids: devlink doesn't contain "
1571                     "/dev/cfg\n");
1572                 free(ap_id_log);
1573                 return (CFGA_IB_DEVLINK_ERR);
1574         }
1575 
1576         clp->ap_cond = CFGA_COND_OK;
1577         clp->ap_r_state = CFGA_STAT_CONNECTED;
1578         clp->ap_o_state = CFGA_STAT_CONFIGURED;
1579         clp->ap_class[0] = '\0';     /* Filled by libcfgadm */
1580         clp->ap_busy = 0;
1581         clp->ap_status_time = (time_t)-1;
1582         (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s",
1583             /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR) + 1);
1584         (void) strlcpy(clp->ap_phys_id, ap_id, sizeof (clp->ap_phys_id));
1585 
1586         /* Static IB apid */
1587         if (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL)  {
1588                 (void) strlcpy(clp->ap_type, IB_FABRIC_TYPE,
1589                     sizeof (clp->ap_type));  /* Fill in type */
1590                 (void) strlcpy(clp->ap_info, IB_FABRIC_INFO,
1591                     sizeof (clp->ap_info));
1592 
1593         } else {        /* Static HCA apid */
1594                 size_t  size = 0;
1595                 uchar_t *data = NULL;
1596 
1597                 (void) strlcpy(clp->ap_type, IB_HCA_TYPE,
1598                     sizeof (clp->ap_type));  /* Fill in type */
1599 
1600                 rv = ib_do_control_ioctl(ap_id, IBNEX_HCA_VERBOSE_SZ,
1601                     IBNEX_HCA_VERBOSE_INFO, 0, (void **)&data, &size);
1602                 if (rv != 0) {
1603                         DPRINTF("ib_fill_static_apids: ib_do_control_ioctl "
1604                             "failed :%d\n", rv);
1605                         free(ap_id_log);
1606                         S_FREE(data);
1607                         return (CFGA_IB_IOCTL_ERR);
1608                 }
1609 
1610                 (void) strlcpy(clp->ap_info, (char *)data,
1611                     sizeof (clp->ap_info));
1612                 S_FREE(data);
1613         }
1614         free(ap_id_log);
1615         return (CFGA_IB_OK);
1616 }
1617 
1618 
1619 /*
1620  * Function:
1621  *      cfga_list_ext
1622  * Input:
1623  *      ap_id           - The attachment point of an IB fabric
1624  *      ap_id_list      - The returned "list" information array
1625  *      nlistp          - Number of elements in the "list" information array
1626  *      options         - List command options passed by the cfgadm(1M)
1627  *      listopts        - "-s" specific options
1628  *      errstring       - This contains error msg if command fails
1629  *      flags           - Cfgadm(1m) flags
1630  * Output:
1631  *      NONE
1632  * Returns:
1633  *      If the command succeeded, cfgadm -l output otherwise an error
1634  * Description:
1635  *      Do cfgadm -l
1636  */
1637 /*ARGSUSED*/
1638 cfga_err_t
1639 cfga_list_ext(const char *ap_id, cfga_list_data_t **ap_id_list, int *nlistp,
1640     const char *options, const char *listopts, char **errstring,
1641     cfga_flags_t flags)
1642 {
1643         int                     expand = 0;
1644         int                     i, index, count;
1645         int                     show_dynamic = 0;
1646         size_t                  num_devices = 0;
1647         size_t                  num_hcas = 0;
1648         size_t                  snap_size = 0;
1649         uchar_t                 *snap_data = NULL;
1650         nvpair_t                *nvp = NULL;    /* for lint purposes */
1651         nvlist_t                *nvl = NULL;
1652         boolean_t               apid_matched = B_FALSE; /* for valid ap_id */
1653         cfga_ib_ret_t           rv = CFGA_IB_OK;
1654         cfga_list_data_t        *clp = NULL;
1655 
1656         if ((rv = ib_verify_params(ap_id, options, errstring)) != CFGA_IB_OK) {
1657                 (void) cfga_help(NULL, options, flags);
1658                 return (ib_err_msg(errstring, rv, ap_id, errno));
1659         }
1660 
1661         /* make sure we have a valid ap_id_list */
1662         if (ap_id_list == NULL || nlistp == NULL) {
1663                 DPRINTF("cfga_list_ext: list = NULL or nlistp = NULL\n");
1664                 (void) cfga_help(NULL, options, flags);
1665                 return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR,
1666                     ap_id, errno));
1667         }
1668 
1669         DPRINTF("cfga_list_ext: ap_id = %s\n", ap_id);
1670 
1671         if ((flags & CFGA_FLAG_LIST_ALL) == CFGA_FLAG_LIST_ALL) {
1672                 expand = 1;             /* -a flag passed */
1673         }
1674 
1675         if (GET_DYN(ap_id) != NULL) {
1676                 show_dynamic = 1;
1677         }
1678 
1679         if ((expand == 1) &&    /* -a option passed */
1680             (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL)) {
1681                 /*
1682                  * Figure out how many IOC/Port/Pseudo
1683                  * devices exist in the system?
1684                  */
1685                 if ((rv = ib_do_control_ioctl((char *)ap_id,
1686                     IBNEX_NUM_DEVICE_NODES, 0, 0, 0, &num_devices)) !=
1687                     CFGA_IB_OK) {
1688                         DPRINTF("cfga_list_ext: ib_do_control_ioctl "
1689                             "IBNEX_NUM_DEVICE_NODES failed :%d\n", rv);
1690                         if (errno == ENOENT)
1691                                 return (CFGA_APID_NOEXIST);
1692                         return (ib_err_msg(errstring, rv, ap_id, errno));
1693                 }
1694 
1695                 DPRINTF("cfga_list_ext: num_devices = %d\n", num_devices);
1696         }
1697 
1698         /* Figure out how many HCA nodes exist in the system. */
1699         if ((rv = ib_do_control_ioctl((char *)ap_id, IBNEX_NUM_HCA_NODES, 0, 0,
1700             0, &num_hcas)) != CFGA_IB_OK) {
1701                 DPRINTF("cfga_list_ext: ib_do_control_ioctl "
1702                     "IBNEX_NUM_HCA_NODES failed :%d\n", rv);
1703                 if (errno == ENOENT)
1704                         return (CFGA_APID_NOEXIST);
1705                 return (ib_err_msg(errstring, rv, ap_id, errno));
1706         }
1707         DPRINTF("cfga_list_ext: num_hcas = %d\n", num_hcas);
1708 
1709         /*
1710          * No HCAs or IOC/VPPA/Port/HCA_SVC/Pseudo devices seen (non-IB system)
1711          */
1712         if (!(num_hcas || num_devices)) {
1713                 DPRINTF("cfga_list_ext: no IB devices found\n");
1714                 return (CFGA_APID_NOEXIST);
1715         }
1716 
1717         /*
1718          * *nlistp contains to how many APIDs to show w/ cfgadm -l.
1719          * If ap_id is "fabric" then
1720          *      *nlistp is all Dynamic Apids + One more for "fabric"
1721          * If ap_id is "HCA" ap_id then
1722          *      *nlistp is 1
1723          * Note that each HCA is a static APID, so nlistp will be 1 always
1724          * and this function will be called N times for each of the N HCAs
1725          * in the host.
1726          */
1727         if (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL) {
1728                 *nlistp = num_devices + 1;
1729 
1730         } else {
1731                 /* Assume it as a HCA ap_id */
1732                 *nlistp = 1;
1733         }
1734 
1735         /* Allocate storage for passing "list" info back */
1736         if ((*ap_id_list = (cfga_list_data_t *)calloc(*nlistp,
1737             sizeof (cfga_list_data_t))) == NULL) {
1738                 DPRINTF("cfga_list_ext: malloc for cfga_list_data_t failed. "
1739                     "errno: %d\n", errno);
1740                 return (ib_err_msg(errstring, CFGA_IB_ALLOC_FAIL,
1741                     ap_id, errno));
1742         }
1743 
1744         /*
1745          * Only static ap_id is ib_fabric:
1746          * If -a options isn't specified then only show the static ap_id.
1747          */
1748         if (!show_dynamic) {
1749                 clp = &(*ap_id_list[0]);
1750 
1751                 if ((rv = ib_fill_static_apids((char *)ap_id, clp)) !=
1752                     CFGA_IB_OK) {
1753                         S_FREE(*ap_id_list);
1754                         return (ib_err_msg(errstring, rv, ap_id, errno));
1755                 }
1756                 apid_matched = B_TRUE;
1757         }
1758 
1759         /*
1760          * No -a specified
1761          * No HCAs or IOC/VPPA/HCA_SVC/Port/Pseudo devices seen (non-IB system)
1762          */
1763         if (!expand || (!num_hcas && !num_devices)) {
1764                 if (!show_dynamic)
1765                         return (CFGA_OK);
1766         }
1767 
1768         if (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL) {
1769                 rv = ib_do_control_ioctl((char *)ap_id, IBNEX_SNAPSHOT_SIZE,
1770                     IBNEX_GET_SNAPSHOT, IBNEX_DONOT_PROBE_FLAG,
1771                     (void **)&snap_data, &snap_size);
1772                 if (rv != 0) {
1773                         DPRINTF("cfga_list_ext: ib_do_control_ioctl "
1774                             "failed :%d\n", rv);
1775                         S_FREE(*ap_id_list);
1776                         S_FREE(snap_data);
1777                         return (ib_err_msg(errstring, rv, ap_id, errno));
1778                 }
1779 
1780                 if (nvlist_unpack((char *)snap_data, snap_size, &nvl, 0)) {
1781                         DPRINTF("cfga_list_ext: nvlist_unpack 1 failed %p\n",
1782                             snap_data);
1783                         S_FREE(*ap_id_list);
1784                         S_FREE(snap_data);
1785                         return (ib_err_msg(errstring, CFGA_IB_NVLIST_ERR,
1786                             ap_id, errno));
1787                 }
1788 
1789                 /*
1790                  * In kernel a nvlist is build per ap_id which contains
1791                  * information that is displayed using cfgadm -l.
1792                  * For IB devices only these 6 items are shown:
1793                  *      ap_id, type, occupant, receptacle, condition and info
1794                  *
1795                  * In addition, one could specify a dynamic ap_id from
1796                  * command-line. Then cfgadm -l should show only that
1797                  * ap_id and skip rest.
1798                  */
1799                 index = 1; count = 0;
1800                 while (nvp = nvlist_next_nvpair(nvl, nvp)) {
1801                         int32_t intval = 0;
1802                         int32_t node_type;
1803                         char    *info;
1804                         char    *nv_apid;
1805                         char    *name = nvpair_name(nvp);
1806 
1807                         /* start of with next device */
1808                         if (count == IB_NUM_NVPAIRS) {
1809                                 count = 0;
1810                                 ++index;
1811                         }
1812 
1813                         /*
1814                          * Check if the index doesn't go beyond the
1815                          * device number. If it goes, stop the loop
1816                          * here not to cause the heap corruption.
1817                          */
1818                         if (show_dynamic == 0 && index > num_devices)
1819                                 break;
1820 
1821                         /* fill up data into "clp" */
1822                         clp =  (show_dynamic != 0) ? &(*ap_id_list[0]) :
1823                             &(ap_id_list[0][index]);
1824 
1825                         /* First nvlist entry is "ap_id" always */
1826                         if (strcmp(name, IBNEX_NODE_APID_NVL) == 0) {
1827                                 (void) nvpair_value_string(nvp, &nv_apid);
1828                                 DPRINTF("cfga_list_ext: Name = %s, apid = %s\n",
1829                                     name, nv_apid);
1830 
1831                                 /*
1832                                  * If a dynamic ap_id is specified in the
1833                                  * command-line, skip all entries until
1834                                  * the one needed matches.
1835                                  */
1836                                 if (show_dynamic &&
1837                                     strstr(ap_id, nv_apid) == NULL) {
1838                                         DPRINTF("cfga_list_ext: NO MATCH\n");
1839 
1840                                         /*
1841                                          * skip rest of the entries of this
1842                                          * device.
1843                                          */
1844                                         for (i = 0; i < IB_NUM_NVPAIRS - 1; i++)
1845                                                 nvp = nvlist_next_nvpair(nvl,
1846                                                     nvp);
1847                                         count = 0;      /* reset it */
1848                                         continue;
1849                                 }
1850 
1851                                 apid_matched = B_TRUE;
1852 
1853                                 /* build the physical ap_id */
1854                                 if (strstr(ap_id, DYN_SEP) == NULL) {
1855                                         (void) snprintf(clp->ap_phys_id,
1856                                             sizeof (clp->ap_phys_id), "%s%s%s",
1857                                             ap_id, DYN_SEP, nv_apid);
1858                                 } else {
1859                                         (void) snprintf(clp->ap_phys_id,
1860                                             sizeof (clp->ap_phys_id), "%s",
1861                                             ap_id);
1862                                 }
1863 
1864                                 /* ensure that this is a valid apid */
1865                                 if (ib_verify_valid_apid(clp->ap_phys_id) !=
1866                                     0) {
1867                                         DPRINTF("cfga_list_ext: "
1868                                             "not a valid IB ap_id\n");
1869                                         S_FREE(*ap_id_list);
1870                                         S_FREE(snap_data);
1871                                         nvlist_free(nvl);
1872                                         return (ib_err_msg(errstring,
1873                                             CFGA_IB_AP_ERR, ap_id, errno));
1874                                 }
1875 
1876                                 /* build the logical ap_id */
1877                                 (void) snprintf(clp->ap_log_id,
1878                                     sizeof (clp->ap_log_id), "ib%s%s",
1879                                     DYN_SEP, nv_apid);
1880                                 DPRINTF("cfga_list_ext: ap_pi = %s, ap_li = %s,"
1881                                     "\nap_info = %s\n", clp->ap_phys_id,
1882                                     clp->ap_log_id, clp->ap_info);
1883                                 ++count;
1884 
1885                         } else if (strcmp(name, IBNEX_NODE_INFO_NVL) == 0) {
1886                                 (void) nvpair_value_string(nvp, &info);
1887                                 DPRINTF("cfga_list_ext: Name = %s, info = %s\n",
1888                                     name, info);
1889                                 (void) snprintf(clp->ap_info,
1890                                     sizeof (clp->ap_info), "%s", info);
1891                                 ++count;
1892 
1893                         } else if (strcmp(name, IBNEX_NODE_TYPE_NVL) == 0) {
1894                                 (void) nvpair_value_int32(nvp, &node_type);
1895                                 if (node_type == IBNEX_PORT_NODE_TYPE) {
1896                                         (void) snprintf(clp->ap_type,
1897                                             sizeof (clp->ap_type), "%s",
1898                                             IB_PORT_TYPE);
1899                                 } else if (node_type == IBNEX_VPPA_NODE_TYPE) {
1900                                         (void) snprintf(clp->ap_type,
1901                                             sizeof (clp->ap_type), "%s",
1902                                             IB_VPPA_TYPE);
1903                                 } else if (node_type ==
1904                                     IBNEX_HCASVC_NODE_TYPE) {
1905                                         (void) snprintf(clp->ap_type,
1906                                             sizeof (clp->ap_type), "%s",
1907                                             IB_HCASVC_TYPE);
1908                                 } else if (node_type == IBNEX_IOC_NODE_TYPE) {
1909                                         (void) snprintf(clp->ap_type,
1910                                             sizeof (clp->ap_type), "%s",
1911                                             IB_IOC_TYPE);
1912                                 } else if (node_type ==
1913                                     IBNEX_PSEUDO_NODE_TYPE) {
1914                                         (void) snprintf(clp->ap_type,
1915                                             sizeof (clp->ap_type), "%s",
1916                                             IB_PSEUDO_TYPE);
1917                                 }
1918                                 DPRINTF("cfga_list_ext: Name = %s, type = %x\n",
1919                                     name, intval);
1920                                 ++count;
1921 
1922                         } else if (strcmp(name, IBNEX_NODE_RSTATE_NVL) == 0) {
1923                                 (void) nvpair_value_int32(nvp, &intval);
1924 
1925                                 if (intval == AP_RSTATE_EMPTY)
1926                                         clp->ap_r_state = CFGA_STAT_EMPTY;
1927                                 else if (intval == AP_RSTATE_DISCONNECTED)
1928                                         clp->ap_r_state =
1929                                             CFGA_STAT_DISCONNECTED;
1930                                 else if (intval == AP_RSTATE_CONNECTED)
1931                                         clp->ap_r_state = CFGA_STAT_CONNECTED;
1932                                 DPRINTF("cfga_list_ext: Name = %s, "
1933                                     "rstate = %x\n", name, intval);
1934                                 ++count;
1935 
1936                         } else if (strcmp(name, IBNEX_NODE_OSTATE_NVL) == 0) {
1937                                 (void) nvpair_value_int32(nvp, &intval);
1938 
1939                                 if (intval == AP_OSTATE_CONFIGURED)
1940                                         clp->ap_o_state = CFGA_STAT_CONFIGURED;
1941                                 else if (intval == AP_OSTATE_UNCONFIGURED)
1942                                         clp->ap_o_state =
1943                                             CFGA_STAT_UNCONFIGURED;
1944                                 DPRINTF("cfga_list_ext: Name = %s, "
1945                                     "ostate = %x\n", name, intval);
1946                                 ++count;
1947 
1948                         } else if (strcmp(name, IBNEX_NODE_COND_NVL) == 0) {
1949                                 (void) nvpair_value_int32(nvp, &intval);
1950 
1951                                 if (intval == AP_COND_OK)
1952                                         clp->ap_cond = CFGA_COND_OK;
1953                                 else if (intval == AP_COND_FAILING)
1954                                         clp->ap_cond = CFGA_COND_FAILING;
1955                                 else if (intval == AP_COND_FAILED)
1956                                         clp->ap_cond = CFGA_COND_FAILED;
1957                                 else if (intval == AP_COND_UNUSABLE)
1958                                         clp->ap_cond = CFGA_COND_UNUSABLE;
1959                                 else if (intval == AP_COND_UNKNOWN)
1960                                         clp->ap_cond = CFGA_COND_UNKNOWN;
1961                                 DPRINTF("cfga_list_ext: Name = %s, "
1962                                     "condition = %x\n", name, intval);
1963                                 ++count;
1964                         }
1965 
1966                         clp->ap_class[0] = '\0'; /* Filled by libcfgadm */
1967                         clp->ap_busy = 0;
1968                         clp->ap_status_time = (time_t)-1;
1969                 } /* end of while */
1970         }
1971 
1972         S_FREE(snap_data);
1973         nvlist_free(nvl);
1974 
1975         /*
1976          * if a cmdline specified ap_id doesn't match the known list of ap_ids
1977          * then report an error right away
1978          */
1979         rv = (apid_matched ==  B_TRUE) ? CFGA_IB_OK : CFGA_IB_AP_ERR;
1980         return (ib_err_msg(errstring, rv, ap_id, errno));
1981 }
1982 
1983 
1984 /*
1985  * Function:
1986  *      cfga_msg
1987  * Input:
1988  *      msgp            - cfgadm error message for this plugin
1989  *      str             - string to be passed on to the message
1990  * Output:
1991  *      NONE
1992  * Returns:
1993  *      NONE
1994  * Description:
1995  *      This routine accepts a variable number of message IDs and
1996  *      constructs a corresponding error string which is printed
1997  *      via the message print routine argument.
1998  */
1999 void
2000 cfga_msg(struct cfga_msg *msgp, const char *str)
2001 {
2002         int len;
2003         char *q;
2004 
2005         if (msgp == NULL || msgp->message_routine == NULL) {
2006                 DPRINTF("cfga_msg: msg\n");
2007                 return;
2008         }
2009 
2010         if ((len = strlen(str)) == 0) {
2011                 DPRINTF("cfga_msg: null str\n");
2012                 return;
2013         }
2014 
2015         if ((q = (char *)calloc(len + 1, 1)) == NULL) {
2016                 DPRINTF("cfga_msg: null q\n");
2017                 return;
2018         }
2019 
2020         (void) strlcpy(q, str, len + 1);
2021         (*msgp->message_routine)(msgp->appdata_ptr, q);
2022 
2023         free(q);
2024 }
2025 
2026 
2027 /*
2028  * Function:
2029  *      cfga_help
2030  * Input:
2031  *      msgp            - Help message passed on to cfgadm(1M)
2032  *      options         - Help message options passed on to cfgadm(1M)
2033  *      flags           - Cfgadm(1m) flags
2034  * Output:
2035  *      NONE
2036  * Returns:
2037  *      Were we able to print cfgadm help or not for this plugin
2038  * Description:
2039  *      Print cfgadm help for this plugin
2040  */
2041 /* ARGSUSED */
2042 cfga_err_t
2043 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
2044 {
2045         DPRINTF("cfga_help:\n");
2046 
2047         if (options) {
2048                 cfga_msg(msgp, dgettext(TEXT_DOMAIN, ib_help[
2049                     CFGA_IB_HELP_UNKNOWN]));
2050                 cfga_msg(msgp, options);
2051         }
2052 
2053         /* Print messages array */
2054         cfga_msg(msgp, dgettext(TEXT_DOMAIN, ib_help[CFGA_IB_HELP_HEADER]));
2055         cfga_msg(msgp, ib_help[CFGA_IB_HELP_CONFIG]);
2056         cfga_msg(msgp, ib_help[CFGA_IB_HELP_LIST]);
2057         cfga_msg(msgp, ib_help[CFGA_IB_HELP_UPD_PKEY]);
2058         cfga_msg(msgp, ib_help[CFGA_IB_HELP_CONF_FILE1]);
2059         cfga_msg(msgp, ib_help[CFGA_IB_HELP_CONF_FILE2]);
2060         cfga_msg(msgp, ib_help[CFGA_IB_HELP_UPD_IOC_CONF]);
2061         cfga_msg(msgp, ib_help[CFGA_IB_HELP_UNCFG_CLNTS]);
2062 
2063         return (CFGA_OK);
2064 }
2065 
2066 
2067 /*
2068  * Function:
2069  *      ib_confirm
2070  * Input:
2071  *      confp           - The "cfga" structure that confirms a cfgadm query
2072  *      msg             - The message that needs confirmation
2073  * Output:
2074  *      None
2075  * Returns:
2076  *      If a user entered YES or NO
2077  * Description:
2078  *      Queries a user if it is ok to proceed with an operation or not.
2079  *      Returns user's response.
2080  */
2081 static int
2082 ib_confirm(struct cfga_confirm *confp, char *msg)
2083 {
2084         int rval;
2085 
2086         /* check that "confirm" function exists */
2087         if (confp == NULL || confp->confirm == NULL) {
2088                 return (0);
2089         }
2090 
2091         /* Call cfgadm provided "confirm" function */
2092         rval = (*confp->confirm)(confp->appdata_ptr, msg);
2093         DPRINTF("ib_confirm: %d\n", rval);
2094 
2095         return (rval);
2096 }
2097 
2098 
2099 /*
2100  * Function:
2101  *      ib_get_devicepath
2102  * Input:
2103  *      ap_id           - The dynamic attachment point of an IB device
2104  * Output:
2105  *      None
2106  * Returns:
2107  *      devpath if it exists; otherwise NULL
2108  * Description:
2109  *      Returns the devicepath for a dynamic attachment point of an IB device
2110  */
2111 static char *
2112 ib_get_devicepath(const char *ap_id)
2113 {
2114         char            *devpath = NULL;
2115         size_t          size;
2116 
2117         /* Get device path sizes */
2118         if (ib_do_control_ioctl((char *)ap_id, IBNEX_DEVICE_PATH_SZ,
2119             IBNEX_GET_DEVICE_PATH, 0, (void **)&devpath, &size) == CFGA_IB_OK) {
2120                 DPRINTF("ib_get_devicepath: get device path ioctl ok\n");
2121                 return (devpath);
2122 
2123         } else {
2124                 DPRINTF("ib_get_devicepath: get device path ioctl failed\n");
2125                 return ((char *)NULL);
2126         }
2127 }