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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright (c) 2016 by Delphix. All rights reserved.
  24  */
  25 
  26 #include <sys/ib/mgt/ibcm/ibcm_impl.h>
  27 #include <sys/ib/mgt/ibcm/ibcm_arp.h>
  28 
  29 /*
  30  * ibcm_path.c
  31  *
  32  * ibt_get_paths() implement the Path Informations related functionality.
  33  */
  34 
  35 /* ibcm_saa_service_rec() fills in ServiceID and DGID. */
  36 typedef struct ibcm_dest_s {
  37         ib_gid_t        d_gid;
  38         ib_svc_id_t     d_sid;
  39         ibt_srv_data_t  d_sdata;
  40         ib_pkey_t       d_pkey;
  41         uint_t          d_tag;  /* 0 = Unicast, 1 = Multicast */
  42 } ibcm_dest_t;
  43 
  44 /* Holds Destination information needed to fill in ibt_path_info_t. */
  45 typedef struct ibcm_dinfo_s {
  46         uint8_t         num_dest;
  47         ib_pkey_t       p_key;
  48         ibcm_dest_t     dest[1];
  49 } ibcm_dinfo_t;
  50 
  51 _NOTE(SCHEME_PROTECTS_DATA("Temporary path storage", ibcm_dinfo_s))
  52 _NOTE(READ_ONLY_DATA(ibt_path_attr_s))
  53 
  54 typedef struct ibcm_path_tqargs_s {
  55         ibt_path_attr_t         attr;
  56         ibt_path_info_t         *paths;
  57         uint8_t                 *num_paths_p;
  58         ibt_path_handler_t      func;
  59         void                    *arg;
  60         ibt_path_flags_t        flags;
  61         uint8_t                 max_paths;
  62 } ibcm_path_tqargs_t;
  63 
  64 
  65 /* Prototype Declarations. */
  66 static ibt_status_t ibcm_saa_path_rec(ibcm_path_tqargs_t *,
  67     ibtl_cm_port_list_t *, ibcm_dinfo_t *, uint8_t *);
  68 
  69 static ibt_status_t ibcm_update_cep_info(sa_path_record_t *,
  70     ibtl_cm_port_list_t *, ibtl_cm_hca_port_t *, ibt_cep_path_t *);
  71 
  72 static ibt_status_t ibcm_saa_service_rec(ibcm_path_tqargs_t *,
  73     ibtl_cm_port_list_t *, ibcm_dinfo_t *);
  74 
  75 static ibt_status_t ibcm_get_single_pathrec(ibcm_path_tqargs_t *,
  76     ibtl_cm_port_list_t *, ibcm_dinfo_t *, uint8_t,
  77     uint8_t *, ibt_path_info_t *);
  78 
  79 static ibt_status_t ibcm_get_multi_pathrec(ibcm_path_tqargs_t *,
  80     ibtl_cm_port_list_t *, ibcm_dinfo_t *dinfo,
  81     uint8_t *, ibt_path_info_t *);
  82 
  83 static ibt_status_t ibcm_validate_path_attributes(ibt_path_attr_t *attrp,
  84     ibt_path_flags_t flags, uint8_t max_paths);
  85 
  86 static ibt_status_t ibcm_handle_get_path(ibt_path_attr_t *attrp,
  87     ibt_path_flags_t flags, uint8_t max_paths, ibt_path_info_t *paths,
  88     uint8_t *num_path_p, ibt_path_handler_t func, void  *arg);
  89 
  90 static void ibcm_process_async_get_paths(void *tq_arg);
  91 
  92 static ibt_status_t ibcm_process_get_paths(void *tq_arg);
  93 
  94 static ibt_status_t ibcm_get_comp_pgids(ib_gid_t, ib_gid_t, ib_guid_t,
  95     ib_gid_t **, uint_t *);
  96 
  97 /*
  98  * Function:
  99  *      ibt_aget_paths
 100  * Input:
 101  *      ibt_hdl         The handle returned to the client by the IBTF from an
 102  *                      ibt_attach() call. Can be used by the IBTF Policy module
 103  *                      and CM in the determination of the "best" path to the
 104  *                      specified destination for this class of driver.
 105  *      flags           Path flags.
 106  *      attrp           Points to an ibt_path_attr_t struct that contains
 107  *                      required and optional attributes.
 108  *      func            A pointer to an ibt_path_handler_t function to call
 109  *                      when ibt_aget_paths() completes.
 110  *      arg             The argument to 'func'.
 111  * Returns:
 112  *      IBT_SUCCESS on early validation of attributes else appropriate error.
 113  * Description:
 114  *      Finds the best path to a specified destination or service
 115  *      asynchronously (as determined by the IBTL) that satisfies the
 116  *      requirements specified in an ibt_path_attr_t struct.
 117  *      ibt_aget_paths() is a Non-Blocking version of ibt_get_paths().
 118  */
 119 ibt_status_t
 120 ibt_aget_paths(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags,
 121     ibt_path_attr_t *attrp, uint8_t max_paths, ibt_path_handler_t func,
 122     void  *arg)
 123 {
 124         IBTF_DPRINTF_L3(cmlog, "ibt_aget_paths(%p(%s), 0x%X, %p, %d, %p)",
 125             ibt_hdl, ibtl_cm_get_clnt_name(ibt_hdl), flags, attrp, max_paths,
 126             func);
 127 
 128         if (func == NULL) {
 129                 IBTF_DPRINTF_L2(cmlog, "ibt_aget_paths: Function Pointer is "
 130                     "NULL - ERROR ");
 131                 return (IBT_INVALID_PARAM);
 132         }
 133 
 134         /* Memory for path info will be allocated in ibcm_process_get_paths() */
 135         return (ibcm_handle_get_path(attrp, flags, max_paths, NULL, NULL,
 136             func, arg));
 137 }
 138 
 139 
 140 /*
 141  * ibt_get_paths() cache consists of one or more of:
 142  *
 143  *      ib_gid_t dgid (attrp->pa_dgids[0])
 144  *      ibt_path_attr_t attr
 145  *      ibt_path_flags_t flags
 146  *      ibt_path_info_t path
 147  *
 148  * If the first 3 match, max_paths is 1, sname is NULL, and sid is 0,
 149  * then the path is returned immediately.
 150  *
 151  * Note that a compare of "attr" is non-trivial.  Only accept ones
 152  * that memcmp() succeeds, i.e., basically assume a bzero was done.
 153  *
 154  * Cache must be invalidated if PORT_DOWN event or GID_UNAVAIL occurs.
 155  * Cache must be freed as part of _fini.
 156  */
 157 
 158 #define IBCM_PATH_CACHE_SIZE    16      /* keep small for linear search */
 159 #define IBCM_PATH_CACHE_TIMEOUT 60      /* purge cache after 60 seconds */
 160 
 161 typedef struct ibcm_path_cache_s {
 162         ib_gid_t                dgid;
 163         ibt_path_attr_t         attr;
 164         ibt_path_flags_t        flags;
 165         ibt_path_info_t         path;
 166 } ibcm_path_cache_t;
 167 
 168 kmutex_t ibcm_path_cache_mutex;
 169 int ibcm_path_cache_invalidate; /* invalidate cache on next ibt_get_paths */
 170 clock_t ibcm_path_cache_timeout = IBCM_PATH_CACHE_TIMEOUT; /* tunable */
 171 timeout_id_t ibcm_path_cache_timeout_id;
 172 int ibcm_path_cache_size_init = IBCM_PATH_CACHE_SIZE;   /* tunable */
 173 int ibcm_path_cache_size;
 174 ibcm_path_cache_t *ibcm_path_cachep;
 175 
 176 /* tunable, set to 1 to not allow link-local address */
 177 int     ibcm_ip6_linklocal_addr_ok = 0;
 178 
 179 struct ibcm_path_cache_stat_s {
 180         int hits;
 181         int misses;
 182         int adds;
 183         int already_in_cache;
 184         int bad_path_for_cache;
 185         int purges;
 186         int timeouts;
 187 } ibcm_path_cache_stats;
 188 
 189 /*ARGSUSED*/
 190 static void
 191 ibcm_path_cache_timeout_cb(void *arg)
 192 {
 193         clock_t timeout_in_hz;
 194 
 195         timeout_in_hz = drv_usectohz(ibcm_path_cache_timeout * 1000000);
 196         mutex_enter(&ibcm_path_cache_mutex);
 197         ibcm_path_cache_invalidate = 1; /* invalidate cache on next check */
 198         if (ibcm_path_cache_timeout_id)
 199                 ibcm_path_cache_timeout_id = timeout(ibcm_path_cache_timeout_cb,
 200                     NULL, timeout_in_hz);
 201         /* else we're in _fini */
 202         mutex_exit(&ibcm_path_cache_mutex);
 203 }
 204 
 205 void
 206 ibcm_path_cache_init(void)
 207 {
 208         clock_t timeout_in_hz;
 209         int cache_size = ibcm_path_cache_size_init;
 210         ibcm_path_cache_t *path_cachep;
 211 
 212         timeout_in_hz = drv_usectohz(ibcm_path_cache_timeout * 1000000);
 213         path_cachep = kmem_zalloc(cache_size * sizeof (*path_cachep), KM_SLEEP);
 214         mutex_init(&ibcm_path_cache_mutex, NULL, MUTEX_DEFAULT, NULL);
 215         mutex_enter(&ibcm_path_cache_mutex);
 216         ibcm_path_cache_size = cache_size;
 217         ibcm_path_cachep = path_cachep;
 218         ibcm_path_cache_timeout_id = timeout(ibcm_path_cache_timeout_cb,
 219             NULL, timeout_in_hz);
 220         mutex_exit(&ibcm_path_cache_mutex);
 221 }
 222 
 223 void
 224 ibcm_path_cache_fini(void)
 225 {
 226         timeout_id_t tmp_timeout_id;
 227         int cache_size;
 228         ibcm_path_cache_t *path_cachep;
 229 
 230         mutex_enter(&ibcm_path_cache_mutex);
 231         if (ibcm_path_cache_timeout_id) {
 232                 tmp_timeout_id = ibcm_path_cache_timeout_id;
 233                 ibcm_path_cache_timeout_id = 0; /* no more timeouts */
 234         }
 235         cache_size = ibcm_path_cache_size;
 236         path_cachep = ibcm_path_cachep;
 237         mutex_exit(&ibcm_path_cache_mutex);
 238         if (tmp_timeout_id)
 239                 (void) untimeout(tmp_timeout_id);
 240         mutex_destroy(&ibcm_path_cache_mutex);
 241         kmem_free(path_cachep, cache_size * sizeof (*path_cachep));
 242 }
 243 
 244 static ibcm_status_t
 245 ibcm_path_cache_check(ibt_path_flags_t flags, ibt_path_attr_t *attrp,
 246     uint8_t max_paths, ibt_path_info_t *path, uint8_t *num_paths_p)
 247 {
 248         int i;
 249         ib_gid_t dgid;
 250         ibcm_path_cache_t *path_cachep;
 251 
 252         if (max_paths != 1 || attrp->pa_num_dgids != 1 ||
 253             attrp->pa_sname != NULL || attrp->pa_sid != 0) {
 254                 mutex_enter(&ibcm_path_cache_mutex);
 255                 ibcm_path_cache_stats.bad_path_for_cache++;
 256                 mutex_exit(&ibcm_path_cache_mutex);
 257                 return (IBCM_FAILURE);
 258         }
 259 
 260         dgid = attrp->pa_dgids[0];
 261         if ((dgid.gid_guid | dgid.gid_prefix) == 0ULL)
 262                 return (IBCM_FAILURE);
 263 
 264         mutex_enter(&ibcm_path_cache_mutex);
 265         if (ibcm_path_cache_invalidate) {       /* invalidate all entries */
 266                 ibcm_path_cache_stats.timeouts++;
 267                 ibcm_path_cache_invalidate = 0;
 268                 path_cachep = ibcm_path_cachep;
 269                 for (i = 0; i < ibcm_path_cache_size; i++, path_cachep++) {
 270                         path_cachep->dgid.gid_guid = 0ULL;
 271                         path_cachep->dgid.gid_prefix = 0ULL;
 272                 }
 273                 mutex_exit(&ibcm_path_cache_mutex);
 274                 return (IBCM_FAILURE);
 275         }
 276 
 277         path_cachep = ibcm_path_cachep;
 278         for (i = 0; i < ibcm_path_cache_size; i++, path_cachep++) {
 279                 if (path_cachep->dgid.gid_guid == 0ULL)
 280                         break;  /* end of search, no more valid cache entries */
 281 
 282                 /* make pa_dgids pointers match, so we can use memcmp */
 283                 path_cachep->attr.pa_dgids = attrp->pa_dgids;
 284                 if (path_cachep->flags != flags ||
 285                     path_cachep->dgid.gid_guid != dgid.gid_guid ||
 286                     path_cachep->dgid.gid_prefix != dgid.gid_prefix ||
 287                     memcmp(&(path_cachep->attr), attrp, sizeof (*attrp)) != 0) {
 288                         /* make pa_dgids NULL again */
 289                         path_cachep->attr.pa_dgids = NULL;
 290                         continue;
 291                 }
 292                 /* else we have a match */
 293                 /* make pa_dgids NULL again */
 294                 path_cachep->attr.pa_dgids = NULL;
 295                 *path = path_cachep->path;   /* retval */
 296                 if (num_paths_p)
 297                         *num_paths_p = 1;       /* retval */
 298                 ibcm_path_cache_stats.hits++;
 299                 mutex_exit(&ibcm_path_cache_mutex);
 300                 return (IBCM_SUCCESS);
 301         }
 302         ibcm_path_cache_stats.misses++;
 303         mutex_exit(&ibcm_path_cache_mutex);
 304         return (IBCM_FAILURE);
 305 }
 306 
 307 static void
 308 ibcm_path_cache_add(ibt_path_flags_t flags,
 309     ibt_path_attr_t *attrp, uint8_t max_paths, ibt_path_info_t *path)
 310 {
 311         int i;
 312         ib_gid_t dgid;
 313         ibcm_path_cache_t *path_cachep;
 314 
 315         if (max_paths != 1 || attrp->pa_num_dgids != 1 ||
 316             attrp->pa_sname != NULL || attrp->pa_sid != 0)
 317                 return;
 318 
 319         dgid = attrp->pa_dgids[0];
 320         if ((dgid.gid_guid | dgid.gid_prefix) == 0ULL)
 321                 return;
 322 
 323         mutex_enter(&ibcm_path_cache_mutex);
 324         path_cachep = ibcm_path_cachep;
 325         for (i = 0; i < ibcm_path_cache_size; i++, path_cachep++) {
 326                 path_cachep->attr.pa_dgids = attrp->pa_dgids;
 327                 if (path_cachep->flags == flags &&
 328                     path_cachep->dgid.gid_guid == dgid.gid_guid &&
 329                     path_cachep->dgid.gid_prefix == dgid.gid_prefix &&
 330                     memcmp(&(path_cachep->attr), attrp, sizeof (*attrp)) == 0) {
 331                         /* already in cache */
 332                         ibcm_path_cache_stats.already_in_cache++;
 333                         path_cachep->attr.pa_dgids = NULL;
 334                         mutex_exit(&ibcm_path_cache_mutex);
 335                         return;
 336                 }
 337                 if (path_cachep->dgid.gid_guid != 0ULL) {
 338                         path_cachep->attr.pa_dgids = NULL;
 339                         continue;
 340                 }
 341                 /* else the rest of the entries are free, so use this one */
 342                 ibcm_path_cache_stats.adds++;
 343                 path_cachep->flags = flags;
 344                 path_cachep->attr = *attrp;
 345                 path_cachep->attr.pa_dgids = NULL;
 346                 path_cachep->dgid = attrp->pa_dgids[0];
 347                 path_cachep->path = *path;
 348                 mutex_exit(&ibcm_path_cache_mutex);
 349                 return;
 350         }
 351         mutex_exit(&ibcm_path_cache_mutex);
 352 }
 353 
 354 void
 355 ibcm_path_cache_purge(void)
 356 {
 357         mutex_enter(&ibcm_path_cache_mutex);
 358         ibcm_path_cache_invalidate = 1; /* invalidate cache on next check */
 359         ibcm_path_cache_stats.purges++;
 360         mutex_exit(&ibcm_path_cache_mutex);
 361 }
 362 
 363 /*
 364  * Function:
 365  *      ibt_get_paths
 366  * Input:
 367  *      ibt_hdl         The handle returned to the client by the IBTF from an
 368  *                      ibt_attach() call. Can be used by the IBTF Policy module
 369  *                      and CM in the determination of the "best" path to the
 370  *                      specified destination for this class of driver.
 371  *      flags           Path flags.
 372  *      attrp           Points to an ibt_path_attr_t struct that contains
 373  *                      required and optional attributes.
 374  *      max_paths       The size of the "paths" array argument. Also, this
 375  *                      is the limit on the number of paths returned.
 376  *                      max_paths indicates the number of requested paths to
 377  *                      the specified destination(s).
 378  * Output:
 379  *      paths           An array of ibt_path_info_t structs filled in by
 380  *                      ibt_get_paths() as output parameters. Upon return,
 381  *                      array elements with non-NULL HCA GUIDs are valid.
 382  *      num_paths_p     If non-NULL, return the actual number of paths found.
 383  * Returns:
 384  *      IBT_SUCCESS on Success else appropriate error.
 385  * Description:
 386  *      Finds the best path to a specified destination (as determined by the
 387  *      IBTL) that satisfies the requirements specified in an ibt_path_attr_t
 388  *      struct.
 389  *
 390  *      This routine can not be called from interrupt context.
 391  */
 392 ibt_status_t
 393 ibt_get_paths(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags,
 394     ibt_path_attr_t *attrp, uint8_t max_paths, ibt_path_info_t *paths,
 395     uint8_t *num_paths_p)
 396 {
 397         ibt_status_t    retval;
 398 
 399         ASSERT(paths != NULL);
 400 
 401         IBTF_DPRINTF_L3(cmlog, "ibt_get_paths(%p(%s), 0x%X, %p, %d)",
 402             ibt_hdl, ibtl_cm_get_clnt_name(ibt_hdl), flags, attrp, max_paths);
 403 
 404         if (paths == NULL) {
 405                 IBTF_DPRINTF_L2(cmlog, "ibt_get_paths: Path Info Pointer is "
 406                     "NULL - ERROR ");
 407                 return (IBT_INVALID_PARAM);
 408         }
 409 
 410         if (num_paths_p != NULL)
 411                 *num_paths_p = 0;
 412 
 413         if (ibcm_path_cache_check(flags, attrp, max_paths, paths,
 414             num_paths_p) == IBCM_SUCCESS)
 415                 return (IBT_SUCCESS);
 416 
 417         retval = ibcm_handle_get_path(attrp, flags, max_paths, paths,
 418             num_paths_p, NULL, NULL);
 419 
 420         if (retval == IBT_SUCCESS)
 421                 ibcm_path_cache_add(flags, attrp, max_paths, paths);
 422         return (retval);
 423 }
 424 
 425 
 426 static ibt_status_t
 427 ibcm_handle_get_path(ibt_path_attr_t *attrp, ibt_path_flags_t flags,
 428     uint8_t max_paths, ibt_path_info_t *paths, uint8_t *num_path_p,
 429     ibt_path_handler_t func, void  *arg)
 430 {
 431         ibcm_path_tqargs_t      *path_tq;
 432         int             sleep_flag = ((func == NULL) ? KM_SLEEP : KM_NOSLEEP);
 433         int             len;
 434         ibt_status_t    retval;
 435 
 436         retval = ibcm_validate_path_attributes(attrp, flags, max_paths);
 437         if (retval != IBT_SUCCESS)
 438                 return (retval);
 439 
 440         len = (attrp->pa_num_dgids * sizeof (ib_gid_t)) +
 441             sizeof (ibcm_path_tqargs_t);
 442 
 443         path_tq = kmem_alloc(len, sleep_flag);
 444         if (path_tq == NULL) {
 445                 IBTF_DPRINTF_L2(cmlog, "ibcm_handle_get_path: "
 446                     "Unable to allocate memory for local usage.");
 447                 return (IBT_INSUFF_KERNEL_RESOURCE);
 448         }
 449 
 450         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*path_tq))
 451 
 452         bcopy(attrp, &path_tq->attr, sizeof (ibt_path_attr_t));
 453 
 454         if (attrp->pa_num_dgids) {
 455                 path_tq->attr.pa_dgids = (ib_gid_t *)(((uchar_t *)path_tq) +
 456                     sizeof (ibcm_path_tqargs_t));
 457 
 458                 bcopy(attrp->pa_dgids, path_tq->attr.pa_dgids,
 459                     sizeof (ib_gid_t) * attrp->pa_num_dgids);
 460         } else {
 461                 path_tq->attr.pa_dgids = NULL;
 462         }
 463 
 464         /* Ignore IBT_PATH_AVAIL flag, if only one path is requested. */
 465         if ((flags & IBT_PATH_AVAIL) && (max_paths == 1)) {
 466                 flags &= ~IBT_PATH_AVAIL;
 467 
 468                 IBTF_DPRINTF_L4(cmlog, "ibcm_handle_get_path: "
 469                     "Ignoring IBT_PATH_AVAIL flag, as only ONE path "
 470                     "information is requested.");
 471         }
 472 
 473         path_tq->flags = flags;
 474         path_tq->max_paths = max_paths;
 475         path_tq->paths = paths;
 476         path_tq->num_paths_p = num_path_p;
 477         path_tq->func = func;
 478         path_tq->arg = arg;
 479 
 480         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*path_tq))
 481 
 482         if (func != NULL) {             /* Non-Blocking */
 483                 IBTF_DPRINTF_L3(cmlog, "ibcm_handle_get_path: Non Blocking");
 484                 if (taskq_dispatch(ibcm_taskq, ibcm_process_async_get_paths,
 485                     path_tq, TQ_NOSLEEP) == 0) {
 486                         IBTF_DPRINTF_L2(cmlog, "ibcm_handle_get_path: "
 487                             "Failed to dispatch the TaskQ");
 488                         kmem_free(path_tq, len);
 489                         return (IBT_INSUFF_KERNEL_RESOURCE);
 490                 } else
 491                         return (IBT_SUCCESS);
 492         } else {                /* Blocking */
 493                 IBTF_DPRINTF_L3(cmlog, "ibcm_handle_get_path: Blocking");
 494                 return (ibcm_process_get_paths(path_tq));
 495         }
 496 }
 497 
 498 
 499 static void
 500 ibcm_process_async_get_paths(void *tq_arg)
 501 {
 502         (void) ibcm_process_get_paths(tq_arg);
 503 }
 504 
 505 
 506 static ibt_status_t
 507 ibcm_validate_path_attributes(ibt_path_attr_t *attrp, ibt_path_flags_t flags,
 508     uint8_t max_paths)
 509 {
 510         uint_t                  i;
 511 
 512         IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: Inputs are: "
 513             "HCA (%llX, %d),\n\tSGID(%llX:%llX), SName=\"%s\",\n\tSID= %llX, "
 514             "Maxpath= %d, Flags= 0x%X, #Dgid= %d, SDFlag= 0x%llX",
 515             attrp->pa_hca_guid, attrp->pa_hca_port_num,
 516             attrp->pa_sgid.gid_prefix, attrp->pa_sgid.gid_guid,
 517             ((attrp->pa_sname != NULL) ? attrp->pa_sname : ""), attrp->pa_sid,
 518             max_paths, flags, attrp->pa_num_dgids, attrp->pa_sd_flags);
 519 
 520         /*
 521          * Validate Path Flags.
 522          * IBT_PATH_AVAIL & IBT_PATH_PERF are mutually exclusive.
 523          */
 524         if ((flags & IBT_PATH_AVAIL) && (flags & IBT_PATH_PERF)) {
 525                 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
 526                     "Invalid Flags: 0x%X,\n\t AVAIL and PERF flags cannot "
 527                     "specified together.", flags);
 528                 return (IBT_INVALID_PARAM);
 529         }
 530 
 531         /* Validate number of records requested. */
 532         if ((flags & (IBT_PATH_AVAIL | IBT_PATH_PERF)) &&
 533             (max_paths > IBT_MAX_SPECIAL_PATHS)) {
 534                 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
 535                     "Max records that can be requested is <%d> \n"
 536                     "when IBT_PATH_AVAIL or IBT_PATH_PERF flag is specified.",
 537                     IBT_MAX_SPECIAL_PATHS);
 538                 return (IBT_INVALID_PARAM);
 539         }
 540 
 541         /* Only 2 destinations can be specified w/ APM flag. */
 542         if ((flags & IBT_PATH_APM) && (attrp->pa_num_dgids > 2)) {
 543                 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes:\n\t Max "
 544                     "number of DGIDs that can be specified w/APM flag is 2");
 545                 return (IBT_INVALID_PARAM);
 546         }
 547 
 548         /*
 549          * Max_paths of "0" is invalid.
 550          * w/ IBT_PATH_MULTI_SVC_DEST flag, max_paths must be greater than "1".
 551          */
 552         if ((max_paths == 0) ||
 553             ((flags & IBT_PATH_MULTI_SVC_DEST) && (max_paths < 2))) {
 554                 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
 555                     "Invalid number of records requested:\n flags 0x%X, "
 556                     "max_paths %d", flags, max_paths);
 557                 return (IBT_INVALID_PARAM);
 558         }
 559 
 560         /*
 561          * If IBT_PATH_MULTI_SVC_DEST is set, then ServiceName and/or Service ID
 562          * must be specified and DGIDs SHOULD NOT be specified.
 563          */
 564         if ((flags & IBT_PATH_MULTI_SVC_DEST) && ((attrp->pa_num_dgids > 0) ||
 565             ((attrp->pa_sid == 0) && ((attrp->pa_sname == NULL) ||
 566             ((attrp->pa_sname != NULL) && (strlen(attrp->pa_sname) == 0)))))) {
 567                 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
 568                     "Invalid Flags: 0x%X, IBT_PATH_MULTI_SVC_DEST flag set "
 569                     "but Service Name \n or Service ID NOT specified or DGIDs "
 570                     "are specified.", flags);
 571                 return (IBT_INVALID_PARAM);
 572         }
 573 
 574         /*
 575          * User need to specify the destination information, which can be
 576          * provided as one or more of the following.
 577          *      o ServiceName
 578          *      o ServiceID
 579          *      o Array of DGIDs w/Num of DGIDs, (max of 2)
 580          */
 581         if ((attrp->pa_sid == 0) && (attrp->pa_num_dgids == 0) &&
 582             ((attrp->pa_sname == NULL) || ((attrp->pa_sname != NULL) &&
 583             (strlen(attrp->pa_sname) == 0)))) {
 584                 /* Destination information not provided, bail out. */
 585                 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
 586                     "Client's MUST supply DestInfo.");
 587                 return (IBT_INVALID_PARAM);
 588         }
 589 
 590         /* If DGIDs are provided, validate them. */
 591         if (attrp->pa_num_dgids > 0) {
 592                 if (attrp->pa_dgids == NULL) {
 593                         IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
 594                             "pa_dgids NULL, but pa_num_dgids : %d",
 595                             attrp->pa_num_dgids);
 596                         return (IBT_INVALID_PARAM);
 597                 }
 598 
 599                 /* Validate DGIDs */
 600                 for (i = 0; i < attrp->pa_num_dgids; i++) {
 601                         ib_gid_t        gid = attrp->pa_dgids[i];
 602 
 603                         IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
 604                             "DGID[%d] = %llX:%llX", i, gid.gid_prefix,
 605                             gid.gid_guid);
 606 
 607                         /* APM request for MultiCast destination is invalid. */
 608                         if ((gid.gid_prefix >> 56ULL & 0xFF) == 0xFF) {
 609                                 if (flags & IBT_PATH_APM) {
 610                                         IBTF_DPRINTF_L2(cmlog,
 611                                             "ibcm_validate_path_attributes: "
 612                                             "APM for MGIDs not supported.");
 613                                         return (IBT_INVALID_PARAM);
 614                                 }
 615                         } else if ((gid.gid_prefix == 0) ||
 616                             (gid.gid_guid == 0)) {
 617                                 IBTF_DPRINTF_L2(cmlog,
 618                                     "ibcm_validate_path_attributes: ERROR: "
 619                                     "Invalid DGIDs specified");
 620                                 return (IBT_INVALID_PARAM);
 621                         }
 622                 }
 623         }
 624 
 625         /* Check for valid Service Name length. */
 626         if ((attrp->pa_sname != NULL) &&
 627             (strlen(attrp->pa_sname) >= IB_SVC_NAME_LEN)) {
 628                 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
 629                     "ServiceName too long");
 630                 return (IBT_INVALID_PARAM);
 631         }
 632 
 633         /* If P_Key is specified, check for invalid p_key's */
 634         if (flags & IBT_PATH_PKEY) {
 635                 /* Limited P_Key is NOT supported as of now!. */
 636                 if ((attrp->pa_pkey == IB_PKEY_INVALID_FULL) ||
 637                     (attrp->pa_pkey & 0x8000) == 0) {
 638                         IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
 639                             "Specified P_Key is invalid: 0x%X", attrp->pa_pkey);
 640                         return (IBT_INVALID_PARAM);
 641                 }
 642                 IBTF_DPRINTF_L3(cmlog, "ibcm_validate_path_attributes: "
 643                     "P_Key= 0x%X", attrp->pa_pkey);
 644         }
 645 
 646         return (IBT_SUCCESS);
 647 }
 648 
 649 
 650 static ibt_status_t
 651 ibcm_process_get_paths(void *tq_arg)
 652 {
 653         ibcm_path_tqargs_t      *p_arg = (ibcm_path_tqargs_t *)tq_arg;
 654         ibcm_dinfo_t            *dinfo;
 655         int                     len;
 656         uint8_t                 max_paths, num_path;
 657         ibt_status_t            retval;
 658         ib_gid_t                *d_gids_p = NULL;
 659         ibtl_cm_port_list_t     *slistp = NULL;
 660         uint_t                  dnum = 0;
 661         uint8_t                 num_dest, i, j;
 662         ibcm_hca_info_t         *hcap;
 663         ibmf_saa_handle_t       saa_handle;
 664 
 665         IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths(%p, 0x%X, %d) ",
 666             p_arg, p_arg->flags, p_arg->max_paths);
 667 
 668         max_paths = num_path = p_arg->max_paths;
 669 
 670         /*
 671          * Prepare the Destination list based on the input DGIDs and
 672          * other attributes.
 673          *
 674          * APM is requested and pa_dgids are specified.  If multiple DGIDs are
 675          * specified, check out whether they are companion to each other or if
 676          * only one DGID is specified, then get the companion port GID for that.
 677          */
 678         if (p_arg->attr.pa_num_dgids) {
 679                 if (p_arg->flags & IBT_PATH_APM) {
 680                         ib_gid_t        c_gid, n_gid;
 681 
 682                         IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: "
 683                             "DGIDs specified w/ APM Flag");
 684 
 685                         c_gid = p_arg->attr.pa_dgids[0];
 686                         if (p_arg->attr.pa_num_dgids > 1)
 687                                 n_gid = p_arg->attr.pa_dgids[1];
 688                         else
 689                                 n_gid.gid_prefix = n_gid.gid_guid = 0;
 690 
 691                         retval = ibcm_get_comp_pgids(c_gid, n_gid, 0, &d_gids_p,
 692                             &dnum);
 693                         if ((retval != IBT_SUCCESS) &&
 694                             (retval != IBT_GIDS_NOT_FOUND)) {
 695                                 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths:"
 696                                     " Invalid DGIDs specified w/ APM Flag");
 697                                 goto path_error2;
 698                         }
 699                         IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: "
 700                             "Found %d Comp DGID", dnum);
 701                 }
 702 
 703                 if (dnum) {
 704                         len = 1;
 705                 } else {
 706                         len = p_arg->attr.pa_num_dgids - 1;
 707                 }
 708                 num_dest = len + 1;
 709 
 710                 IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: #dgid %d, dnum "
 711                     "%d, #dest %d", p_arg->attr.pa_num_dgids, dnum, num_dest);
 712         } else {
 713                 if (p_arg->flags & IBT_PATH_MULTI_SVC_DEST) {
 714                         IBTF_DPRINTF_L4(cmlog, "ibcm_process_get_paths: "
 715                             "IBT_PATH_MULTI_SVC_DEST flags set");
 716                         len = max_paths - 1;
 717                 } else if (p_arg->flags & IBT_PATH_APM) {
 718                         len = 1;
 719                 } else {
 720                         len = 0;
 721                 }
 722                 num_dest = 0;
 723         }
 724 
 725         /* Allocate memory and accumulate all destination information */
 726         len = (len * sizeof (ibcm_dest_t)) + sizeof (ibcm_dinfo_t);
 727 
 728         dinfo = kmem_zalloc(len, KM_SLEEP);
 729         dinfo->num_dest = num_dest;
 730         if (p_arg->flags & IBT_PATH_PKEY)
 731                 dinfo->p_key = p_arg->attr.pa_pkey;
 732 
 733         for (i = 0, j = 0; i < num_dest; i++) {
 734                 if (i < p_arg->attr.pa_num_dgids)
 735                         dinfo->dest[i].d_gid = p_arg->attr.pa_dgids[i];
 736                 else
 737                         dinfo->dest[i].d_gid = d_gids_p[j++];
 738         }
 739 
 740         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*p_arg))
 741 
 742         /* IBTF allocates memory for path_info in case of Async Get Paths */
 743         if (p_arg->paths == NULL)
 744                 p_arg->paths = kmem_zalloc(sizeof (ibt_path_info_t) * max_paths,
 745                     KM_SLEEP);
 746 
 747         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*p_arg))
 748 
 749         /*
 750          * Get list of active HCA<->Port list, that matches input specified attr
 751          */
 752         IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: Get Paths from \n HCA "
 753             "(%llX:%d), SGID  %llX:%llX", p_arg->attr.pa_hca_guid,
 754             p_arg->attr.pa_hca_port_num, p_arg->attr.pa_sgid.gid_prefix,
 755             p_arg->attr.pa_sgid.gid_guid);
 756 
 757         retval = ibtl_cm_get_active_plist(&p_arg->attr, p_arg->flags, &slistp);
 758         if (retval != IBT_SUCCESS) {
 759                 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: HCA capable of "
 760                     "requested source attributes NOT available.");
 761                 goto path_error;
 762         }
 763 
 764         IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: HCA (%llX, %d)",
 765             slistp->p_hca_guid, slistp->p_port_num);
 766 
 767         hcap = ibcm_find_hca_entry(slistp->p_hca_guid);
 768         if (hcap == NULL) {
 769                 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: "
 770                     "NO HCA found");
 771                 retval = IBT_HCA_BUSY_DETACHING;
 772                 goto path_error;
 773         }
 774 
 775         /* Get SA Access Handle. */
 776         for (i = 0; i < slistp->p_count; i++) {
 777                 if (i == 0) {
 778                         /* Validate whether this HCA supports APM */
 779                         if ((p_arg->flags & IBT_PATH_APM) &&
 780                             (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG))) {
 781                                 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths:"
 782                                     " HCA (%llX): APM NOT SUPPORTED ",
 783                                     slistp[i].p_hca_guid);
 784                                 retval = IBT_APM_NOT_SUPPORTED;
 785                                 goto path_error1;
 786                         }
 787                 }
 788 
 789                 saa_handle = ibcm_get_saa_handle(hcap, slistp[i].p_port_num);
 790                 if (saa_handle == NULL) {
 791                         IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: "
 792                             "SAA HDL NULL, HCA (%llX:%d) NOT ACTIVE",
 793                             slistp[i].p_hca_guid, slistp[i].p_port_num);
 794                         retval = IBT_HCA_PORT_NOT_ACTIVE;
 795                         goto path_error1;
 796                 }
 797                 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*slistp))
 798                 slistp[i].p_saa_hdl = saa_handle;
 799                 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*slistp))
 800         }
 801 
 802         /*
 803          * If Service Name or Service ID are specified, first retrieve
 804          * Service Records.
 805          */
 806         if ((p_arg->attr.pa_sid != 0) || ((p_arg->attr.pa_sname != NULL) &&
 807             (strlen(p_arg->attr.pa_sname) != 0))) {
 808 
 809                 IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: Get Service "
 810                     "Record for \n\t(%llX, \"%s\")", p_arg->attr.pa_sid,
 811                     ((p_arg->attr.pa_sname != NULL) ?
 812                     p_arg->attr.pa_sname : ""));
 813 
 814                 /* Get Service Records. */
 815                 retval = ibcm_saa_service_rec(p_arg, slistp, dinfo);
 816                 if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA)) {
 817                         IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: Status="
 818                             "%d, Failed to get Service Record for \n\t"
 819                             "(%llX, \"%s\")", retval, p_arg->attr.pa_sid,
 820                             ((p_arg->attr.pa_sname != NULL) ?
 821                             p_arg->attr.pa_sname : ""));
 822                         goto path_error1;
 823                 }
 824         }
 825 
 826         /* Get Path Records. */
 827         retval = ibcm_saa_path_rec(p_arg, slistp, dinfo, &num_path);
 828 
 829 path_error1:
 830         ibcm_dec_hca_acc_cnt(hcap);
 831 
 832 path_error:
 833         if (slistp)
 834                 ibtl_cm_free_active_plist(slistp);
 835 
 836         if (dinfo)
 837                 kmem_free(dinfo, len);
 838 
 839 path_error2:
 840         if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA))
 841                 num_path = 0;
 842 
 843         if (p_arg->num_paths_p != NULL)
 844                 *p_arg->num_paths_p = num_path;
 845 
 846         if ((dnum) && (d_gids_p))
 847                 kmem_free(d_gids_p, dnum * sizeof (ib_gid_t));
 848 
 849         if (p_arg->func) {   /* Do these only for Async Get Paths */
 850                 ibt_path_info_t *tmp_path_p;
 851 
 852                 if (retval == IBT_INSUFF_DATA) {
 853                         /*
 854                          * We allocated earlier memory based on "max_paths",
 855                          * but we got lesser path-records, so re-adjust that
 856                          * buffer so that caller can free the correct memory.
 857                          */
 858                         tmp_path_p = kmem_alloc(
 859                             sizeof (ibt_path_info_t) * num_path, KM_SLEEP);
 860 
 861                         bcopy(p_arg->paths, tmp_path_p,
 862                             num_path * sizeof (ibt_path_info_t));
 863 
 864                         kmem_free(p_arg->paths,
 865                             sizeof (ibt_path_info_t) * max_paths);
 866                 } else if (retval != IBT_SUCCESS) {
 867                         if (p_arg->paths)
 868                                 kmem_free(p_arg->paths,
 869                                     sizeof (ibt_path_info_t) * max_paths);
 870                         tmp_path_p = NULL;
 871                 } else {
 872                         tmp_path_p = p_arg->paths;
 873                 }
 874                 (*(p_arg->func))(p_arg->arg, retval, tmp_path_p, num_path);
 875         }
 876 
 877         len = (sizeof (ib_gid_t) * p_arg->attr.pa_num_dgids) +
 878             sizeof (ibcm_path_tqargs_t);
 879 
 880         if (p_arg && len)
 881                 kmem_free(p_arg, len);
 882 
 883         IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: done: status %d, "
 884             "Found %d/%d Path Records", retval, num_path, max_paths);
 885 
 886         return (retval);
 887 }
 888 
 889 
 890 /*
 891  * Perform SA Access to retrieve Path Records.
 892  */
 893 static ibt_status_t
 894 ibcm_saa_path_rec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
 895     ibcm_dinfo_t *dinfo, uint8_t *max_count)
 896 {
 897         uint8_t         num_path = *max_count;
 898         uint8_t         num_path_plus;
 899         uint8_t         extra, idx, rec_found = 0;
 900         ibt_status_t    retval = IBT_SUCCESS;
 901         int             unicast_dgid_present = 0;
 902         uint8_t         i;
 903 
 904         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec(%p, %p, %p, 0x%X, %d)",
 905             p_arg, sl, dinfo, p_arg->flags, *max_count);
 906 
 907         if ((dinfo->num_dest == 0) || (num_path == 0) || (sl == NULL)) {
 908                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: Invalid Counters");
 909                 return (IBT_INVALID_PARAM);
 910         }
 911 
 912         /*
 913          * Of the total needed "X" number of paths to "Y" number of destination
 914          * we need to get X/Y plus X%Y extra paths to each destination,
 915          * We do this so that we can choose the required number of path records
 916          * for the specific destination.
 917          */
 918         num_path /= dinfo->num_dest;
 919         extra = (*max_count % dinfo->num_dest);
 920 
 921         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: numpath %d extra %d dest %d",
 922             num_path, extra, dinfo->num_dest);
 923 
 924         /* Find out whether we need to get PathRecord for a MGID as DGID. */
 925         for (idx = 0; idx < dinfo->num_dest; idx++) {
 926                 ib_gid_t        dgid = dinfo->dest[idx].d_gid;
 927 
 928                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: DGID[%d]: %llX:%llX",
 929                     idx, dgid.gid_prefix, dgid.gid_guid);
 930 
 931                 if ((dgid.gid_prefix >> 56ULL & 0xFF) == 0xFF) {
 932                         if (extra)
 933                                 num_path_plus = num_path + 1;
 934                         else
 935                                 num_path_plus = num_path;
 936 
 937                         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: Get %d Paths"
 938                             "- MGID(%016llX%016llX)", num_path_plus,
 939                             dgid.gid_prefix, dgid.gid_guid);
 940 
 941                         dinfo->dest[idx].d_tag = 1; /* MultiCast */
 942 
 943                         /* Yes, it's Single PathRec query for MGID as DGID. */
 944                         retval = ibcm_get_single_pathrec(p_arg, sl, dinfo, idx,
 945                             &num_path_plus, &p_arg->paths[rec_found]);
 946                         if ((retval != IBT_SUCCESS) &&
 947                             (retval != IBT_INSUFF_DATA)) {
 948                                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: "
 949                                     "Failed to get PathRec for MGID %d",
 950                                     retval);
 951                                 continue;
 952                         }
 953                         if (extra)
 954                                 extra--;
 955 
 956                         rec_found += num_path_plus;
 957                 }
 958                 if (rec_found == *max_count)
 959                         break;
 960         }
 961 
 962         for (i = 0; i < dinfo->num_dest; i++) {
 963                 if (dinfo->dest[i].d_tag == 0) {
 964                         unicast_dgid_present++;
 965                 }
 966         }
 967 
 968         num_path_plus = *max_count - rec_found;
 969 
 970         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: Recfound: %d, need to find "
 971             "%d, UniCastGID present %d", rec_found, num_path_plus,
 972             unicast_dgid_present);
 973 
 974         if ((unicast_dgid_present != 0) && (num_path_plus > 0)) {
 975                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: MultiSM=%X, #SRC=%d,"
 976                     "Dest%d", sl->p_multi, sl->p_count, unicast_dgid_present);
 977 
 978                 if ((sl->p_multi != IBTL_CM_SIMPLE_SETUP) ||
 979                     ((unicast_dgid_present == 1) && (sl->p_count == 1))) {
 980                         /*
 981                          * Use SinglePathRec if we are dealing w/ MultiSM or
 982                          * request is for one SGID to one DGID.
 983                          */
 984                         retval = ibcm_get_single_pathrec(p_arg, sl, dinfo, 0xFF,
 985                             &num_path_plus, &p_arg->paths[rec_found]);
 986                 } else {
 987                         uint8_t old_num_path_plus = num_path_plus;
 988 
 989                         /* MultiPathRec will be used for other queries. */
 990                         retval = ibcm_get_multi_pathrec(p_arg, sl, dinfo,
 991                             &num_path_plus, &p_arg->paths[rec_found]);
 992                         if ((retval != IBT_SUCCESS) &&
 993                             (retval != IBT_INSUFF_DATA) &&
 994                             (sl->p_count > 0) &&
 995                             (dinfo->num_dest > 0)) {
 996                                 ibtl_cm_port_list_t sl_tmp = *sl;
 997                                 ibcm_dinfo_t dinfo_tmp = *dinfo;
 998 
 999                                 sl_tmp.p_count = 1;
1000                                 dinfo_tmp.num_dest = 1;
1001                                 num_path_plus = old_num_path_plus;
1002                                 retval = ibcm_get_single_pathrec(p_arg, &sl_tmp,
1003                                     &dinfo_tmp, 0xFF, &num_path_plus,
1004                                     &p_arg->paths[rec_found]);
1005                         }
1006                 }
1007                 if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA)) {
1008                         IBTF_DPRINTF_L2(cmlog, "ibcm_saa_path_rec: "
1009                             "Failed to get PathRec: Status %d", retval);
1010                 } else {
1011                         rec_found += num_path_plus;
1012                 }
1013         }
1014 
1015         if (rec_found == 0)  {
1016                 if (retval == IBT_SUCCESS)
1017                         retval = IBT_PATH_RECORDS_NOT_FOUND;
1018         } else if (rec_found != *max_count)
1019                 retval = IBT_INSUFF_DATA;
1020         else if (rec_found != 0)
1021                 retval = IBT_SUCCESS;
1022 
1023         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: done. Status = %d, "
1024             "Found %d/%d Paths", retval, rec_found, *max_count);
1025 
1026         *max_count = rec_found; /* Update the return count. */
1027 
1028         return (retval);
1029 }
1030 
1031 ibt_status_t
1032 ibcm_contact_sa_access(ibmf_saa_handle_t saa_handle,
1033     ibmf_saa_access_args_t *access_args, size_t *length, void **results_p)
1034 {
1035         int     retry;
1036         int     sa_retval;
1037 
1038         IBTF_DPRINTF_L3(cmlog, "ibcm_contact_sa_access(%p, %p)",
1039             saa_handle, access_args);
1040 
1041         ibcm_sa_access_enter();
1042 
1043         for (retry = 0; retry < ibcm_max_sa_retries; retry++) {
1044                 sa_retval = ibmf_sa_access(saa_handle, access_args, 0,
1045                     length, results_p);
1046                 if (sa_retval != IBMF_TRANS_TIMEOUT)
1047                         break;
1048 
1049                 IBTF_DPRINTF_L2(cmlog, "ibcm_contact_sa_access: "
1050                     "ibmf_sa_access() - Timed Out (%d)", sa_retval);
1051                 delay(ibcm_sa_timeout_delay);
1052         }
1053 
1054         ibcm_sa_access_exit();
1055 
1056         if ((sa_retval == IBMF_SUCCESS) || (sa_retval == IBMF_NO_RECORDS) ||
1057             (sa_retval == IBMF_REQ_INVALID)) {
1058                 IBTF_DPRINTF_L3(cmlog, "ibcm_contact_sa_access: "
1059                     "ibmf_sa_access() returned (%d)", sa_retval);
1060                 return (IBT_SUCCESS);
1061         } else  {
1062                 IBTF_DPRINTF_L2(cmlog, "ibcm_contact_sa_access: "
1063                     "ibmf_sa_access(): Failed (%d)", sa_retval);
1064                 return (ibcm_ibmf_analyze_error(sa_retval));
1065         }
1066 }
1067 
1068 
1069 static ibt_status_t
1070 ibcm_update_pri(sa_path_record_t *pr_resp, ibtl_cm_port_list_t *sl,
1071     ibcm_dinfo_t *dinfo, ibt_path_info_t *paths)
1072 {
1073         ibt_status_t    retval = IBT_SUCCESS;
1074         int             d, s;
1075 
1076         retval = ibcm_update_cep_info(pr_resp, sl, NULL,
1077             &paths->pi_prim_cep_path);
1078         if (retval != IBT_SUCCESS)
1079                 return (retval);
1080 
1081         /* Update some leftovers */
1082         paths->pi_prim_pkt_lt = pr_resp->PacketLifeTime;
1083         paths->pi_path_mtu = pr_resp->Mtu;
1084 
1085         for (d = 0; d < dinfo->num_dest; d++) {
1086                 if (pr_resp->DGID.gid_guid == dinfo->dest[d].d_gid.gid_guid) {
1087                         paths->pi_sid = dinfo->dest[d].d_sid;
1088                         if (paths->pi_sid != 0) {
1089                                 bcopy(&dinfo->dest[d].d_sdata,
1090                                     &paths->pi_sdata, sizeof (ibt_srv_data_t));
1091                         }
1092                         break;
1093                 }
1094         }
1095 
1096         for (s = 0; s < sl->p_count; s++) {
1097                 if (pr_resp->SGID.gid_guid == sl[s].p_sgid.gid_guid) {
1098                         paths->pi_hca_guid = sl[s].p_hca_guid;
1099                 }
1100         }
1101 
1102         /* Set Alternate Path to invalid state. */
1103         paths->pi_alt_cep_path.cep_hca_port_num = 0;
1104         paths->pi_alt_cep_path.cep_adds_vect.av_dlid = 0;
1105 
1106         IBTF_DPRINTF_L5(cmlog, "Path: HCA GUID  = 0x%llX", paths->pi_hca_guid);
1107         IBTF_DPRINTF_L5(cmlog, "Path: ServiceID = 0x%llX", paths->pi_sid);
1108 
1109         return (retval);
1110 }
1111 
1112 
1113 static ibt_status_t
1114 ibcm_get_single_pathrec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
1115     ibcm_dinfo_t *dinfo, uint8_t idx, uint8_t *num_path, ibt_path_info_t *paths)
1116 {
1117         sa_path_record_t        pathrec_req;
1118         sa_path_record_t        *pr_resp;
1119         ibmf_saa_access_args_t  access_args;
1120         uint64_t                c_mask = 0;
1121         void                    *results_p;
1122         uint8_t                 num_rec;
1123         size_t                  length;
1124         ibt_status_t            retval;
1125         int                     i, j, k;
1126         uint8_t                 found, p_fnd;
1127         ibt_path_attr_t         *attrp = &p_arg->attr;
1128         ibmf_saa_handle_t       saa_handle;
1129 
1130         IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec(%p, %p, %p, %d)",
1131             p_arg, sl, dinfo, *num_path);
1132 
1133         bzero(&pathrec_req, sizeof (sa_path_record_t));
1134 
1135         /* Is Flow Label Specified. */
1136         if (attrp->pa_flow) {
1137                 pathrec_req.FlowLabel = attrp->pa_flow;
1138                 c_mask |= SA_PR_COMPMASK_FLOWLABEL;
1139         }
1140 
1141         /* Is HopLimit Specified. */
1142         if (p_arg->flags & IBT_PATH_HOP) {
1143                 pathrec_req.HopLimit = attrp->pa_hop;
1144                 c_mask |= SA_PR_COMPMASK_HOPLIMIT;
1145         }
1146 
1147         /* Is P_Key Specified. */
1148         if (dinfo->p_key) {
1149                 IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: "
1150                     "Specified or Global PKEY 0x%X", dinfo->p_key);
1151                 pathrec_req.P_Key = dinfo->p_key;
1152                 c_mask |= SA_PR_COMPMASK_PKEY;
1153         }
1154 
1155         /* Is TClass Specified. */
1156         if (attrp->pa_tclass) {
1157                 pathrec_req.TClass = attrp->pa_tclass;
1158                 c_mask |= SA_PR_COMPMASK_TCLASS;
1159         }
1160 
1161         /* Is SL specified. */
1162         if (attrp->pa_sl) {
1163                 pathrec_req.SL = attrp->pa_sl;
1164                 c_mask |= SA_PR_COMPMASK_SL;
1165         }
1166 
1167         /* If IBT_PATH_PERF is set, then mark all selectors to BEST. */
1168         if (p_arg->flags & IBT_PATH_PERF) {
1169                 pathrec_req.PacketLifeTimeSelector = IBT_BEST;
1170                 pathrec_req.MtuSelector = IBT_BEST;
1171                 pathrec_req.RateSelector = IBT_BEST;
1172 
1173                 c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR |
1174                     SA_PR_COMPMASK_RATESELECTOR | SA_PR_COMPMASK_MTUSELECTOR;
1175         } else {
1176                 if (attrp->pa_pkt_lt.p_selector == IBT_BEST) {
1177                         pathrec_req.PacketLifeTimeSelector = IBT_BEST;
1178                         c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR;
1179                 }
1180 
1181                 if (attrp->pa_srate.r_selector == IBT_BEST) {
1182                         pathrec_req.RateSelector = IBT_BEST;
1183                         c_mask |= SA_PR_COMPMASK_RATESELECTOR;
1184                 }
1185 
1186                 if (attrp->pa_mtu.r_selector == IBT_BEST) {
1187                         pathrec_req.MtuSelector = IBT_BEST;
1188                         c_mask |= SA_PR_COMPMASK_MTUSELECTOR;
1189                 }
1190         }
1191 
1192         /*
1193          * Honor individual selection of these attributes,
1194          * even if IBT_PATH_PERF is set.
1195          */
1196         /* Check out whether Packet Life Time is specified. */
1197         if (attrp->pa_pkt_lt.p_pkt_lt) {
1198                 pathrec_req.PacketLifeTime =
1199                     ibt_usec2ib(attrp->pa_pkt_lt.p_pkt_lt);
1200                 pathrec_req.PacketLifeTimeSelector =
1201                     attrp->pa_pkt_lt.p_selector;
1202 
1203                 c_mask |= SA_PR_COMPMASK_PKTLT | SA_PR_COMPMASK_PKTLTSELECTOR;
1204         }
1205 
1206         /* Is SRATE specified. */
1207         if (attrp->pa_srate.r_srate) {
1208                 pathrec_req.Rate = attrp->pa_srate.r_srate;
1209                 pathrec_req.RateSelector = attrp->pa_srate.r_selector;
1210 
1211                 c_mask |= SA_PR_COMPMASK_RATE | SA_PR_COMPMASK_RATESELECTOR;
1212         }
1213 
1214         /* Is MTU specified. */
1215         if (attrp->pa_mtu.r_mtu) {
1216                 pathrec_req.Mtu = attrp->pa_mtu.r_mtu;
1217                 pathrec_req.MtuSelector = attrp->pa_mtu.r_selector;
1218 
1219                 c_mask |= SA_PR_COMPMASK_MTU | SA_PR_COMPMASK_MTUSELECTOR;
1220         }
1221 
1222         /* We always get REVERSIBLE paths. */
1223         pathrec_req.Reversible = 1;
1224         c_mask |= SA_PR_COMPMASK_REVERSIBLE;
1225 
1226         pathrec_req.NumbPath = *num_path;
1227         c_mask |= SA_PR_COMPMASK_NUMBPATH;
1228 
1229         if (idx != 0xFF) {
1230                 /* MGID */
1231                 pathrec_req.DGID = dinfo->dest[idx].d_gid;
1232                 c_mask |= SA_PR_COMPMASK_DGID;
1233         }
1234 
1235         p_fnd = found = 0;
1236 
1237         for (i = 0; i < sl->p_count; i++) {
1238                 /* SGID */
1239                 pathrec_req.SGID = sl[i].p_sgid;
1240                 c_mask |= SA_PR_COMPMASK_SGID;
1241                 saa_handle = sl[i].p_saa_hdl;
1242 
1243                 for (k = 0; k < dinfo->num_dest; k++) {
1244                         if (idx == 0xFF) {              /* DGID */
1245                                 if (dinfo->dest[k].d_tag != 0)
1246                                         continue;
1247 
1248                                 if (pathrec_req.SGID.gid_prefix !=
1249                                     dinfo->dest[k].d_gid.gid_prefix) {
1250                                         IBTF_DPRINTF_L3(cmlog,
1251                                             "ibcm_get_single_pathrec: SGID_pfx="
1252                                             "%llX, DGID_pfx=%llX doesn't match",
1253                                             pathrec_req.SGID.gid_prefix,
1254                                             dinfo->dest[k].d_gid.gid_prefix);
1255                                         continue;
1256                                 }
1257 
1258                                 pathrec_req.DGID = dinfo->dest[k].d_gid;
1259                                 c_mask |= SA_PR_COMPMASK_DGID;
1260 
1261                                 /*
1262                                  * If we had performed Service Look-up, then we
1263                                  * got P_Key from ServiceRecord, so get path
1264                                  * records that satisfy this particular P_Key.
1265                                  */
1266                                 if ((dinfo->p_key == 0) &&
1267                                     (dinfo->dest[k].d_pkey != 0)) {
1268                                         pathrec_req.P_Key =
1269                                             dinfo->dest[k].d_pkey;
1270                                         c_mask |= SA_PR_COMPMASK_PKEY;
1271                                 }
1272                         }
1273 
1274                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: "
1275                             "Get %d Path(s) between\nSGID %llX:%llX "
1276                             "DGID %llX:%llX", pathrec_req.NumbPath,
1277                             pathrec_req.SGID.gid_prefix,
1278                             pathrec_req.SGID.gid_guid,
1279                             pathrec_req.DGID.gid_prefix,
1280                             pathrec_req.DGID.gid_guid);
1281 
1282                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: CMask"
1283                             "=0x%llX, PKey=0x%X", c_mask, pathrec_req.P_Key);
1284 
1285                         /* Contact SA Access to retrieve Path Records. */
1286                         access_args.sq_attr_id = SA_PATHRECORD_ATTRID;
1287                         access_args.sq_template = &pathrec_req;
1288                         access_args.sq_access_type = IBMF_SAA_RETRIEVE;
1289                         access_args.sq_template_length =
1290                             sizeof (sa_path_record_t);
1291                         access_args.sq_component_mask = c_mask;
1292                         access_args.sq_callback = NULL;
1293                         access_args.sq_callback_arg = NULL;
1294 
1295                         retval = ibcm_contact_sa_access(saa_handle,
1296                             &access_args, &length, &results_p);
1297                         if (retval != IBT_SUCCESS) {
1298                                 *num_path = 0;
1299                                 return (retval);
1300                         }
1301 
1302                         num_rec = length / sizeof (sa_path_record_t);
1303 
1304                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: "
1305                             "FOUND %d/%d path requested", num_rec, *num_path);
1306 
1307                         if ((results_p == NULL) || (num_rec == 0)) {
1308                                 if (idx != 0xFF)
1309                                         break;
1310                                 else
1311                                         continue;
1312                         }
1313 
1314                         /* Update the PathInfo from the response. */
1315                         pr_resp = (sa_path_record_t *)results_p;
1316                         for (j = 0; j < num_rec; j++, pr_resp++) {
1317                                 if ((p_fnd != 0) &&
1318                                     (p_arg->flags & IBT_PATH_APM)) {
1319                                         IBTF_DPRINTF_L3(cmlog,
1320                                             "ibcm_get_single_pathrec: "
1321                                             "Fill Alternate Path");
1322                                         retval = ibcm_update_cep_info(pr_resp,
1323                                             sl, NULL,
1324                                             &paths[found - 1].pi_alt_cep_path);
1325                                         if (retval != IBT_SUCCESS)
1326                                                 continue;
1327 
1328                                         /* Update some leftovers */
1329                                         paths[found - 1].pi_alt_pkt_lt =
1330                                             pr_resp->PacketLifeTime;
1331                                         p_fnd = 0;
1332                                 } else {
1333                                         IBTF_DPRINTF_L3(cmlog,
1334                                             "ibcm_get_single_pathrec: "
1335                                             "Fill Primary Path");
1336 
1337                                         if (found == *num_path)
1338                                                 break;
1339 
1340                                         retval = ibcm_update_pri(pr_resp, sl,
1341                                             dinfo, &paths[found]);
1342                                         if (retval != IBT_SUCCESS)
1343                                                 continue;
1344                                         p_fnd = 1;
1345                                         found++;
1346                                 }
1347 
1348                         }
1349                         /* Deallocate the memory for results_p. */
1350                         kmem_free(results_p, length);
1351 
1352                         if (idx != 0xFF)
1353                                 break;          /* We r here for MGID */
1354                 }
1355                 if ((idx != 0xFF) && (found == *num_path))
1356                         break;          /* We r here for MGID */
1357         }
1358 
1359         if (found == 0)
1360                 retval = IBT_PATH_RECORDS_NOT_FOUND;
1361         else if (found != *num_path)
1362                 retval = IBT_INSUFF_DATA;
1363         else
1364                 retval = IBT_SUCCESS;
1365 
1366         IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: done. Status %d, "
1367             "Found %d/%d Paths", retval, found, *num_path);
1368 
1369         *num_path = found;
1370 
1371         return (retval);
1372 }
1373 
1374 
1375 static ibt_status_t
1376 ibcm_get_multi_pathrec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
1377     ibcm_dinfo_t *dinfo, uint8_t *num_path, ibt_path_info_t *paths)
1378 {
1379         sa_multipath_record_t   *mpr_req;
1380         sa_path_record_t        *pr_resp;
1381         ibmf_saa_access_args_t  access_args;
1382         void                    *results_p;
1383         uint64_t                c_mask = 0;
1384         ib_gid_t                *gid_ptr, *gid_s_ptr;
1385         size_t                  length;
1386         int                     template_len;
1387         uint8_t                 found, num_rec;
1388         int                     i, k;
1389         ibt_status_t            retval;
1390         uint8_t                 sgid_cnt, dgid_cnt;
1391         ibt_path_attr_t         *attrp = &p_arg->attr;
1392 
1393         IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec(%p, %p, %p, %d)",
1394             attrp, sl, dinfo, *num_path);
1395 
1396         for (i = 0, dgid_cnt = 0; i < dinfo->num_dest; i++) {
1397                 if (dinfo->dest[i].d_tag == 0)
1398                         dgid_cnt++;
1399         }
1400 
1401         sgid_cnt = sl->p_count;
1402 
1403         if ((sgid_cnt == 0) || (dgid_cnt == 0)) {
1404                 IBTF_DPRINTF_L2(cmlog, "ibcm_get_multi_pathrec: sgid_cnt(%d) or"
1405                     " dgid_cnt(%d) is zero", sgid_cnt, dgid_cnt);
1406                 return (IBT_INVALID_PARAM);
1407         }
1408 
1409         IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: Get %d records between "
1410             "%d Src(s) <=> %d Dest(s)", *num_path, sgid_cnt, dgid_cnt);
1411 
1412         /*
1413          * Calculate the size for multi-path records template, which includes
1414          * constant portion of the multipath record, plus variable size for
1415          * SGID (sgid_cnt) and DGID (dgid_cnt).
1416          */
1417         template_len = ((dgid_cnt + sgid_cnt) * sizeof (ib_gid_t)) +
1418             sizeof (sa_multipath_record_t);
1419 
1420         mpr_req = kmem_zalloc(template_len, KM_SLEEP);
1421 
1422         ASSERT(mpr_req != NULL);
1423 
1424         gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
1425             sizeof (sa_multipath_record_t));
1426 
1427         /* Get the starting pointer where GIDs are stored. */
1428         gid_s_ptr = gid_ptr;
1429 
1430         /* SGID */
1431         for (i = 0; i < sgid_cnt; i++) {
1432                 *gid_ptr = sl[i].p_sgid;
1433 
1434                 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: SGID[%d] = "
1435                     "(%llX:%llX)", i, gid_ptr->gid_prefix, gid_ptr->gid_guid);
1436 
1437                 gid_ptr++;
1438         }
1439 
1440         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
1441 
1442         mpr_req->SGIDCount = sgid_cnt;
1443         c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
1444 
1445         /* DGIDs */
1446         for (i = 0; i < dinfo->num_dest; i++) {
1447                 if (dinfo->dest[i].d_tag == 0) {
1448                         *gid_ptr = dinfo->dest[i].d_gid;
1449 
1450                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1451                             "DGID[%d] = (%llX:%llX)", i, gid_ptr->gid_prefix,
1452                             gid_ptr->gid_guid);
1453                         gid_ptr++;
1454                 }
1455         }
1456 
1457         mpr_req->DGIDCount = dgid_cnt;
1458         c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
1459 
1460         /* Is Flow Label Specified. */
1461         if (attrp->pa_flow) {
1462                 mpr_req->FlowLabel = attrp->pa_flow;
1463                 c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
1464         }
1465 
1466         /* Is HopLimit Specified. */
1467         if (p_arg->flags & IBT_PATH_HOP) {
1468                 mpr_req->HopLimit = attrp->pa_hop;
1469                 c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
1470         }
1471 
1472         /* Is TClass Specified. */
1473         if (attrp->pa_tclass) {
1474                 mpr_req->TClass = attrp->pa_tclass;
1475                 c_mask |= SA_MPR_COMPMASK_TCLASS;
1476         }
1477 
1478         /* Is SL specified. */
1479         if (attrp->pa_sl) {
1480                 mpr_req->SL = attrp->pa_sl;
1481                 c_mask |= SA_MPR_COMPMASK_SL;
1482         }
1483 
1484         if (p_arg->flags & IBT_PATH_PERF) {
1485                 mpr_req->PacketLifeTimeSelector = IBT_BEST;
1486                 mpr_req->RateSelector = IBT_BEST;
1487                 mpr_req->MtuSelector = IBT_BEST;
1488 
1489                 c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
1490                     SA_MPR_COMPMASK_RATESELECTOR | SA_MPR_COMPMASK_MTUSELECTOR;
1491         } else {
1492                 if (attrp->pa_pkt_lt.p_selector == IBT_BEST) {
1493                         mpr_req->PacketLifeTimeSelector = IBT_BEST;
1494                         c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
1495                 }
1496 
1497                 if (attrp->pa_srate.r_selector == IBT_BEST) {
1498                         mpr_req->RateSelector = IBT_BEST;
1499                         c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
1500                 }
1501 
1502                 if (attrp->pa_mtu.r_selector == IBT_BEST) {
1503                         mpr_req->MtuSelector = IBT_BEST;
1504                         c_mask |= SA_MPR_COMPMASK_MTUSELECTOR;
1505                 }
1506         }
1507 
1508         /*
1509          * Honor individual selection of these attributes,
1510          * even if IBT_PATH_PERF is set.
1511          */
1512         /* Check out whether Packet Life Time is specified. */
1513         if (attrp->pa_pkt_lt.p_pkt_lt) {
1514                 mpr_req->PacketLifeTime =
1515                     ibt_usec2ib(attrp->pa_pkt_lt.p_pkt_lt);
1516                 mpr_req->PacketLifeTimeSelector =
1517                     attrp->pa_pkt_lt.p_selector;
1518 
1519                 c_mask |= SA_MPR_COMPMASK_PKTLT |
1520                     SA_MPR_COMPMASK_PKTLTSELECTOR;
1521         }
1522 
1523         /* Is SRATE specified. */
1524         if (attrp->pa_srate.r_srate) {
1525                 mpr_req->Rate = attrp->pa_srate.r_srate;
1526                 mpr_req->RateSelector = attrp->pa_srate.r_selector;
1527 
1528                 c_mask |= SA_MPR_COMPMASK_RATE |
1529                     SA_MPR_COMPMASK_RATESELECTOR;
1530         }
1531 
1532         /* Is MTU specified. */
1533         if (attrp->pa_mtu.r_mtu) {
1534                 mpr_req->Mtu = attrp->pa_mtu.r_mtu;
1535                 mpr_req->MtuSelector = attrp->pa_mtu.r_selector;
1536 
1537                 c_mask |= SA_MPR_COMPMASK_MTU |
1538                     SA_MPR_COMPMASK_MTUSELECTOR;
1539         }
1540 
1541         /* Is P_Key Specified or obtained during Service Look-up. */
1542         if (dinfo->p_key) {
1543                 mpr_req->P_Key = dinfo->p_key;
1544                 c_mask |= SA_MPR_COMPMASK_PKEY;
1545         }
1546 
1547         /* We always get REVERSIBLE paths. */
1548         mpr_req->Reversible = 1;
1549         c_mask |= SA_MPR_COMPMASK_REVERSIBLE;
1550 
1551         if (p_arg->flags & IBT_PATH_AVAIL) {
1552                 mpr_req->IndependenceSelector = 1;
1553                 c_mask |= SA_MPR_COMPMASK_INDEPSEL;
1554         }
1555 
1556         /* we will not specify how many records we want. */
1557 
1558         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
1559 
1560         IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: CMask: %llX Pkey: %X",
1561             c_mask, mpr_req->P_Key);
1562 
1563         /* Contact SA Access to retrieve Path Records. */
1564         access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
1565         access_args.sq_access_type = IBMF_SAA_RETRIEVE;
1566         access_args.sq_component_mask = c_mask;
1567         access_args.sq_template = mpr_req;
1568         access_args.sq_template_length = sizeof (sa_multipath_record_t);
1569         access_args.sq_callback = NULL;
1570         access_args.sq_callback_arg = NULL;
1571 
1572         retval = ibcm_contact_sa_access(sl->p_saa_hdl, &access_args, &length,
1573             &results_p);
1574         if (retval != IBT_SUCCESS) {
1575                 *num_path = 0;  /* Update the return count. */
1576                 kmem_free(mpr_req, template_len);
1577                 return (retval);
1578         }
1579 
1580         num_rec = length / sizeof (sa_path_record_t);
1581 
1582         IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: Found %d Paths",
1583             num_rec);
1584 
1585         found = 0;
1586         if ((results_p != NULL) && (num_rec > 0)) {
1587                 /* Update the PathInfo with the response Path Records */
1588                 pr_resp = (sa_path_record_t *)results_p;
1589 
1590                 for (i = 0; i < num_rec; i++) {
1591                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1592                             "P[%d]: SG %llX, DG %llX", i,
1593                             pr_resp[i].SGID.gid_guid, pr_resp[i].DGID.gid_guid);
1594                 }
1595 
1596                 if (p_arg->flags & (IBT_PATH_APM | IBT_PATH_AVAIL)) {
1597                         sa_path_record_t *p_resp = NULL, *a_resp = NULL;
1598                         sa_path_record_t *p_tmp = NULL, *a_tmp = NULL;
1599                         int             p_found = 0, a_found = 0;
1600                         ib_gid_t        p_sg, a_sg, p_dg, a_dg;
1601                         int             p_tmp_found = 0, a_tmp_found = 0;
1602 
1603                         p_sg = gid_s_ptr[0];
1604                         if (sgid_cnt > 1)
1605                                 a_sg = gid_s_ptr[1];
1606                         else
1607                                 a_sg = p_sg;
1608 
1609                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1610                             "REQ: P_SG: %llX, A_SG: %llX",
1611                             p_sg.gid_guid, a_sg.gid_guid);
1612 
1613                         p_dg = gid_s_ptr[sgid_cnt];
1614                         if (dgid_cnt > 1)
1615                                 a_dg = gid_s_ptr[sgid_cnt + 1];
1616                         else
1617                                 a_dg = p_dg;
1618 
1619                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1620                             "REQ: P_DG: %llX, A_DG: %llX",
1621                             p_dg.gid_guid, a_dg.gid_guid);
1622 
1623                         /*
1624                          * If SGID and/or DGID is specified by user, make sure
1625                          * they get their primary-path on those node points.
1626                          */
1627                         for (i = 0; i < num_rec; i++, pr_resp++) {
1628                                 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec:"
1629                                     " PF %d, AF %d,\n\t\t P[%d] = SG: %llX, "
1630                                     "DG: %llX", p_found, a_found, i,
1631                                     pr_resp->SGID.gid_guid,
1632                                     pr_resp->DGID.gid_guid);
1633 
1634                                 if ((!p_found) &&
1635                                     (p_dg.gid_guid == pr_resp->DGID.gid_guid)) {
1636                                         IBTF_DPRINTF_L3(cmlog,
1637                                             "ibcm_get_multi_pathrec: "
1638                                             "Pri DGID Match.. ");
1639                                         if (p_sg.gid_guid ==
1640                                             pr_resp->SGID.gid_guid) {
1641                                                 p_found = 1;
1642                                                 p_resp = pr_resp;
1643                                                 IBTF_DPRINTF_L3(cmlog,
1644                                                     "ibcm_get_multi_pathrec: "
1645                                                     "Primary Path Found");
1646 
1647                                                 if (a_found)
1648                                                         break;
1649                                                 else
1650                                                         continue;
1651                                         } else if ((!p_tmp_found) &&
1652                                             (a_sg.gid_guid ==
1653                                             pr_resp->SGID.gid_guid)) {
1654                                                 p_tmp_found = 1;
1655                                                 p_tmp = pr_resp;
1656                                                 IBTF_DPRINTF_L3(cmlog,
1657                                                     "ibcm_get_multi_pathrec: "
1658                                                     "Tmp Pri Path Found");
1659                                         }
1660                                         IBTF_DPRINTF_L3(cmlog,
1661                                             "ibcm_get_multi_pathrec:"
1662                                             "Pri SGID Don't Match.. ");
1663                                 }
1664 
1665                                 if ((!a_found) &&
1666                                     (a_dg.gid_guid == pr_resp->DGID.gid_guid)) {
1667                                         IBTF_DPRINTF_L3(cmlog,
1668                                             "ibcm_get_multi_pathrec:"
1669                                             "Alt DGID Match.. ");
1670                                         if (a_sg.gid_guid ==
1671                                             pr_resp->SGID.gid_guid) {
1672                                                 a_found = 1;
1673                                                 a_resp = pr_resp;
1674 
1675                                                 IBTF_DPRINTF_L3(cmlog,
1676                                                     "ibcm_get_multi_pathrec:"
1677                                                     "Alternate Path Found ");
1678 
1679                                                 if (p_found)
1680                                                         break;
1681                                                 else
1682                                                         continue;
1683                                         } else if ((!a_tmp_found) &&
1684                                             (p_sg.gid_guid ==
1685                                             pr_resp->SGID.gid_guid)) {
1686                                                 a_tmp_found = 1;
1687                                                 a_tmp = pr_resp;
1688 
1689                                                 IBTF_DPRINTF_L3(cmlog,
1690                                                     "ibcm_get_multi_pathrec:"
1691                                                     "Tmp Alt Path Found ");
1692                                         }
1693                                         IBTF_DPRINTF_L3(cmlog,
1694                                             "ibcm_get_multi_pathrec:"
1695                                             "Alt SGID Don't Match.. ");
1696                                 }
1697                         }
1698 
1699                         if ((p_found == 0) && (a_found == 0) &&
1700                             (p_tmp_found == 0) && (a_tmp_found == 0)) {
1701                                 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec:"
1702                                     " Path to desired node points NOT "
1703                                     "Available.");
1704                                 retval = IBT_PATH_RECORDS_NOT_FOUND;
1705                                 goto get_mpr_end;
1706                         }
1707 
1708                         if (p_resp == NULL) {
1709                                 if (a_resp != NULL) {
1710                                         p_resp = a_resp;
1711                                         a_resp = NULL;
1712                                 } else if (p_tmp != NULL) {
1713                                         p_resp = p_tmp;
1714                                         p_tmp = NULL;
1715                                 } else if (a_tmp != NULL) {
1716                                         p_resp = a_tmp;
1717                                         a_tmp = NULL;
1718                                 }
1719                         }
1720                         if (a_resp == NULL) {
1721                                 if (a_tmp != NULL) {
1722                                         a_resp = a_tmp;
1723                                         a_tmp = NULL;
1724                                 } else if (p_tmp != NULL) {
1725                                         a_resp = p_tmp;
1726                                         p_tmp = NULL;
1727                                 }
1728                         }
1729 
1730                         /* Fill in Primary Path */
1731                         retval = ibcm_update_pri(p_resp, sl, dinfo,
1732                             &paths[found]);
1733                         if (retval != IBT_SUCCESS)
1734                                 goto get_mpr_end;
1735 
1736                         if (p_arg->flags & IBT_PATH_APM) {
1737                                 /* Fill in Alternate Path */
1738                                 if (a_resp != NULL) {
1739                                         /*
1740                                          * a_resp will point to AltPathInfo
1741                                          * buffer.
1742                                          */
1743                                         retval = ibcm_update_cep_info(a_resp,
1744                                             sl, NULL,
1745                                             &paths[found].pi_alt_cep_path);
1746                                         if (retval != IBT_SUCCESS)
1747                                                 goto get_mpr_end;
1748 
1749                                         /* Update some leftovers */
1750                                         paths[found].pi_alt_pkt_lt =
1751                                             a_resp->PacketLifeTime;
1752                                 } else {
1753                                         IBTF_DPRINTF_L3(cmlog,
1754                                             "ibcm_get_multi_pathrec:"
1755                                             " Alternate Path NOT Available.");
1756                                         retval = IBT_INSUFF_DATA;
1757                                 }
1758                                 found++;
1759                         } else if (p_arg->flags & IBT_PATH_AVAIL) {
1760                                 found++;
1761 
1762                                 if (found < *num_path) {
1763 
1764                                         /* Fill in second Path */
1765                                         if (a_resp != NULL) {
1766                                                 retval = ibcm_update_pri(a_resp,
1767                                                     sl, dinfo, &paths[found]);
1768                                                 if (retval != IBT_SUCCESS)
1769                                                         goto get_mpr_end;
1770                                                 else
1771                                                         found++;
1772                                         } else {
1773                                                 IBTF_DPRINTF_L3(cmlog,
1774                                                     "ibcm_get_multi_pathrec: "
1775                                                     "SecondPath NOT Available");
1776                                                 retval = IBT_INSUFF_DATA;
1777                                         }
1778                                 }
1779                         }
1780                 } else {        /* If NOT APM */
1781                         boolean_t       check_pkey = B_FALSE;
1782 
1783                         /* mark flag whether to validate PKey or not. */
1784                         if ((dinfo->p_key == 0) && (dinfo->dest[0].d_pkey != 0))
1785                                 check_pkey = B_TRUE;
1786 
1787                         for (i = 0; i < num_rec; i++, pr_resp++) {
1788                                 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec:"
1789                                     " PKeyCheck - %s, PKey=0x%X, DGID(%llX)",
1790                                     ((check_pkey == B_TRUE)?"REQD":"NOT_REQD"),
1791                                     pr_resp->P_Key, pr_resp->DGID.gid_guid);
1792 
1793                                 if (check_pkey) {
1794                                         boolean_t       match_found = B_FALSE;
1795 
1796                                         /* For all DGIDs */
1797                                         for (k = 0; k < dinfo->num_dest; k++) {
1798                                                 if (dinfo->dest[k].d_tag != 0)
1799                                                         continue;
1800 
1801                                                 if ((dinfo->dest[k].d_gid.
1802                                                     gid_guid ==
1803                                                     pr_resp->DGID.gid_guid) &&
1804                                                     (dinfo->dest[k].d_pkey ==
1805                                                     pr_resp->P_Key)) {
1806                                                         match_found = B_TRUE;
1807                                                         break;
1808                                                 }
1809                                         }
1810                                         if (!match_found)
1811                                                 continue;
1812                                 }
1813                                 /* Fill in Primary Path */
1814                                 retval = ibcm_update_pri(pr_resp, sl, dinfo,
1815                                     &paths[found]);
1816                                 if (retval != IBT_SUCCESS)
1817                                         continue;
1818 
1819                                 if (++found == *num_path)
1820                                         break;
1821                         }
1822                 }
1823 get_mpr_end:
1824                 kmem_free(results_p, length);
1825         }
1826         kmem_free(mpr_req, template_len);
1827 
1828         if (found == 0)
1829                 retval = IBT_PATH_RECORDS_NOT_FOUND;
1830         else if (found != *num_path)
1831                 retval = IBT_INSUFF_DATA;
1832         else
1833                 retval = IBT_SUCCESS;
1834 
1835         IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: Done (status %d). "
1836             "Found %d/%d Paths", retval, found, *num_path);
1837 
1838         *num_path = found;      /* Update the return count. */
1839 
1840         return (retval);
1841 }
1842 
1843 
1844 /*
1845  * Update the output path records buffer with the values as obtained from
1846  * SA Access retrieve call results for Path Records.
1847  */
1848 static ibt_status_t
1849 ibcm_update_cep_info(sa_path_record_t *prec_resp, ibtl_cm_port_list_t *sl,
1850     ibtl_cm_hca_port_t *hport, ibt_cep_path_t *cep_p)
1851 {
1852         ibt_status_t    retval;
1853         int             i;
1854 
1855         IBCM_DUMP_PATH_REC(prec_resp);
1856 
1857         /*
1858          * If path's packet life time is more than 4 seconds, IBCM cannot
1859          * handle this path connection, so discard this path record.
1860          */
1861         if (prec_resp->PacketLifeTime > ibcm_max_ib_pkt_lt) {
1862                 IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: Path's Packet "
1863                     "LifeTime too high %d, Maximum allowed %d IB Time (4 sec)",
1864                     prec_resp->PacketLifeTime, ibcm_max_ib_pkt_lt);
1865                 return (ibt_get_module_failure(IBT_FAILURE_IBSM, 0));
1866         }
1867 
1868         if ((prec_resp->Mtu > IB_MTU_4K) || (prec_resp->Mtu < IB_MTU_256)) {
1869                 IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: MTU (%d) from "
1870                     "pathrecord is invalid, reject it.", prec_resp->Mtu);
1871                 return (ibt_get_module_failure(IBT_FAILURE_IBSM, 0));
1872         }
1873 
1874         /* Source Node Information. */
1875         cep_p->cep_adds_vect.av_sgid = prec_resp->SGID;
1876         if (hport != NULL) {
1877                 /* Convert P_Key to P_Key_Index */
1878                 retval = ibt_pkey2index_byguid(hport->hp_hca_guid,
1879                     hport->hp_port, prec_resp->P_Key, &cep_p->cep_pkey_ix);
1880                 if (retval != IBT_SUCCESS) {
1881                         /* Failed to get pkey_index from pkey */
1882                         IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: "
1883                             "Pkey2Index (PKey = %X) conversion failed: %d",
1884                             prec_resp->P_Key, retval);
1885                         return (ibt_get_module_failure(IBT_FAILURE_IBSM, 0));
1886                 }
1887                 cep_p->cep_adds_vect.av_sgid_ix = hport->hp_sgid_ix;
1888                 cep_p->cep_adds_vect.av_src_path =
1889                     prec_resp->SLID - hport->hp_base_lid;
1890                 cep_p->cep_adds_vect.av_port_num = cep_p->cep_hca_port_num =
1891                     hport->hp_port;
1892         } else if (sl != NULL) {
1893                 for (i = 0; i < sl->p_count; i++) {
1894                         if (prec_resp->SGID.gid_guid == sl[i].p_sgid.gid_guid) {
1895                                 /* Convert P_Key to P_Key_Index */
1896                                 retval = ibt_pkey2index_byguid(sl[i].p_hca_guid,
1897                                     sl[i].p_port_num, prec_resp->P_Key,
1898                                     &cep_p->cep_pkey_ix);
1899                                 if (retval != IBT_SUCCESS) {
1900                                         /* Failed to get pkey_index from pkey */
1901                                         IBTF_DPRINTF_L2(cmlog,
1902                                             "ibcm_update_cep_info: Pkey2Index "
1903                                             "(PKey = %X) conversion failed: %d",
1904                                             prec_resp->P_Key, retval);
1905                                         return (ibt_get_module_failure(
1906                                             IBT_FAILURE_IBSM, 0));
1907                                 }
1908 
1909                                 cep_p->cep_adds_vect.av_sgid_ix =
1910                                     sl[i].p_sgid_ix;
1911                                 cep_p->cep_adds_vect.av_src_path =
1912                                     prec_resp->SLID - sl[i].p_base_lid;
1913                                 cep_p->cep_adds_vect.av_port_num =
1914                                     sl[i].p_port_num;
1915                                 cep_p->cep_hca_port_num = sl[i].p_port_num;
1916 
1917                                 break;
1918                         }
1919                 }
1920         } else {
1921                 IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: Sl or Hport "
1922                     "must be non-null");
1923                 return (IBT_INVALID_PARAM);
1924         }
1925 
1926         if (prec_resp->Rate) {
1927                 cep_p->cep_adds_vect.av_srate = prec_resp->Rate;
1928         } else {
1929                 IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: SRate (%d) from "
1930                     "pathrecord is invalid, reject it.", prec_resp->Rate);
1931                 return (ibt_get_module_failure(IBT_FAILURE_IBSM, 0));
1932         }
1933         /*
1934          * If both Source and Destination GID prefix are same, then GRH is not
1935          * valid, so make it as false, else set this field as true.
1936          */
1937         if (prec_resp->SGID.gid_prefix == prec_resp->DGID.gid_prefix)
1938                 cep_p->cep_adds_vect.av_send_grh = B_FALSE;
1939         else
1940                 cep_p->cep_adds_vect.av_send_grh = B_TRUE;
1941 
1942         /* SGID and SGID Index. */
1943         cep_p->cep_adds_vect.av_sgid = prec_resp->SGID;
1944         cep_p->cep_adds_vect.av_flow = prec_resp->FlowLabel;
1945         cep_p->cep_adds_vect.av_tclass = prec_resp->TClass;
1946         cep_p->cep_adds_vect.av_hop = prec_resp->HopLimit;
1947 
1948         /* Address Vector Definition. */
1949         cep_p->cep_adds_vect.av_dlid = prec_resp->DLID;
1950         cep_p->cep_adds_vect.av_srvl = prec_resp->SL;
1951 
1952         /* DGID */
1953         cep_p->cep_adds_vect.av_dgid = prec_resp->DGID;
1954 
1955         /* CEP Timeout is NOT filled in by PATH routines. */
1956         cep_p->cep_timeout = 0;
1957 
1958         IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: Done. Port=%d, PKey=%X\n"
1959             "SGID=%llX:%llX DGID=%llX:%llX", cep_p->cep_adds_vect.av_port_num,
1960             prec_resp->P_Key,
1961             prec_resp->SGID.gid_prefix, prec_resp->SGID.gid_guid,
1962             prec_resp->DGID.gid_prefix, prec_resp->DGID.gid_guid);
1963 
1964         return (IBT_SUCCESS);
1965 }
1966 
1967 
1968 static void
1969 ibcm_fill_svcinfo(sa_service_record_t *sr_resp, ibcm_dest_t *dest)
1970 {
1971         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dest))
1972 
1973         dest->d_gid = sr_resp->ServiceGID;
1974         dest->d_sid = sr_resp->ServiceID;
1975         ibcm_swizzle_to_srv(sr_resp->ServiceData, &dest->d_sdata);
1976         dest->d_pkey = sr_resp->ServiceP_Key;
1977 
1978         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*dest))
1979 
1980         IBTF_DPRINTF_L3(cmlog, "ibcm_fill_svcinfo: SID(%llX), GID(%llX:%llX)"
1981             "\n\tSvcPKey 0x%X", dest->d_sid, dest->d_gid.gid_prefix,
1982             dest->d_gid.gid_guid, dest->d_pkey);
1983 }
1984 
1985 
1986 static ib_gid_t
1987 ibcm_saa_get_agid(ibtl_cm_port_list_t *sl, ib_gid_t *gidp, uint_t ngid)
1988 {
1989         int             k, l;
1990         ib_gid_t        a_gid;
1991 
1992         a_gid.gid_prefix = a_gid.gid_guid = 0;
1993 
1994         for (k = 0; k < sl->p_count; k++) {
1995                 for (l = 0; l < ngid; l++) {
1996 
1997                         if (gidp->gid_prefix == sl->p_sgid.gid_prefix) {
1998                                 a_gid = *gidp;
1999                                 break;
2000                         }
2001                         if (a_gid.gid_guid && a_gid.gid_prefix)
2002                                 break;
2003                         gidp++;
2004                 }
2005                 if (a_gid.gid_guid && a_gid.gid_prefix)
2006                         break;
2007                 sl++;
2008         }
2009         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_get_agid: AltGID = %llX:%llX",
2010             a_gid.gid_prefix, a_gid.gid_guid);
2011 
2012         return (a_gid);
2013 }
2014 
2015 /*
2016  * Perform SA Access to retrieve Service Records.
2017  * On Success, returns ServiceID and ServiceGID info in '*dinfo'.
2018  */
2019 static ibt_status_t
2020 ibcm_saa_service_rec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
2021     ibcm_dinfo_t *dinfo)
2022 {
2023         sa_service_record_t     svcrec_req;
2024         sa_service_record_t     *svcrec_resp;
2025         void                    *results_p;
2026         uint64_t                component_mask = 0;
2027         size_t                  length;
2028         uint8_t                 i, j, k, rec_found, s;
2029         ibmf_saa_access_args_t  access_args;
2030         ibt_status_t            retval;
2031         ibt_path_attr_t         *attrp = &p_arg->attr;
2032         uint64_t                tmp_sd_flag = attrp->pa_sd_flags;
2033         uint8_t                 num_req;
2034 
2035         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec(%p, %p)", p_arg, sl);
2036 
2037         bzero(&svcrec_req, sizeof (svcrec_req));
2038 
2039         /* Service Name */
2040         if ((attrp->pa_sname != NULL) && (strlen(attrp->pa_sname) != 0)) {
2041                 (void) strncpy((char *)(svcrec_req.ServiceName),
2042                     attrp->pa_sname, IB_SVC_NAME_LEN);
2043 
2044                 component_mask |= SA_SR_COMPMASK_NAME;
2045         }
2046 
2047         /* Service ID */
2048         if (attrp->pa_sid) {
2049                 svcrec_req.ServiceID = attrp->pa_sid;
2050                 component_mask |= SA_SR_COMPMASK_ID;
2051         }
2052 
2053         /* Is P_Key Specified. */
2054         if (p_arg->flags & IBT_PATH_PKEY) {
2055                 svcrec_req.ServiceP_Key = attrp->pa_pkey;
2056                 component_mask |= SA_SR_COMPMASK_PKEY;
2057         }
2058 
2059         /* Is ServiceData Specified. */
2060         if (attrp->pa_sd_flags != IBT_NO_SDATA) {
2061                 /* Handle endianess for service data. */
2062                 ibcm_swizzle_from_srv(&attrp->pa_sdata, svcrec_req.ServiceData);
2063 
2064                 /*
2065                  * Lets not interpret each and every ServiceData flags,
2066                  * just pass it on to SAA. Shift the flag, to suit
2067                  * SA_SR_COMPMASK_ALL_DATA definition.
2068                  */
2069                 component_mask |= (tmp_sd_flag << 7);
2070         }
2071 
2072         if (dinfo->num_dest == 1) {
2073 
2074                 /* If a single DGID is specified, provide it */
2075                 svcrec_req.ServiceGID = dinfo->dest->d_gid;
2076                 component_mask |= SA_SR_COMPMASK_GID;
2077 
2078                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec:%llX:%llX",
2079                     svcrec_req.ServiceGID.gid_prefix,
2080                     svcrec_req.ServiceGID.gid_guid);
2081         }
2082 
2083         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2084             "Perform SA Access: Mask: 0x%X", component_mask);
2085 
2086         /*
2087          * Call in SA Access retrieve routine to get Service Records.
2088          *
2089          * SA Access framework allocated memory for the "results_p".
2090          * Make sure to deallocate once we are done with the results_p.
2091          * The size of the buffer allocated will be as returned in
2092          * "length" field.
2093          */
2094         access_args.sq_attr_id = SA_SERVICERECORD_ATTRID;
2095         access_args.sq_access_type = IBMF_SAA_RETRIEVE;
2096         access_args.sq_component_mask = component_mask;
2097         access_args.sq_template = &svcrec_req;
2098         access_args.sq_template_length = sizeof (sa_service_record_t);
2099         access_args.sq_callback = NULL;
2100         access_args.sq_callback_arg = NULL;
2101 
2102         for (s = 0; s < sl->p_count; s++) {
2103                 retval = ibcm_contact_sa_access(sl[s].p_saa_hdl, &access_args,
2104                     &length, &results_p);
2105                 if (retval != IBT_SUCCESS)
2106                         if (sl[s].p_multi & IBTL_CM_MULTI_SM)
2107                                 continue;
2108                         else
2109                                 return (retval);
2110 
2111                 if ((results_p == NULL) || (length == 0)) {
2112                         IBTF_DPRINTF_L2(cmlog, "ibcm_saa_service_rec: SvcRec "
2113                             "Not Found: res_p %p, len %d", results_p, length);
2114                         if (sl[s].p_multi & IBTL_CM_MULTI_SM) {
2115                                 retval = IBT_SERVICE_RECORDS_NOT_FOUND;
2116                                 continue;
2117                         } else
2118                                 return (IBT_SERVICE_RECORDS_NOT_FOUND);
2119                 }
2120 
2121                 /* if we are here, we got some records. so break. */
2122                 break;
2123         }
2124 
2125         if (retval != IBT_SUCCESS)
2126                 return (retval);
2127 
2128         num_req = length / sizeof (sa_service_record_t);
2129 
2130         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Got %d Service Records.",
2131             num_req);
2132 
2133         svcrec_resp = (sa_service_record_t *)results_p;
2134         rec_found = 0;
2135 
2136         /* Update the return values. */
2137         if (dinfo->num_dest) {
2138                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Get ServiceRec "
2139                     "for Specified DGID: %d", dinfo->num_dest);
2140 
2141                 for (i = 0; i < num_req; i++, svcrec_resp++) {
2142                         /* Limited P_Key is NOT supported as of now!. */
2143                         if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2144                                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2145                                     "SvcPkey 0x%X limited, reject the record.",
2146                                     svcrec_resp->ServiceP_Key);
2147                                 continue;
2148                         }
2149 
2150                         for (j = 0; j < dinfo->num_dest; j++) {
2151                                 if (dinfo->dest[j].d_gid.gid_guid ==
2152                                     svcrec_resp->ServiceGID.gid_guid) {
2153                                         ibcm_fill_svcinfo(svcrec_resp,
2154                                             &dinfo->dest[j]);
2155                                         rec_found++;
2156                                 }
2157                                 if (rec_found == dinfo->num_dest)
2158                                         break;
2159                         }
2160                         if (rec_found == dinfo->num_dest)
2161                                 break;
2162                 }
2163                 if (rec_found != dinfo->num_dest) {
2164                         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Did NOT "
2165                             "find ServiceRec for all DGIDs: (%d/%d)", rec_found,
2166                             dinfo->num_dest);
2167                         retval = IBT_INSUFF_DATA;
2168                 }
2169         } else if (p_arg->flags & IBT_PATH_APM) {
2170                 ib_gid_t                p_gid, a_gid, last_p_gid;
2171                 ib_gid_t                *gidp = NULL;
2172                 uint_t                  n_gids;
2173                 sa_service_record_t     *stmp;
2174                 boolean_t               pri_fill_done = B_FALSE;
2175                 boolean_t               alt_fill_done = B_FALSE;
2176                 ib_pkey_t               p_pkey = 0, a_pkey = 0;
2177 
2178                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Need to "
2179                     "find ServiceRec that can satisfy APM");
2180 
2181                 p_gid.gid_prefix = p_gid.gid_guid = 0;
2182                 a_gid.gid_prefix = a_gid.gid_guid = 0;
2183                 last_p_gid.gid_prefix = last_p_gid.gid_guid = 0;
2184 
2185                 for (i = 0; i < num_req; i++, svcrec_resp++) {
2186                         ibt_status_t    ret;
2187                         boolean_t       is_this_on_local_node = B_FALSE;
2188 
2189                         /* Limited P_Key is NOT supported as of now!. */
2190                         if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2191                                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2192                                     "SvcPkey 0x%X limited, reject the record.",
2193                                     svcrec_resp->ServiceP_Key);
2194                                 continue;
2195                         }
2196 
2197                         p_gid = svcrec_resp->ServiceGID;
2198 
2199                         /* Let's avoid LoopBack Nodes. */
2200                         for (j = 0; j < sl->p_count; j++) {
2201                                 if (p_gid.gid_guid == sl[j].p_sgid.gid_guid) {
2202                                         is_this_on_local_node = B_TRUE;
2203 
2204                                         IBTF_DPRINTF_L3(cmlog,
2205                                             "ibcm_saa_service_rec: ServiceGID "
2206                                             "%llX:%llX is on Local Node, "
2207                                             "search for remote.",
2208                                             p_gid.gid_prefix, p_gid.gid_guid);
2209                                 }
2210                         }
2211 
2212                         if (is_this_on_local_node) {
2213                                 if ((i + 1) < num_req) {
2214                                         p_gid.gid_prefix = 0;
2215                                         p_gid.gid_guid = 0;
2216                                         continue;
2217                                 } else if (last_p_gid.gid_prefix != 0) {
2218                                         p_gid = last_p_gid;
2219                                         break;
2220                                 }
2221                         }
2222 
2223                         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2224                             "Finally let Primary DGID = %llX:%llX",
2225                             p_gid.gid_prefix, p_gid.gid_guid);
2226 
2227                         ret = ibt_get_companion_port_gids(p_gid, 0, 0,
2228                             &gidp, &n_gids);
2229                         if (ret == IBT_SUCCESS) {
2230                                 IBTF_DPRINTF_L3(cmlog,
2231                                     "ibcm_saa_service_rec: Found %d "
2232                                     "CompGID for %llX:%llX", n_gids,
2233                                     p_gid.gid_prefix, p_gid.gid_guid);
2234 
2235                                 stmp = (sa_service_record_t *)results_p;
2236                                 a_gid.gid_prefix = a_gid.gid_guid = 0;
2237 
2238                                 if (sl->p_multi & IBTL_CM_MULTI_SM) {
2239                                         /* validate sn_pfx */
2240                                         a_gid = ibcm_saa_get_agid(sl,
2241                                             gidp, n_gids);
2242                                 } else {
2243                                         for (k = 0; k < num_req; k++) {
2244                                                 ib_gid_t sg = stmp->ServiceGID;
2245 
2246                                                 IBTF_DPRINTF_L3(cmlog,
2247                                                     "ibcm_saa_service_rec: "
2248                                                     "SvcGID[%d] = %llX:%llX", k,
2249                                                     sg.gid_prefix, sg.gid_guid);
2250 
2251                                                 for (j = 0; j < n_gids; j++) {
2252                                                         if (gidp[j].gid_guid ==
2253                                                             sg.gid_guid) {
2254                                                                 a_gid = gidp[j];
2255                                                                 break;
2256                                                         }
2257                                                 }
2258                                                 if (a_gid.gid_guid)
2259                                                         break;
2260                                                 stmp++;
2261                                         }
2262                                         if (a_gid.gid_guid == 0) {
2263                                                 /* Rec not found for Alt. */
2264                                                 for (j = 0; j < n_gids; j++) {
2265                                                         if (gidp[j].gid_prefix
2266                                                             == p_gid.
2267                                                             gid_prefix) {
2268                                                                 a_gid = gidp[j];
2269                                                                 break;
2270                                                         }
2271                                                 }
2272                                         }
2273                                 }
2274                                 kmem_free(gidp,
2275                                     n_gids * sizeof (ib_gid_t));
2276 
2277                                 if (a_gid.gid_guid)
2278                                         break;
2279                         } else if (ret == IBT_GIDS_NOT_FOUND) {
2280                                 last_p_gid = p_gid;
2281                                 IBTF_DPRINTF_L3(cmlog,
2282                                     "ibcm_saa_service_rec: Didn't find "
2283                                     "CompGID for %llX:%llX, ret=%d",
2284                                     p_gid.gid_prefix, p_gid.gid_guid,
2285                                     ret);
2286                         } else {
2287                                 IBTF_DPRINTF_L3(cmlog,
2288                                     "ibcm_saa_service_rec: Call to "
2289                                     "ibt_get_companion_port_gids(%llX:"
2290                                     "%llX) Failed = %d",
2291                                     p_gid.gid_prefix, p_gid.gid_guid,
2292                                     ret);
2293                         }
2294                 }
2295 
2296                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: \n\t"
2297                     "Pri DGID(%llX:%llX), Alt DGID(%llX:%llX)",
2298                     p_gid.gid_prefix, p_gid.gid_guid, a_gid.gid_prefix,
2299                     a_gid.gid_guid);
2300 
2301                 svcrec_resp = (sa_service_record_t *)results_p;
2302 
2303                 for (i = 0, j = 0; i < num_req; i++, svcrec_resp++) {
2304                         /* Limited P_Key is NOT supported as of now!. */
2305                         if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2306                                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2307                                     "SvcPkey 0x%X limited, reject the record.",
2308                                     svcrec_resp->ServiceP_Key);
2309                                 continue;
2310                         }
2311 
2312                         if ((!pri_fill_done) && (p_gid.gid_guid ==
2313                             svcrec_resp->ServiceGID.gid_guid)) {
2314                                 p_pkey = svcrec_resp->ServiceP_Key;
2315                                 if ((a_pkey != 0) &&
2316                                     (a_pkey != p_pkey)) {
2317                                         IBTF_DPRINTF_L3(cmlog,
2318                                             "ibcm_saa_service_rec: "
2319                                             "Pri(0x%X) & Alt (0x%X) "
2320                                             "PKey must match.",
2321                                             p_pkey, a_pkey);
2322                                         p_pkey = 0;
2323                                         continue;
2324                                 }
2325                                 ibcm_fill_svcinfo(svcrec_resp,
2326                                     &dinfo->dest[j++]);
2327                                 rec_found++;
2328                                 pri_fill_done = B_TRUE;
2329                         } else if ((!alt_fill_done) && (a_gid.gid_guid ==
2330                             svcrec_resp->ServiceGID.gid_guid)) {
2331                                 a_pkey = svcrec_resp->ServiceP_Key;
2332                                 if ((p_pkey != 0) &&
2333                                     (a_pkey != p_pkey)) {
2334                                         IBTF_DPRINTF_L3(cmlog,
2335                                             "ibcm_saa_service_rec: "
2336                                             "Pri(0x%X) & Alt (0x%X) "
2337                                             "PKey must match.",
2338                                             p_pkey, a_pkey);
2339                                         a_pkey = 0;
2340                                         continue;
2341                                 }
2342                                 ibcm_fill_svcinfo(svcrec_resp,
2343                                     &dinfo->dest[j++]);
2344                                 rec_found++;
2345                                 alt_fill_done = B_TRUE;
2346                         }
2347 
2348                         if (rec_found == 2)
2349                                 break;
2350                 }
2351                 if ((!alt_fill_done) && (a_gid.gid_guid)) {
2352                         dinfo->dest[j].d_gid = a_gid;
2353                         dinfo->dest[j].d_pkey = p_pkey;
2354                         rec_found++;
2355                         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2356                             "Let Alt Pkey=%X, DGID=%llX:%llX", p_pkey,
2357                             a_gid.gid_prefix, a_gid.gid_guid);
2358                 }
2359 
2360                 if (rec_found == 1)
2361                         retval = IBT_INSUFF_DATA;
2362         } else if (p_arg->flags & IBT_PATH_MULTI_SVC_DEST) {
2363                 for (i = 0; i < num_req; i++, svcrec_resp++) {
2364                         ib_gid_t        p_gid;
2365                         boolean_t       is_this_on_local_node = B_FALSE;
2366 
2367                         /* Limited P_Key is NOT supported as of now!. */
2368                         if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2369                                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2370                                     "SvcPkey 0x%X limited, reject the record.",
2371                                     svcrec_resp->ServiceP_Key);
2372                                 continue;
2373                         }
2374 
2375                         p_gid = svcrec_resp->ServiceGID;
2376 
2377                         /* Let's avoid LoopBack Nodes. */
2378                         for (j = 0; j < sl->p_count; j++) {
2379                                 if (p_gid.gid_guid == sl[j].p_sgid.gid_guid) {
2380                                         is_this_on_local_node = B_TRUE;
2381                                         IBTF_DPRINTF_L3(cmlog,
2382                                             "ibcm_saa_service_rec: ServiceGID "
2383                                             "%llX:%llX is on Local Node, "
2384                                             "search for remote.",
2385                                             p_gid.gid_prefix, p_gid.gid_guid);
2386                                 }
2387                         }
2388 
2389                         if (is_this_on_local_node)
2390                                 if ((i + 1) < num_req)
2391                                         continue;
2392 
2393                         IBTF_DPRINTF_L4(cmlog, "ibcm_saa_service_rec: "
2394                             "Found ServiceGID = %llX:%llX",
2395                             p_gid.gid_prefix, p_gid.gid_guid);
2396 
2397                         ibcm_fill_svcinfo(svcrec_resp,
2398                             &dinfo->dest[rec_found]);
2399                         rec_found++;
2400                         if (rec_found == p_arg->max_paths)
2401                                 break;
2402                 }
2403 
2404                 if (rec_found < p_arg->max_paths)
2405                         retval = IBT_INSUFF_DATA;
2406         } else {
2407                 for (i = 0; i < num_req; i++) {
2408                         /* Limited P_Key is NOT supported as of now!. */
2409                         if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2410                                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2411                                     "SvcPkey 0x%X limited, reject the record.",
2412                                     svcrec_resp->ServiceP_Key);
2413                                 svcrec_resp++;
2414                                 continue;
2415                         }
2416 
2417                         ibcm_fill_svcinfo(svcrec_resp, &dinfo->dest[0]);
2418                         rec_found = 1;
2419 
2420                         /* Avoid having loopback node */
2421                         if (svcrec_resp->ServiceGID.gid_guid !=
2422                             sl->p_sgid.gid_guid) {
2423                                 break;
2424                         } else {
2425                                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2426                                     "avoid LoopBack node.");
2427                                 svcrec_resp++;
2428                         }
2429                 }
2430         }
2431 
2432         /* Deallocate the memory for results_p. */
2433         kmem_free(results_p, length);
2434         if (dinfo->num_dest == 0)
2435                 dinfo->num_dest = rec_found;
2436 
2437         /*
2438          * Check out whether all Service Path we looking for are on the same
2439          * P_key. If yes, then set the global p_key field with that value,
2440          * to make it easy during SA Path Query.
2441          */
2442         if ((dinfo->num_dest) && (dinfo->p_key == 0)) {
2443                 ib_pkey_t       pk = dinfo->dest[0].d_pkey;
2444 
2445                 if (dinfo->num_dest == 1) {
2446                         dinfo->p_key = pk;
2447                 } else {
2448                         for (i = 1; i < (dinfo->num_dest - 1); i++) {
2449                                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2450                                     "pk= 0x%X, pk[%d]= 0x%X", pk, i,
2451                                     dinfo->dest[i].d_pkey);
2452                                 if (pk != dinfo->dest[i].d_pkey) {
2453                                         dinfo->p_key = 0;
2454                                         break;
2455                                 } else {
2456                                         dinfo->p_key = pk;
2457                                 }
2458                         }
2459                 }
2460         }
2461 
2462         if (rec_found == 0) {
2463                 IBTF_DPRINTF_L2(cmlog, "ibcm_saa_service_rec: "
2464                     "ServiceRec NOT Found");
2465                 retval = IBT_SERVICE_RECORDS_NOT_FOUND;
2466         }
2467 
2468         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: done. Status %d, "
2469             "PKey 0x%X, Found %d SvcRec", retval, dinfo->p_key, rec_found);
2470 
2471         return (retval);
2472 }
2473 
2474 
2475 static boolean_t
2476 ibcm_compare_paths(sa_path_record_t *pr_resp, ibt_cep_path_t *rc_path,
2477     ibtl_cm_hca_port_t *c_hp)
2478 {
2479         if ((rc_path->cep_hca_port_num == c_hp->hp_port) &&
2480             (rc_path->cep_adds_vect.av_src_path ==
2481             (pr_resp->SLID - c_hp->hp_base_lid)) &&
2482             (rc_path->cep_adds_vect.av_dlid == pr_resp->DLID) &&
2483             (rc_path->cep_adds_vect.av_srate == pr_resp->Rate)) {
2484                 return (B_TRUE);
2485         } else {
2486                 return (B_FALSE);
2487         }
2488 }
2489 
2490 /*
2491  * ibcm_get_comp_pgids() routine gets the companion port for 'gid'.
2492  *
2493  * On success:
2494  *      If 'n_gid' is specified, then verify whether 'n_gid' is indeed a
2495  *      companion portgid of 'gid'.  If matches return success or else error.
2496  *
2497  *      If 'n_gid' is NOT specified, then return back SUCCESS along with
2498  *      obtained Companion PortGids 'gid_p', where 'num' indicated number
2499  *      of companion portgids returned in 'gid_p'.
2500  */
2501 
2502 static ibt_status_t
2503 ibcm_get_comp_pgids(ib_gid_t gid, ib_gid_t n_gid, ib_guid_t hca_guid,
2504     ib_gid_t **gid_p, uint_t *num)
2505 {
2506         ibt_status_t    ret;
2507         int             i;
2508 
2509         ret = ibt_get_companion_port_gids(gid, hca_guid, 0, gid_p, num);
2510         if ((ret != IBT_SUCCESS) && (ret != IBT_GIDS_NOT_FOUND)) {
2511                 IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: "
2512                     "ibt_get_companion_port_gids(%llX:%llX) Failed: %d",
2513                     gid.gid_prefix, gid.gid_guid, ret);
2514         } else if ((ret == IBT_GIDS_NOT_FOUND) && (n_gid.gid_guid != 0)) {
2515                 IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: Specified GID "
2516                     "(%llX:%llX) is NOT a Companion \n\t to current channel's "
2517                     "GID(%llX:%llX)", n_gid.gid_prefix, n_gid.gid_guid,
2518                     gid.gid_prefix, gid.gid_guid);
2519                 ret = IBT_INVALID_PARAM;
2520         } else if (n_gid.gid_guid != 0) {
2521                 /*
2522                  * We found some Comp GIDs and n_gid is specified. Validate
2523                  * whether the 'n_gid' specified is indeed the companion port
2524                  * GID of 'gid'.
2525                  */
2526                 for (i = 0; i < *num; i++) {
2527                         if ((n_gid.gid_prefix == gid_p[i]->gid_prefix) &&
2528                             (n_gid.gid_guid == gid_p[i]->gid_guid)) {
2529                                 IBTF_DPRINTF_L3(cmlog, "ibcm_get_comp_pgids: "
2530                                     "Matching Found!. Done.");
2531                                 return (IBT_SUCCESS);
2532                         }
2533                 }
2534                 IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: GID (%llX:%llX)\n"
2535                     "\t and (%llX:%llX) are NOT Companion Port GIDS",
2536                     n_gid.gid_prefix, n_gid.gid_guid, gid.gid_prefix,
2537                     gid.gid_guid);
2538                 ret = IBT_INVALID_PARAM;
2539         } else {
2540                 ret = IBT_SUCCESS;
2541         }
2542 
2543         IBTF_DPRINTF_L3(cmlog, "ibcm_get_comp_pgids: done. Status = %d", ret);
2544         return (ret);
2545 }
2546 
2547 /*
2548  * Function:
2549  *      ibt_get_alt_path
2550  * Input:
2551  *      rc_chan         An RC channel handle returned in a previous call
2552  *                      ibt_alloc_rc_channel(9F), specifies the channel to open.
2553  *      flags           Path flags.
2554  *      attrp           A pointer to an ibt_alt_path_attr_t(9S) structure that
2555  *                      specifies required attributes of the selected path(s).
2556  * Output:
2557  *      api_p           An ibt_alt_path_info_t(9S) struct filled in as output
2558  *                      parameters.
2559  * Returns:
2560  *      IBT_SUCCESS on Success else appropriate error.
2561  * Description:
2562  *      Finds the best alternate path to a specified channel (as determined by
2563  *      the IBTL) that satisfies the requirements specified in an
2564  *      ibt_alt_path_attr_t struct.  The specified channel must have been
2565  *      previously opened successfully using ibt_open_rc_channel.
2566  *      This function also ensures that the service being accessed by the
2567  *      channel is available at the selected alternate port.
2568  *
2569  *      Note: The apa_dgid must be on the same destination channel adapter,
2570  *      if specified.
2571  *      This routine can not be called from interrupt context.
2572  */
2573 ibt_status_t
2574 ibt_get_alt_path(ibt_channel_hdl_t rc_chan, ibt_path_flags_t flags,
2575     ibt_alt_path_attr_t *attrp, ibt_alt_path_info_t *api_p)
2576 {
2577         sa_multipath_record_t   *mpr_req;
2578         sa_path_record_t        *pr_resp;
2579         ibmf_saa_access_args_t  access_args;
2580         ibt_qp_query_attr_t     qp_attr;
2581         ibtl_cm_hca_port_t      c_hp, n_hp;
2582         ibcm_hca_info_t         *hcap;
2583         void                    *results_p;
2584         uint64_t                c_mask = 0;
2585         ib_gid_t                *gid_ptr = NULL;
2586         ib_gid_t                *sgids_p = NULL,  *dgids_p = NULL;
2587         ib_gid_t                cur_dgid, cur_sgid;
2588         ib_gid_t                new_dgid, new_sgid;
2589         ibmf_saa_handle_t       saa_handle;
2590         size_t                  length;
2591         int                     i, j, template_len, rec_found;
2592         uint_t                  snum = 0, dnum = 0, num_rec;
2593         ibt_status_t            retval;
2594         ib_mtu_t                prim_mtu;
2595 
2596         IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path(%p, %x, %p, %p)",
2597             rc_chan, flags, attrp, api_p);
2598 
2599         /* validate channel */
2600         if (IBCM_INVALID_CHANNEL(rc_chan)) {
2601                 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: invalid channel");
2602                 return (IBT_CHAN_HDL_INVALID);
2603         }
2604 
2605         if (api_p == NULL) {
2606                 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: invalid attribute: "
2607                     " AltPathInfo can't be NULL");
2608                 return (IBT_INVALID_PARAM);
2609         }
2610 
2611         retval = ibt_query_qp(rc_chan, &qp_attr);
2612         if (retval != IBT_SUCCESS) {
2613                 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: ibt_query_qp(%p) "
2614                     "failed %d", rc_chan, retval);
2615                 return (retval);
2616         }
2617 
2618         if (qp_attr.qp_info.qp_trans != IBT_RC_SRV) {
2619                 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2620                     "Invalid Channel type: Applicable only to RC Channel");
2621                 return (IBT_CHAN_SRV_TYPE_INVALID);
2622         }
2623 
2624         cur_dgid =
2625             qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dgid;
2626         cur_sgid =
2627             qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_sgid;
2628         prim_mtu = qp_attr.qp_info.qp_transport.rc.rc_path_mtu;
2629 
2630         /* If optional attributes are specified, validate them. */
2631         if (attrp) {
2632                 new_dgid = attrp->apa_dgid;
2633                 new_sgid = attrp->apa_sgid;
2634         } else {
2635                 new_dgid.gid_prefix = 0;
2636                 new_dgid.gid_guid = 0;
2637                 new_sgid.gid_prefix = 0;
2638                 new_sgid.gid_guid = 0;
2639         }
2640 
2641         if ((new_dgid.gid_prefix != 0) && (new_sgid.gid_prefix != 0) &&
2642             (new_dgid.gid_prefix != new_sgid.gid_prefix)) {
2643                 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: Specified SGID's "
2644                     "SNprefix (%llX) doesn't match with \n specified DGID's "
2645                     "SNprefix: %llX", new_sgid.gid_prefix, new_dgid.gid_prefix);
2646                 return (IBT_INVALID_PARAM);
2647         }
2648 
2649         /* For the specified SGID, get HCA information. */
2650         retval = ibtl_cm_get_hca_port(cur_sgid, 0, &c_hp);
2651         if (retval != IBT_SUCCESS) {
2652                 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2653                     "Get HCA Port Failed: %d", retval);
2654                 return (retval);
2655         }
2656 
2657         hcap = ibcm_find_hca_entry(c_hp.hp_hca_guid);
2658         if (hcap == NULL) {
2659                 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: NO HCA found");
2660                 return (IBT_HCA_BUSY_DETACHING);
2661         }
2662 
2663         /* Validate whether this HCA support APM */
2664         if (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG)) {
2665                 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2666                     "HCA (%llX) - APM NOT SUPPORTED ", c_hp.hp_hca_guid);
2667                 retval = IBT_APM_NOT_SUPPORTED;
2668                 goto get_alt_path_done;
2669         }
2670 
2671         /* Get Companion Port GID of the current Channel's SGID */
2672         if ((new_sgid.gid_guid == 0) || ((new_sgid.gid_guid != 0) &&
2673             (new_sgid.gid_guid != cur_sgid.gid_guid))) {
2674                 IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: SRC: "
2675                     "Get Companion PortGids for - %llX:%llX",
2676                     cur_sgid.gid_prefix, cur_sgid.gid_guid);
2677 
2678                 retval = ibcm_get_comp_pgids(cur_sgid, new_sgid,
2679                     c_hp.hp_hca_guid, &sgids_p, &snum);
2680                 if (retval != IBT_SUCCESS)
2681                         goto get_alt_path_done;
2682         }
2683 
2684         /* Get Companion Port GID of the current Channel's DGID */
2685         if ((new_dgid.gid_guid == 0) || ((new_dgid.gid_guid != 0) &&
2686             (new_dgid.gid_guid != cur_dgid.gid_guid))) {
2687 
2688                 IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: DEST: "
2689                     "Get Companion PortGids for - %llX:%llX",
2690                     cur_dgid.gid_prefix, cur_dgid.gid_guid);
2691 
2692                 retval = ibcm_get_comp_pgids(cur_dgid, new_dgid, 0, &dgids_p,
2693                     &dnum);
2694                 if (retval != IBT_SUCCESS)
2695                         goto get_alt_path_done;
2696         }
2697 
2698         if ((new_dgid.gid_guid == 0) || (new_sgid.gid_guid == 0)) {
2699                 if (new_sgid.gid_guid == 0) {
2700                         for (i = 0; i < snum; i++) {
2701                                 if (new_dgid.gid_guid == 0) {
2702                                         for (j = 0; j < dnum; j++) {
2703                                                 if (sgids_p[i].gid_prefix ==
2704                                                     dgids_p[j].gid_prefix) {
2705                                                         new_dgid = dgids_p[j];
2706                                                         new_sgid = sgids_p[i];
2707 
2708                                                         goto get_alt_proceed;
2709                                                 }
2710                                         }
2711                                         /*  Current DGID */
2712                                         if (sgids_p[i].gid_prefix ==
2713                                             cur_dgid.gid_prefix) {
2714                                                 new_sgid = sgids_p[i];
2715                                                 goto get_alt_proceed;
2716                                         }
2717                                 } else {
2718                                         if (sgids_p[i].gid_prefix ==
2719                                             new_dgid.gid_prefix) {
2720                                                 new_sgid = sgids_p[i];
2721                                                 goto get_alt_proceed;
2722                                         }
2723                                 }
2724                         }
2725                         /* Current SGID */
2726                         if (new_dgid.gid_guid == 0) {
2727                                 for (j = 0; j < dnum; j++) {
2728                                         if (cur_sgid.gid_prefix ==
2729                                             dgids_p[j].gid_prefix) {
2730                                                 new_dgid = dgids_p[j];
2731 
2732                                                 goto get_alt_proceed;
2733                                         }
2734                                 }
2735                         }
2736                 } else if (new_dgid.gid_guid == 0) {
2737                         for (i = 0; i < dnum; i++) {
2738                                 if (dgids_p[i].gid_prefix ==
2739                                     new_sgid.gid_prefix) {
2740                                         new_dgid = dgids_p[i];
2741                                         goto get_alt_proceed;
2742                                 }
2743                         }
2744                         /* Current DGID */
2745                         if (cur_dgid.gid_prefix == new_sgid.gid_prefix) {
2746                                 goto get_alt_proceed;
2747                         }
2748                 }
2749                 /*
2750                  * hmm... No Companion Ports available.
2751                  * so we will be using current or specified attributes only.
2752                  */
2753         }
2754 
2755 get_alt_proceed:
2756 
2757         if (new_sgid.gid_guid != 0) {
2758                 retval = ibtl_cm_get_hca_port(new_sgid, 0, &n_hp);
2759                 if (retval != IBT_SUCCESS) {
2760                         IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2761                             "Get HCA Port Failed: %d", retval);
2762                         goto get_alt_path_done;
2763                 }
2764         }
2765 
2766         /* Calculate the size for multi-path records template */
2767         template_len = (2 * sizeof (ib_gid_t)) + sizeof (sa_multipath_record_t);
2768 
2769         mpr_req = kmem_zalloc(template_len, KM_SLEEP);
2770 
2771         ASSERT(mpr_req != NULL);
2772 
2773         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
2774 
2775         gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
2776             sizeof (sa_multipath_record_t));
2777 
2778         /* SGID */
2779         if (new_sgid.gid_guid == 0)
2780                 *gid_ptr = cur_sgid;
2781         else
2782                 *gid_ptr = new_sgid;
2783 
2784         IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Get Path Between "
2785             " SGID : %llX:%llX", gid_ptr->gid_prefix, gid_ptr->gid_guid);
2786 
2787         gid_ptr++;
2788 
2789         /* DGID */
2790         if (new_dgid.gid_guid == 0)
2791                 *gid_ptr = cur_dgid;
2792         else
2793                 *gid_ptr = new_dgid;
2794 
2795         IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path:\t\t    DGID : %llX:%llX",
2796             gid_ptr->gid_prefix, gid_ptr->gid_guid);
2797 
2798         mpr_req->SGIDCount = 1;
2799         c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
2800 
2801         mpr_req->DGIDCount = 1;
2802         c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
2803 
2804         /* Is Flow Label Specified. */
2805         if (attrp) {
2806                 if (attrp->apa_flow) {
2807                         mpr_req->FlowLabel = attrp->apa_flow;
2808                         c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
2809                 }
2810 
2811                 /* Is HopLimit Specified. */
2812                 if (flags & IBT_PATH_HOP) {
2813                         mpr_req->HopLimit = attrp->apa_hop;
2814                         c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
2815                 }
2816 
2817                 /* Is TClass Specified. */
2818                 if (attrp->apa_tclass) {
2819                         mpr_req->TClass = attrp->apa_tclass;
2820                         c_mask |= SA_MPR_COMPMASK_TCLASS;
2821                 }
2822 
2823                 /* Is SL specified. */
2824                 if (attrp->apa_sl) {
2825                         mpr_req->SL = attrp->apa_sl;
2826                         c_mask |= SA_MPR_COMPMASK_SL;
2827                 }
2828 
2829                 if (flags & IBT_PATH_PERF) {
2830                         mpr_req->PacketLifeTimeSelector = IBT_BEST;
2831                         mpr_req->RateSelector = IBT_BEST;
2832 
2833                         c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
2834                             SA_MPR_COMPMASK_RATESELECTOR;
2835                 } else {
2836                         if (attrp->apa_pkt_lt.p_selector == IBT_BEST) {
2837                                 mpr_req->PacketLifeTimeSelector = IBT_BEST;
2838                                 c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
2839                         }
2840 
2841                         if (attrp->apa_srate.r_selector == IBT_BEST) {
2842                                 mpr_req->RateSelector = IBT_BEST;
2843                                 c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
2844                         }
2845                 }
2846 
2847                 /*
2848                  * Honor individual selection of these attributes,
2849                  * even if IBT_PATH_PERF is set.
2850                  */
2851                 /* Check out whether Packet Life Time is specified. */
2852                 if (attrp->apa_pkt_lt.p_pkt_lt) {
2853                         mpr_req->PacketLifeTime =
2854                             ibt_usec2ib(attrp->apa_pkt_lt.p_pkt_lt);
2855                         mpr_req->PacketLifeTimeSelector =
2856                             attrp->apa_pkt_lt.p_selector;
2857 
2858                         c_mask |= SA_MPR_COMPMASK_PKTLT |
2859                             SA_MPR_COMPMASK_PKTLTSELECTOR;
2860                 }
2861 
2862                 /* Is SRATE specified. */
2863                 if (attrp->apa_srate.r_srate) {
2864                         mpr_req->Rate = attrp->apa_srate.r_srate;
2865                         mpr_req->RateSelector = attrp->apa_srate.r_selector;
2866 
2867                         c_mask |= SA_MPR_COMPMASK_RATE |
2868                             SA_MPR_COMPMASK_RATESELECTOR;
2869                 }
2870         }
2871 
2872         /* Alt PathMTU can be GT or EQU to current channel's Pri PathMTU */
2873 
2874         /* P_Key must be same as that of primary path */
2875         retval = ibt_index2pkey_byguid(c_hp.hp_hca_guid, c_hp.hp_port,
2876             qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix,
2877             &mpr_req->P_Key);
2878         if (retval != IBT_SUCCESS) {
2879                 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: Idx2Pkey Failed: %d",
2880                     retval);
2881                 goto get_alt_path_done;
2882         }
2883         c_mask |= SA_MPR_COMPMASK_PKEY;
2884 
2885         mpr_req->Reversible = 1;     /* We always get REVERSIBLE paths. */
2886         mpr_req->IndependenceSelector = 1;
2887         c_mask |= SA_MPR_COMPMASK_REVERSIBLE | SA_MPR_COMPMASK_INDEPSEL;
2888 
2889         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
2890 
2891         IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: CMask: 0x%llX", c_mask);
2892 
2893         /* NOTE: We will **NOT** specify how many records we want. */
2894 
2895         IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Primary: MTU %d, PKey[%d]="
2896             "0x%X\n\tSGID = %llX:%llX, DGID = %llX:%llX", prim_mtu,
2897             qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix, mpr_req->P_Key,
2898             cur_sgid.gid_prefix, cur_sgid.gid_guid, cur_dgid.gid_prefix,
2899             cur_dgid.gid_guid);
2900 
2901         /* Get SA Access Handle. */
2902         if (new_sgid.gid_guid != 0)
2903                 saa_handle = ibcm_get_saa_handle(hcap, n_hp.hp_port);
2904         else
2905                 saa_handle = ibcm_get_saa_handle(hcap, c_hp.hp_port);
2906         if (saa_handle == NULL) {
2907                 retval = IBT_HCA_PORT_NOT_ACTIVE;
2908                 goto get_alt_path_done;
2909         }
2910 
2911         /* Contact SA Access to retrieve Path Records. */
2912         access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
2913         access_args.sq_access_type = IBMF_SAA_RETRIEVE;
2914         access_args.sq_component_mask = c_mask;
2915         access_args.sq_template = mpr_req;
2916         access_args.sq_template_length = sizeof (sa_multipath_record_t);
2917         access_args.sq_callback = NULL;
2918         access_args.sq_callback_arg = NULL;
2919 
2920         retval = ibcm_contact_sa_access(saa_handle, &access_args, &length,
2921             &results_p);
2922         if (retval != IBT_SUCCESS) {
2923                 goto get_alt_path_done;
2924         }
2925 
2926         num_rec = length / sizeof (sa_path_record_t);
2927 
2928         kmem_free(mpr_req, template_len);
2929 
2930         IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Found %d Paths", num_rec);
2931 
2932         rec_found = 0;
2933         if ((results_p != NULL) && (num_rec > 0)) {
2934                 /* Update the PathInfo with the response Path Records */
2935                 pr_resp = (sa_path_record_t *)results_p;
2936                 for (i = 0; i < num_rec; i++, pr_resp++) {
2937                         if (prim_mtu > pr_resp->Mtu) {
2938                                 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2939                                     "Alt PathMTU(%d) must be GT or EQU to Pri "
2940                                     "PathMTU(%d). Ignore this rec",
2941                                     pr_resp->Mtu, prim_mtu);
2942                                 continue;
2943                         }
2944 
2945                         if ((new_sgid.gid_guid == 0) &&
2946                             (new_dgid.gid_guid == 0)) {
2947                                 /* Reject PathRec if it same as Primary Path. */
2948                                 if (ibcm_compare_paths(pr_resp,
2949                                     &qp_attr.qp_info.qp_transport.rc.rc_path,
2950                                     &c_hp)) {
2951                                         IBTF_DPRINTF_L3(cmlog,
2952                                             "ibt_get_alt_path: PathRec obtained"
2953                                             " is similar to Prim Path, ignore "
2954                                             "this record");
2955                                         continue;
2956                                 }
2957                         }
2958 
2959                         if (new_sgid.gid_guid == 0) {
2960                                 retval = ibcm_update_cep_info(pr_resp, NULL,
2961                                     &c_hp, &api_p->ap_alt_cep_path);
2962                         } else {
2963                                 retval = ibcm_update_cep_info(pr_resp, NULL,
2964                                     &n_hp, &api_p->ap_alt_cep_path);
2965                         }
2966                         if (retval != IBT_SUCCESS)
2967                                 continue;
2968 
2969                         /* Update some leftovers */
2970                         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*api_p))
2971 
2972                         api_p->ap_alt_pkt_lt = pr_resp->PacketLifeTime;
2973 
2974                         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*api_p))
2975 
2976                         rec_found = 1;
2977                         break;
2978                 }
2979                 kmem_free(results_p, length);
2980         }
2981 
2982         if (rec_found == 0) {
2983                 IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Alternate Path cannot"
2984                     " be established");
2985                 retval = IBT_PATH_RECORDS_NOT_FOUND;
2986         } else
2987                 retval = IBT_SUCCESS;
2988 
2989 get_alt_path_done:
2990         if ((snum) && (sgids_p))
2991                 kmem_free(sgids_p, snum * sizeof (ib_gid_t));
2992 
2993         if ((dnum) && (dgids_p))
2994                 kmem_free(dgids_p, dnum * sizeof (ib_gid_t));
2995 
2996         ibcm_dec_hca_acc_cnt(hcap);
2997 
2998         IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Done (status %d).", retval);
2999 
3000         return (retval);
3001 }
3002 
3003 
3004 
3005 /*
3006  * IP Path API
3007  */
3008 
3009 typedef struct ibcm_ip_path_tqargs_s {
3010         ibt_ip_path_attr_t      attr;
3011         ibt_path_info_t         *paths;
3012         ibt_path_ip_src_t       *src_ip_p;
3013         uint8_t                 *num_paths_p;
3014         ibt_ip_path_handler_t   func;
3015         void                    *arg;
3016         ibt_path_flags_t        flags;
3017         ibt_clnt_hdl_t          ibt_hdl;
3018         kmutex_t                ip_lock;
3019         kcondvar_t              ip_cv;
3020         boolean_t               ip_done;
3021         ibt_status_t            retval;
3022         uint_t                  len;
3023 } ibcm_ip_path_tqargs_t;
3024 
3025 /* Holds destination information needed to fill in ibt_path_info_t. */
3026 typedef struct ibcm_ip_dinfo_s {
3027         uint8_t         num_dest;
3028         ib_gid_t        d_gid[1];
3029 } ibcm_ip_dinfo_t;
3030 
3031 _NOTE(SCHEME_PROTECTS_DATA("Temporary path storage", ibcm_ip_dinfo_s))
3032 
3033 /* Prototype Declarations. */
3034 static void ibcm_process_get_ip_paths(void *tq_arg);
3035 static ibt_status_t ibcm_get_ip_spr(ibcm_ip_path_tqargs_t *,
3036     ibtl_cm_port_list_t *, ibcm_ip_dinfo_t *, uint8_t *, ibt_path_info_t *);
3037 static ibt_status_t ibcm_get_ip_mpr(ibcm_ip_path_tqargs_t *,
3038     ibtl_cm_port_list_t *, ibcm_ip_dinfo_t *dinfo,
3039     uint8_t *, ibt_path_info_t *);
3040 
3041 /*
3042  * Perform SA Access to retrieve Path Records.
3043  */
3044 static ibt_status_t
3045 ibcm_saa_ip_pr(ibcm_ip_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
3046     ibcm_ip_dinfo_t *dinfo, uint8_t *max_count)
3047 {
3048         uint8_t         num_path = *max_count;
3049         uint8_t         rec_found = 0;
3050         ibt_status_t    retval = IBT_SUCCESS;
3051         uint8_t         i, j;
3052 
3053         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_ip_pr(%p, %p, %p, 0x%X, %d)",
3054             p_arg, sl, dinfo, p_arg->flags, *max_count);
3055 
3056         if ((dinfo->num_dest == 0) || (num_path == 0) || (sl == NULL)) {
3057                 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_ip_pr: Invalid Counters");
3058                 return (IBT_INVALID_PARAM);
3059         }
3060 
3061         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_ip_pr: MultiSM=%X, #SRC=%d, "
3062             "#Dest=%d, #Path %d", sl->p_multi, sl->p_count, dinfo->num_dest,
3063             num_path);
3064 
3065         if ((sl->p_multi != IBTL_CM_SIMPLE_SETUP) ||
3066             ((dinfo->num_dest == 1) && (sl->p_count == 1))) {
3067                 /*
3068                  * Use SinglePathRec if we are dealing w/ MultiSM or
3069                  * request is for one SGID to one DGID.
3070                  */
3071                 retval = ibcm_get_ip_spr(p_arg, sl, dinfo,
3072                     &num_path, &p_arg->paths[rec_found]);
3073         } else {
3074                 /* MultiPathRec will be used for other queries. */
3075                 retval = ibcm_get_ip_mpr(p_arg, sl, dinfo,
3076                     &num_path, &p_arg->paths[rec_found]);
3077         }
3078         if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA))
3079                 IBTF_DPRINTF_L2(cmlog, "ibcm_saa_ip_pr: "
3080                     "Failed to get PathRec: Status %d", retval);
3081         else
3082                 rec_found += num_path;
3083 
3084         if (rec_found == 0)  {
3085                 if (retval == IBT_SUCCESS)
3086                         retval = IBT_PATH_RECORDS_NOT_FOUND;
3087         } else if (rec_found != *max_count)
3088                 retval = IBT_INSUFF_DATA;
3089         else if (rec_found != 0)
3090                 retval = IBT_SUCCESS;
3091 
3092         if ((p_arg->src_ip_p != NULL) && (rec_found != 0)) {
3093                 for (i = 0; i < rec_found; i++) {
3094                         for (j = 0; j < sl->p_count; j++) {
3095                                 if (sl[j].p_sgid.gid_guid == p_arg->paths[i].
3096                                     pi_prim_cep_path.cep_adds_vect.
3097                                     av_sgid.gid_guid) {
3098                                         bcopy(&sl[j].p_src_ip,
3099                                             &p_arg->src_ip_p[i].ip_primary,
3100                                             sizeof (ibt_ip_addr_t));
3101                                 }
3102                                 /* Is Alt Path present */
3103                                 if (p_arg->paths[i].pi_alt_cep_path.
3104                                     cep_hca_port_num) {
3105                                         if (sl[j].p_sgid.gid_guid ==
3106                                             p_arg->paths[i].pi_alt_cep_path.
3107                                             cep_adds_vect.av_sgid.gid_guid) {
3108                                                 bcopy(&sl[j].p_src_ip,
3109                                                     &p_arg->src_ip_p[i].
3110                                                     ip_alternate,
3111                                                     sizeof (ibt_ip_addr_t));
3112                                         }
3113                                 }
3114                         }
3115                 }
3116         }
3117         IBTF_DPRINTF_L3(cmlog, "ibcm_saa_ip_pr: done. Status = %d, "
3118             "Found %d/%d Paths", retval, rec_found, *max_count);
3119 
3120         *max_count = rec_found; /* Update the return count. */
3121 
3122         return (retval);
3123 }
3124 
3125 static ibt_status_t
3126 ibcm_ip_update_pri(sa_path_record_t *pr_resp, ibtl_cm_port_list_t *sl,
3127     ibt_path_info_t *paths)
3128 {
3129         ibt_status_t    retval = IBT_SUCCESS;
3130         int             s;
3131 
3132         retval = ibcm_update_cep_info(pr_resp, sl, NULL,
3133             &paths->pi_prim_cep_path);
3134         if (retval != IBT_SUCCESS)
3135                 return (retval);
3136 
3137         /* Update some leftovers */
3138         paths->pi_prim_pkt_lt = pr_resp->PacketLifeTime;
3139         paths->pi_path_mtu = pr_resp->Mtu;
3140 
3141         for (s = 0; s < sl->p_count; s++) {
3142                 if (pr_resp->SGID.gid_guid == sl[s].p_sgid.gid_guid)
3143                         paths->pi_hca_guid = sl[s].p_hca_guid;
3144         }
3145 
3146         /* Set Alternate Path to invalid state. */
3147         paths->pi_alt_cep_path.cep_hca_port_num = 0;
3148         paths->pi_alt_cep_path.cep_adds_vect.av_dlid = 0;
3149 
3150         IBTF_DPRINTF_L5(cmlog, "ibcm_ip_update_pri: Path HCA GUID 0x%llX",
3151             paths->pi_hca_guid);
3152 
3153         return (retval);
3154 }
3155 
3156 
3157 static ibt_status_t
3158 ibcm_get_ip_spr(ibcm_ip_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
3159     ibcm_ip_dinfo_t *dinfo, uint8_t *num_path, ibt_path_info_t *paths)
3160 {
3161         sa_path_record_t        pathrec_req;
3162         sa_path_record_t        *pr_resp;
3163         ibmf_saa_access_args_t  access_args;
3164         uint64_t                c_mask = 0;
3165         void                    *results_p;
3166         uint8_t                 num_rec;
3167         size_t                  length;
3168         ibt_status_t            retval;
3169         int                     i, j, k;
3170         uint8_t                 found, p_fnd;
3171         ibt_ip_path_attr_t      *attrp = &p_arg->attr;
3172         ibmf_saa_handle_t       saa_handle;
3173 
3174         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr(%p, %p, %p, %d)",
3175             p_arg, sl, dinfo, *num_path);
3176 
3177         bzero(&pathrec_req, sizeof (sa_path_record_t));
3178 
3179         /* Is Flow Label Specified. */
3180         if (attrp->ipa_flow) {
3181                 pathrec_req.FlowLabel = attrp->ipa_flow;
3182                 c_mask |= SA_PR_COMPMASK_FLOWLABEL;
3183         }
3184 
3185         /* Is HopLimit Specified. */
3186         if (p_arg->flags & IBT_PATH_HOP) {
3187                 pathrec_req.HopLimit = attrp->ipa_hop;
3188                 c_mask |= SA_PR_COMPMASK_HOPLIMIT;
3189         }
3190 
3191         /* Is TClass Specified. */
3192         if (attrp->ipa_tclass) {
3193                 pathrec_req.TClass = attrp->ipa_tclass;
3194                 c_mask |= SA_PR_COMPMASK_TCLASS;
3195         }
3196 
3197         /* Is SL specified. */
3198         if (attrp->ipa_sl) {
3199                 pathrec_req.SL = attrp->ipa_sl;
3200                 c_mask |= SA_PR_COMPMASK_SL;
3201         }
3202 
3203         /* If IBT_PATH_PERF is set, then mark all selectors to BEST. */
3204         if (p_arg->flags & IBT_PATH_PERF) {
3205                 pathrec_req.PacketLifeTimeSelector = IBT_BEST;
3206                 pathrec_req.MtuSelector = IBT_BEST;
3207                 pathrec_req.RateSelector = IBT_BEST;
3208 
3209                 c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR |
3210                     SA_PR_COMPMASK_RATESELECTOR | SA_PR_COMPMASK_MTUSELECTOR;
3211         } else {
3212                 if (attrp->ipa_pkt_lt.p_selector == IBT_BEST) {
3213                         pathrec_req.PacketLifeTimeSelector = IBT_BEST;
3214                         c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR;
3215                 }
3216 
3217                 if (attrp->ipa_srate.r_selector == IBT_BEST) {
3218                         pathrec_req.RateSelector = IBT_BEST;
3219                         c_mask |= SA_PR_COMPMASK_RATESELECTOR;
3220                 }
3221 
3222                 if (attrp->ipa_mtu.r_selector == IBT_BEST) {
3223                         pathrec_req.MtuSelector = IBT_BEST;
3224                         c_mask |= SA_PR_COMPMASK_MTUSELECTOR;
3225                 }
3226         }
3227 
3228         /*
3229          * Honor individual selection of these attributes,
3230          * even if IBT_PATH_PERF is set.
3231          */
3232         /* Check out whether Packet Life Time is specified. */
3233         if (attrp->ipa_pkt_lt.p_pkt_lt) {
3234                 pathrec_req.PacketLifeTime =
3235                     ibt_usec2ib(attrp->ipa_pkt_lt.p_pkt_lt);
3236                 pathrec_req.PacketLifeTimeSelector =
3237                     attrp->ipa_pkt_lt.p_selector;
3238 
3239                 c_mask |= SA_PR_COMPMASK_PKTLT | SA_PR_COMPMASK_PKTLTSELECTOR;
3240         }
3241 
3242         /* Is SRATE specified. */
3243         if (attrp->ipa_srate.r_srate) {
3244                 pathrec_req.Rate = attrp->ipa_srate.r_srate;
3245                 pathrec_req.RateSelector = attrp->ipa_srate.r_selector;
3246 
3247                 c_mask |= SA_PR_COMPMASK_RATE | SA_PR_COMPMASK_RATESELECTOR;
3248         }
3249 
3250         /* Is MTU specified. */
3251         if (attrp->ipa_mtu.r_mtu) {
3252                 pathrec_req.Mtu = attrp->ipa_mtu.r_mtu;
3253                 pathrec_req.MtuSelector = attrp->ipa_mtu.r_selector;
3254 
3255                 c_mask |= SA_PR_COMPMASK_MTU | SA_PR_COMPMASK_MTUSELECTOR;
3256         }
3257 
3258         /* We always get REVERSIBLE paths. */
3259         pathrec_req.Reversible = 1;
3260         c_mask |= SA_PR_COMPMASK_REVERSIBLE;
3261 
3262         pathrec_req.NumbPath = *num_path;
3263         c_mask |= SA_PR_COMPMASK_NUMBPATH;
3264 
3265         p_fnd = found = 0;
3266 
3267         for (i = 0; i < sl->p_count; i++) {
3268                 /* SGID */
3269                 pathrec_req.SGID = sl[i].p_sgid;
3270                 c_mask |= SA_PR_COMPMASK_SGID;
3271                 saa_handle = sl[i].p_saa_hdl;
3272 
3273                 for (k = 0; k < dinfo->num_dest; k++) {
3274                         if (pathrec_req.SGID.gid_prefix !=
3275                             dinfo->d_gid[k].gid_prefix) {
3276                                 IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: "
3277                                     "SGID_pfx=%llX DGID_pfx=%llX doesn't match",
3278                                     pathrec_req.SGID.gid_prefix,
3279                                     dinfo->d_gid[k].gid_prefix);
3280                                 continue;
3281                         }
3282 
3283                         pathrec_req.DGID = dinfo->d_gid[k];
3284                         c_mask |= SA_PR_COMPMASK_DGID;
3285 
3286                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: "
3287                             "Get %d Path(s) between\n SGID %llX:%llX "
3288                             "DGID %llX:%llX", pathrec_req.NumbPath,
3289                             pathrec_req.SGID.gid_prefix,
3290                             pathrec_req.SGID.gid_guid,
3291                             pathrec_req.DGID.gid_prefix,
3292                             pathrec_req.DGID.gid_guid);
3293 
3294                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: CMask=0x%llX, "
3295                             "PKey=0x%X", c_mask, pathrec_req.P_Key);
3296 
3297                         /* Contact SA Access to retrieve Path Records. */
3298                         access_args.sq_attr_id = SA_PATHRECORD_ATTRID;
3299                         access_args.sq_template = &pathrec_req;
3300                         access_args.sq_access_type = IBMF_SAA_RETRIEVE;
3301                         access_args.sq_template_length =
3302                             sizeof (sa_path_record_t);
3303                         access_args.sq_component_mask = c_mask;
3304                         access_args.sq_callback = NULL;
3305                         access_args.sq_callback_arg = NULL;
3306 
3307                         retval = ibcm_contact_sa_access(saa_handle,
3308                             &access_args, &length, &results_p);
3309                         if (retval != IBT_SUCCESS) {
3310                                 *num_path = 0;
3311                                 return (retval);
3312                         }
3313 
3314                         num_rec = length / sizeof (sa_path_record_t);
3315 
3316                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: "
3317                             "FOUND %d/%d path requested", num_rec, *num_path);
3318 
3319                         if ((results_p == NULL) || (num_rec == 0))
3320                                 continue;
3321 
3322                         /* Update the PathInfo from the response. */
3323                         pr_resp = (sa_path_record_t *)results_p;
3324                         for (j = 0; j < num_rec; j++, pr_resp++) {
3325                                 if ((p_fnd != 0) &&
3326                                     (p_arg->flags & IBT_PATH_APM)) {
3327                                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr"
3328                                             ": Fill Alternate Path");
3329                                         retval = ibcm_update_cep_info(pr_resp,
3330                                             sl, NULL,
3331                                             &paths[found - 1].pi_alt_cep_path);
3332                                         if (retval != IBT_SUCCESS)
3333                                                 continue;
3334 
3335                                         /* Update some leftovers */
3336                                         paths[found - 1].pi_alt_pkt_lt =
3337                                             pr_resp->PacketLifeTime;
3338                                         p_fnd = 0;
3339                                 } else {
3340                                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr"
3341                                             ": Fill Primary Path");
3342 
3343                                         if (found == *num_path)
3344                                                 break;
3345 
3346                                         retval = ibcm_ip_update_pri(pr_resp, sl,
3347                                             &paths[found]);
3348                                         if (retval != IBT_SUCCESS)
3349                                                 continue;
3350                                         p_fnd = 1;
3351                                         found++;
3352                                 }
3353 
3354                         }
3355                         /* Deallocate the memory for results_p. */
3356                         kmem_free(results_p, length);
3357                 }
3358         }
3359 
3360         if (found == 0)
3361                 retval = IBT_PATH_RECORDS_NOT_FOUND;
3362         else if (found != *num_path)
3363                 retval = IBT_INSUFF_DATA;
3364         else
3365                 retval = IBT_SUCCESS;
3366 
3367         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: done. Status %d, "
3368             "Found %d/%d Paths", retval, found, *num_path);
3369 
3370         *num_path = found;
3371 
3372         return (retval);
3373 }
3374 
3375 
3376 static ibt_status_t
3377 ibcm_get_ip_mpr(ibcm_ip_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
3378     ibcm_ip_dinfo_t *dinfo, uint8_t *num_path, ibt_path_info_t *paths)
3379 {
3380         sa_multipath_record_t   *mpr_req;
3381         sa_path_record_t        *pr_resp;
3382         ibmf_saa_access_args_t  access_args;
3383         void                    *results_p;
3384         uint64_t                c_mask = 0;
3385         ib_gid_t                *gid_ptr, *gid_s_ptr;
3386         size_t                  length;
3387         int                     template_len;
3388         uint8_t                 found, num_rec;
3389         int                     i;
3390         ibt_status_t            retval;
3391         uint8_t                 sgid_cnt, dgid_cnt;
3392         ibt_ip_path_attr_t      *attrp = &p_arg->attr;
3393 
3394         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr(%p, %p, %p, %d)",
3395             attrp, sl, dinfo, *num_path);
3396 
3397         dgid_cnt = dinfo->num_dest;
3398         sgid_cnt = sl->p_count;
3399 
3400         if ((sgid_cnt == 0) || (dgid_cnt == 0)) {
3401                 IBTF_DPRINTF_L2(cmlog, "ibcm_get_ip_mpr: sgid_cnt(%d) or"
3402                     " dgid_cnt(%d) is zero", sgid_cnt, dgid_cnt);
3403                 return (IBT_INVALID_PARAM);
3404         }
3405 
3406         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: Get %d records between "
3407             "%d Src(s) <=> %d Dest(s)", *num_path, sgid_cnt, dgid_cnt);
3408 
3409         /*
3410          * Calculate the size for multi-path records template, which includes
3411          * constant portion of the multipath record, plus variable size for
3412          * SGID (sgid_cnt) and DGID (dgid_cnt).
3413          */
3414         template_len = ((dgid_cnt + sgid_cnt) * sizeof (ib_gid_t)) +
3415             sizeof (sa_multipath_record_t);
3416 
3417         mpr_req = kmem_zalloc(template_len, KM_SLEEP);
3418 
3419         ASSERT(mpr_req != NULL);
3420 
3421         gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
3422             sizeof (sa_multipath_record_t));
3423 
3424         /* Get the starting pointer where GIDs are stored. */
3425         gid_s_ptr = gid_ptr;
3426 
3427         /* SGID */
3428         for (i = 0; i < sgid_cnt; i++) {
3429                 *gid_ptr = sl[i].p_sgid;
3430 
3431                 IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: SGID[%d] = %llX:%llX",
3432                     i, gid_ptr->gid_prefix, gid_ptr->gid_guid);
3433 
3434                 gid_ptr++;
3435         }
3436 
3437         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
3438 
3439         mpr_req->SGIDCount = sgid_cnt;
3440         c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
3441 
3442         /* DGIDs */
3443         for (i = 0; i < dgid_cnt; i++) {
3444                 *gid_ptr = dinfo->d_gid[i];
3445 
3446                 IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: DGID[%d] = "
3447                     "%llX:%llX", i, gid_ptr->gid_prefix, gid_ptr->gid_guid);
3448                 gid_ptr++;
3449         }
3450 
3451         mpr_req->DGIDCount = dgid_cnt;
3452         c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
3453 
3454         /* Is Flow Label Specified. */
3455         if (attrp->ipa_flow) {
3456                 mpr_req->FlowLabel = attrp->ipa_flow;
3457                 c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
3458         }
3459 
3460         /* Is HopLimit Specified. */
3461         if (p_arg->flags & IBT_PATH_HOP) {
3462                 mpr_req->HopLimit = attrp->ipa_hop;
3463                 c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
3464         }
3465 
3466         /* Is TClass Specified. */
3467         if (attrp->ipa_tclass) {
3468                 mpr_req->TClass = attrp->ipa_tclass;
3469                 c_mask |= SA_MPR_COMPMASK_TCLASS;
3470         }
3471 
3472         /* Is SL specified. */
3473         if (attrp->ipa_sl) {
3474                 mpr_req->SL = attrp->ipa_sl;
3475                 c_mask |= SA_MPR_COMPMASK_SL;
3476         }
3477 
3478         if (p_arg->flags & IBT_PATH_PERF) {
3479                 mpr_req->PacketLifeTimeSelector = IBT_BEST;
3480                 mpr_req->RateSelector = IBT_BEST;
3481                 mpr_req->MtuSelector = IBT_BEST;
3482 
3483                 c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
3484                     SA_MPR_COMPMASK_RATESELECTOR | SA_MPR_COMPMASK_MTUSELECTOR;
3485         } else {
3486                 if (attrp->ipa_pkt_lt.p_selector == IBT_BEST) {
3487                         mpr_req->PacketLifeTimeSelector = IBT_BEST;
3488                         c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
3489                 }
3490 
3491                 if (attrp->ipa_srate.r_selector == IBT_BEST) {
3492                         mpr_req->RateSelector = IBT_BEST;
3493                         c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
3494                 }
3495 
3496                 if (attrp->ipa_mtu.r_selector == IBT_BEST) {
3497                         mpr_req->MtuSelector = IBT_BEST;
3498                         c_mask |= SA_MPR_COMPMASK_MTUSELECTOR;
3499                 }
3500         }
3501 
3502         /*
3503          * Honor individual selection of these attributes,
3504          * even if IBT_PATH_PERF is set.
3505          */
3506         /* Check out whether Packet Life Time is specified. */
3507         if (attrp->ipa_pkt_lt.p_pkt_lt) {
3508                 mpr_req->PacketLifeTime =
3509                     ibt_usec2ib(attrp->ipa_pkt_lt.p_pkt_lt);
3510                 mpr_req->PacketLifeTimeSelector =
3511                     attrp->ipa_pkt_lt.p_selector;
3512 
3513                 c_mask |= SA_MPR_COMPMASK_PKTLT |
3514                     SA_MPR_COMPMASK_PKTLTSELECTOR;
3515         }
3516 
3517         /* Is SRATE specified. */
3518         if (attrp->ipa_srate.r_srate) {
3519                 mpr_req->Rate = attrp->ipa_srate.r_srate;
3520                 mpr_req->RateSelector = attrp->ipa_srate.r_selector;
3521 
3522                 c_mask |= SA_MPR_COMPMASK_RATE |
3523                     SA_MPR_COMPMASK_RATESELECTOR;
3524         }
3525 
3526         /* Is MTU specified. */
3527         if (attrp->ipa_mtu.r_mtu) {
3528                 mpr_req->Mtu = attrp->ipa_mtu.r_mtu;
3529                 mpr_req->MtuSelector = attrp->ipa_mtu.r_selector;
3530 
3531                 c_mask |= SA_MPR_COMPMASK_MTU |
3532                     SA_MPR_COMPMASK_MTUSELECTOR;
3533         }
3534 
3535         /* We always get REVERSIBLE paths. */
3536         mpr_req->Reversible = 1;
3537         c_mask |= SA_MPR_COMPMASK_REVERSIBLE;
3538 
3539         if (p_arg->flags & IBT_PATH_AVAIL) {
3540                 mpr_req->IndependenceSelector = 1;
3541                 c_mask |= SA_MPR_COMPMASK_INDEPSEL;
3542         }
3543 
3544         /* we will not specify how many records we want. */
3545 
3546         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
3547 
3548         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: CMask: %llX Pkey: %X",
3549             c_mask, mpr_req->P_Key);
3550 
3551         /* Contact SA Access to retrieve Path Records. */
3552         access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
3553         access_args.sq_access_type = IBMF_SAA_RETRIEVE;
3554         access_args.sq_component_mask = c_mask;
3555         access_args.sq_template = mpr_req;
3556         access_args.sq_template_length = sizeof (sa_multipath_record_t);
3557         access_args.sq_callback = NULL;
3558         access_args.sq_callback_arg = NULL;
3559 
3560         retval = ibcm_contact_sa_access(sl->p_saa_hdl, &access_args, &length,
3561             &results_p);
3562         if (retval != IBT_SUCCESS) {
3563                 *num_path = 0;  /* Update the return count. */
3564                 kmem_free(mpr_req, template_len);
3565                 return (retval);
3566         }
3567 
3568         num_rec = length / sizeof (sa_path_record_t);
3569 
3570         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: Found %d Paths", num_rec);
3571 
3572         found = 0;
3573         if ((results_p != NULL) && (num_rec > 0)) {
3574                 /* Update the PathInfo with the response Path Records */
3575                 pr_resp = (sa_path_record_t *)results_p;
3576 
3577                 for (i = 0; i < num_rec; i++) {
3578                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: "
3579                             "P[%d]: SG %llX, DG %llX", i,
3580                             pr_resp[i].SGID.gid_guid, pr_resp[i].DGID.gid_guid);
3581                 }
3582 
3583                 if (p_arg->flags & IBT_PATH_APM) {
3584                         sa_path_record_t *p_resp = NULL, *a_resp = NULL;
3585                         int             p_found = 0, a_found = 0;
3586                         ib_gid_t        p_sg, a_sg, p_dg, a_dg;
3587                         int             s_spec;
3588 
3589                         s_spec =
3590                             p_arg->attr.ipa_src_ip.family != AF_UNSPEC ? 1 : 0;
3591 
3592                         p_sg = gid_s_ptr[0];
3593                         if (sgid_cnt > 1)
3594                                 a_sg = gid_s_ptr[1];
3595                         else
3596                                 a_sg = p_sg;
3597 
3598                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: P_SG: %llX, "
3599                             "A_SG: %llX", p_sg.gid_guid, a_sg.gid_guid);
3600 
3601                         p_dg = gid_s_ptr[sgid_cnt];
3602                         if (dgid_cnt > 1)
3603                                 a_dg = gid_s_ptr[sgid_cnt + 1];
3604                         else
3605                                 a_dg = p_dg;
3606 
3607                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: P_DG: %llX, "
3608                             "A_DG: %llX", p_dg.gid_guid, a_dg.gid_guid);
3609 
3610                         /*
3611                          * If SGID and/or DGID is specified by user, make sure
3612                          * he gets his primary-path on those node points.
3613                          */
3614                         for (i = 0; i < num_rec; i++, pr_resp++) {
3615                                 IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: "
3616                                     "PF %d, AF %d,\n\t\t P[%d] = SG: %llX, "
3617                                     "DG: %llX", p_found, a_found, i,
3618                                     pr_resp->SGID.gid_guid,
3619                                     pr_resp->DGID.gid_guid);
3620 
3621                                 if ((!p_found) &&
3622                                     (p_dg.gid_guid == pr_resp->DGID.gid_guid)) {
3623                                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr"
3624                                             ": Pri DGID Match.. ");
3625                                         if ((s_spec == 0) || (p_sg.gid_guid ==
3626                                             pr_resp->SGID.gid_guid)) {
3627                                                 p_found = 1;
3628                                                 p_resp = pr_resp;
3629                                                 IBTF_DPRINTF_L3(cmlog,
3630                                                     "ibcm_get_ip_mpr: "
3631                                                     "Primary Path Found");
3632 
3633                                                 if (a_found)
3634                                                         break;
3635                                                 else
3636                                                         continue;
3637                                         }
3638                                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr"
3639                                             ": Pri SGID Don't Match.. ");
3640                                 }
3641 
3642                                 if ((!a_found) &&
3643                                     (a_dg.gid_guid == pr_resp->DGID.gid_guid)) {
3644                                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr"
3645                                             ": Alt DGID Match.. ");
3646                                         if ((s_spec == 0) || (a_sg.gid_guid ==
3647                                             pr_resp->SGID.gid_guid)) {
3648                                                 a_found = 1;
3649                                                 a_resp = pr_resp;
3650 
3651                                                 IBTF_DPRINTF_L3(cmlog,
3652                                                     "ibcm_get_ip_mpr:"
3653                                                     "Alternate Path Found ");
3654 
3655                                                 if (p_found)
3656                                                         break;
3657                                                 else
3658                                                         continue;
3659                                         }
3660                                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr"
3661                                             ": Alt SGID Don't Match.. ");
3662                                 }
3663                         }
3664 
3665                         if ((p_found == 0) && (a_found == 0)) {
3666                                 IBTF_DPRINTF_L2(cmlog, "ibcm_get_ip_mpr: Path "
3667                                     "to desired node points NOT Available.");
3668                                 retval = IBT_PATH_RECORDS_NOT_FOUND;
3669                                 goto get_ip_mpr_end;
3670                         }
3671 
3672                         if ((p_resp == NULL) && (a_resp != NULL)) {
3673                                 p_resp = a_resp;
3674                                 a_resp = NULL;
3675                         }
3676 
3677                         /* Fill in Primary Path */
3678                         retval = ibcm_ip_update_pri(p_resp, sl, &paths[found]);
3679                         if (retval != IBT_SUCCESS)
3680                                 goto get_ip_mpr_end;
3681 
3682                         /* Fill in Alternate Path */
3683                         if (a_resp != NULL) {
3684                                 /* a_resp will point to AltPathInfo buffer. */
3685                                 retval = ibcm_update_cep_info(a_resp, sl,
3686                                     NULL, &paths[found].pi_alt_cep_path);
3687                                 if (retval != IBT_SUCCESS)
3688                                         goto get_ip_mpr_end;
3689 
3690                                 /* Update some leftovers */
3691                                 paths[found].pi_alt_pkt_lt =
3692                                     a_resp->PacketLifeTime;
3693                         } else {
3694                                 IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: "
3695                                     "Alternate Path NOT Available.");
3696                                 retval = IBT_INSUFF_DATA;
3697                         }
3698                         found++;
3699                 } else {        /* If NOT APM */
3700                         for (i = 0; i < num_rec; i++, pr_resp++) {
3701                                 IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: "
3702                                     "DGID(%llX)", pr_resp->DGID.gid_guid);
3703 
3704                                 /* Fill in Primary Path */
3705                                 retval = ibcm_ip_update_pri(pr_resp, sl,
3706                                     &paths[found]);
3707                                 if (retval != IBT_SUCCESS)
3708                                         continue;
3709 
3710                                 if (++found == *num_path)
3711                                         break;
3712                         }
3713                 }
3714 get_ip_mpr_end:
3715                 kmem_free(results_p, length);
3716         }
3717         kmem_free(mpr_req, template_len);
3718 
3719         if (found == 0)
3720                 retval = IBT_PATH_RECORDS_NOT_FOUND;
3721         else if (found != *num_path)
3722                 retval = IBT_INSUFF_DATA;
3723         else
3724                 retval = IBT_SUCCESS;
3725 
3726         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: Done (status %d). "
3727             "Found %d/%d Paths", retval, found, *num_path);
3728 
3729         *num_path = found;      /* Update the return count. */
3730 
3731         return (retval);
3732 }
3733 
3734 
3735 static void
3736 ibcm_process_get_ip_paths(void *tq_arg)
3737 {
3738         ibcm_ip_path_tqargs_t   *p_arg = (ibcm_ip_path_tqargs_t *)tq_arg;
3739         ibcm_ip_dinfo_t         *dinfo = NULL;
3740         int                     len = 0;
3741         uint8_t                 max_paths, num_path;
3742         ib_gid_t                *d_gids_p = NULL;
3743         ib_gid_t                sgid, dgid1, dgid2;
3744         ibt_status_t            retval = IBT_SUCCESS;
3745         ibtl_cm_port_list_t     *sl = NULL;
3746         uint_t                  dnum = 0;
3747         uint8_t                 i;
3748         ibcm_hca_info_t         *hcap;
3749         ibmf_saa_handle_t       saa_handle;
3750         ibt_path_attr_t         attr;
3751         ibt_ip_addr_t           src_ip_p;
3752 
3753         IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_ip_paths(%p, 0x%X) ",
3754             p_arg, p_arg->flags);
3755 
3756         max_paths = num_path = p_arg->attr.ipa_max_paths;
3757 
3758         /*
3759          * Prepare the Source and Destination GID list based on the input
3760          * attributes.  We contact ARP module to perform IP to MAC
3761          * i.e. GID conversion.  We use this GID for path look-up.
3762          *
3763          * If APM is requested and if multiple Dest IPs are specified, check
3764          * out whether they are companion to each other.  But, if only one
3765          * Dest IP is specified, then it is beyond our scope to verify that
3766          * the companion port GID obtained has IP-Service enabled.
3767          */
3768         dgid1.gid_prefix = dgid1.gid_guid = 0;
3769         sgid.gid_prefix = sgid.gid_guid = 0;
3770 
3771         retval = ibcm_arp_get_ibaddr(p_arg->attr.ipa_zoneid,
3772             p_arg->attr.ipa_src_ip, p_arg->attr.ipa_dst_ip[0], &sgid,
3773             &dgid1, &src_ip_p);
3774         if (retval) {
3775                 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: "
3776                     "ibcm_arp_get_ibaddr() failed: %d", retval);
3777                 goto ippath_error;
3778         }
3779 
3780         bzero(&attr, sizeof (ibt_path_attr_t));
3781         attr.pa_hca_guid = p_arg->attr.ipa_hca_guid;
3782         attr.pa_hca_port_num = p_arg->attr.ipa_hca_port_num;
3783         attr.pa_sgid = sgid;
3784         bcopy(&p_arg->attr.ipa_mtu, &attr.pa_mtu, sizeof (ibt_mtu_req_t));
3785         bcopy(&p_arg->attr.ipa_srate, &attr.pa_srate, sizeof (ibt_srate_req_t));
3786         bcopy(&p_arg->attr.ipa_pkt_lt, &attr.pa_pkt_lt,
3787             sizeof (ibt_pkt_lt_req_t));
3788         retval = ibtl_cm_get_active_plist(&attr, p_arg->flags, &sl);
3789         if (retval == IBT_SUCCESS) {
3790                 bcopy(&src_ip_p, &sl->p_src_ip, sizeof (ibt_ip_addr_t));
3791         } else {
3792                 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: "
3793                     "ibtl_cm_get_active_plist: Failed %d", retval);
3794                 goto ippath_error;
3795         }
3796 
3797         IBTF_DPRINTF_L4(cmlog, "ibcm_process_get_ip_paths: SGID %llX:%llX, "
3798             "DGID0: %llX:%llX", sl->p_sgid.gid_prefix, sl->p_sgid.gid_guid,
3799             dgid1.gid_prefix, dgid1.gid_guid);
3800 
3801         len = p_arg->attr.ipa_ndst - 1;
3802         len = (len * sizeof (ib_gid_t)) + sizeof (ibcm_ip_dinfo_t);
3803         dinfo = kmem_zalloc(len, KM_SLEEP);
3804 
3805         dinfo->d_gid[0] = dgid1;
3806 
3807         i = 1;
3808         if (p_arg->attr.ipa_ndst > 1) {
3809                 /* Get DGID for all specified Dest IP Addr */
3810                 for (; i < p_arg->attr.ipa_ndst; i++) {
3811                         retval = ibcm_arp_get_ibaddr(p_arg->attr.ipa_zoneid,
3812                             p_arg->attr.ipa_src_ip, p_arg->attr.ipa_dst_ip[i],
3813                             NULL, &dgid2, NULL);
3814                         if (retval) {
3815                                 IBTF_DPRINTF_L2(cmlog,
3816                                     "ibcm_process_get_ip_paths: "
3817                                     "ibcm_arp_get_ibaddr failed: %d", retval);
3818                                 goto ippath_error2;
3819                         }
3820                         dinfo->d_gid[i] = dgid2;
3821 
3822                         IBTF_DPRINTF_L4(cmlog, "ibcm_process_get_ip_paths: "
3823                             "DGID%d: %llX:%llX", i, dgid2.gid_prefix,
3824                             dgid2.gid_guid);
3825                 }
3826 
3827                 if (p_arg->flags & IBT_PATH_APM) {
3828                         dgid2 = dinfo->d_gid[1];
3829 
3830                         retval = ibcm_get_comp_pgids(dgid1, dgid2, 0,
3831                             &d_gids_p, &dnum);
3832                         if ((retval != IBT_SUCCESS) &&
3833                             (retval != IBT_GIDS_NOT_FOUND)) {
3834                                 IBTF_DPRINTF_L2(cmlog,
3835                                     "ibcm_process_get_ip_paths: "
3836                                     "Invalid DGIDs specified w/ APM Flag");
3837                                 goto ippath_error2;
3838                         }
3839                         IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_ip_paths: "
3840                             "Found %d Comp DGID", dnum);
3841 
3842                         if (dnum) {
3843                                 dinfo->d_gid[i] = d_gids_p[0];
3844                                 i++;
3845                         }
3846                 }
3847         }
3848 
3849         /* "i" will get us num_dest count. */
3850         dinfo->num_dest = i;
3851 
3852         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*p_arg))
3853 
3854         /*
3855          * IBTF allocates memory for path_info & src_ip in case of
3856          * Async Get IP Paths
3857          */
3858         if (p_arg->func) {   /* Do these only for Async Get Paths */
3859                 p_arg->paths = kmem_zalloc(sizeof (ibt_path_info_t) * max_paths,
3860                     KM_SLEEP);
3861                 if (p_arg->src_ip_p == NULL)
3862                         p_arg->src_ip_p = kmem_zalloc(
3863                             sizeof (ibt_path_ip_src_t) * max_paths, KM_SLEEP);
3864         }
3865 
3866         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*p_arg))
3867 
3868         IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_ip_paths: HCA (%llX, %d)",
3869             sl->p_hca_guid, sl->p_port_num);
3870 
3871         hcap = ibcm_find_hca_entry(sl->p_hca_guid);
3872         if (hcap == NULL) {
3873                 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: "
3874                     "NO HCA found");
3875                 retval = IBT_HCA_BUSY_DETACHING;
3876                 goto ippath_error2;
3877         }
3878 
3879         /* Get SA Access Handle. */
3880         for (i = 0; i < sl->p_count; i++) {
3881                 if (i == 0) {
3882                         /* Validate whether this HCA supports APM */
3883                         if ((p_arg->flags & IBT_PATH_APM) &&
3884                             (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG))) {
3885                                 IBTF_DPRINTF_L2(cmlog,
3886                                     "ibcm_process_get_ip_paths: HCA (%llX): "
3887                                     "APM NOT SUPPORTED", sl[i].p_hca_guid);
3888                                 retval = IBT_APM_NOT_SUPPORTED;
3889                                 goto ippath_error3;
3890                         }
3891                 }
3892 
3893                 saa_handle = ibcm_get_saa_handle(hcap, sl[i].p_port_num);
3894                 if (saa_handle == NULL) {
3895                         IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: "
3896                             "SAA HDL NULL, HCA (%llX:%d) NOT ACTIVE",
3897                             sl[i].p_hca_guid, sl[i].p_port_num);
3898                         retval = IBT_HCA_PORT_NOT_ACTIVE;
3899                         goto ippath_error3;
3900                 }
3901                 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sl))
3902                 sl[i].p_saa_hdl = saa_handle;
3903                 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*sl))
3904         }
3905 
3906         /* Get Path Records. */
3907         retval = ibcm_saa_ip_pr(p_arg, sl, dinfo, &num_path);
3908 
3909 ippath_error3:
3910         ibcm_dec_hca_acc_cnt(hcap);
3911 
3912 ippath_error2:
3913         if (dinfo && len)
3914                 kmem_free(dinfo, len);
3915 
3916 ippath_error1:
3917         if (sl)
3918                 ibtl_cm_free_active_plist(sl);
3919 
3920 ippath_error:
3921         if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA))
3922                 num_path = 0;
3923 
3924         if (p_arg->num_paths_p != NULL)
3925                 *p_arg->num_paths_p = num_path;
3926 
3927         if (p_arg->func) {   /* Do these only for Async Get Paths */
3928                 ibt_path_info_t *tmp_path_p;
3929                 ibt_path_ip_src_t       *tmp_src_ip_p;
3930 
3931                 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*p_arg))
3932                 p_arg->retval = retval;
3933                 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*p_arg))
3934 
3935                 if (retval == IBT_INSUFF_DATA) {
3936                         /*
3937                          * We allocated earlier memory based on "max_paths",
3938                          * but we got lesser path-records, so re-adjust that
3939                          * buffer so that caller can free the correct memory.
3940                          */
3941                         tmp_path_p = kmem_alloc(
3942                             sizeof (ibt_path_info_t) * num_path, KM_SLEEP);
3943 
3944                         bcopy(p_arg->paths, tmp_path_p,
3945                             num_path * sizeof (ibt_path_info_t));
3946 
3947                         kmem_free(p_arg->paths,
3948                             sizeof (ibt_path_info_t) * max_paths);
3949 
3950                         tmp_src_ip_p = kmem_alloc(
3951                             sizeof (ibt_path_ip_src_t) * num_path, KM_SLEEP);
3952 
3953                         bcopy(p_arg->src_ip_p, tmp_src_ip_p,
3954                             num_path * sizeof (ibt_path_ip_src_t));
3955 
3956                         kmem_free(p_arg->src_ip_p,
3957                             sizeof (ibt_path_ip_src_t) * max_paths);
3958                 } else if (retval != IBT_SUCCESS) {
3959                         if (p_arg->paths)
3960                                 kmem_free(p_arg->paths,
3961                                     sizeof (ibt_path_info_t) * max_paths);
3962                         if (p_arg->src_ip_p)
3963                                 kmem_free(p_arg->src_ip_p,
3964                                     sizeof (ibt_path_ip_src_t) * max_paths);
3965                         tmp_path_p = NULL;
3966                         tmp_src_ip_p = NULL;
3967                 } else {
3968                         tmp_path_p = p_arg->paths;
3969                         tmp_src_ip_p = p_arg->src_ip_p;
3970                 }
3971                 (*(p_arg->func))(p_arg->arg, retval, tmp_path_p, num_path,
3972                     tmp_src_ip_p);
3973 
3974                 len = p_arg->len;
3975                 if (p_arg && len)
3976                         kmem_free(p_arg, len);
3977         } else {
3978                 mutex_enter(&p_arg->ip_lock);
3979                 p_arg->ip_done = B_TRUE;
3980                 p_arg->retval = retval;
3981                 cv_signal(&p_arg->ip_cv);
3982                 mutex_exit(&p_arg->ip_lock);
3983         }
3984 
3985         IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: done: status %d, "
3986             "Found %d/%d Path Records", retval, num_path, max_paths);
3987 }
3988 
3989 
3990 static ibt_status_t
3991 ibcm_val_ipattr(ibt_ip_path_attr_t *attrp, ibt_path_flags_t flags)
3992 {
3993         uint_t                  i;
3994 
3995         if (attrp == NULL) {
3996                 IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: IP Path Attr is NULL");
3997                 return (IBT_INVALID_PARAM);
3998         }
3999 
4000         IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: Inputs are: HCA %llX:%d, "
4001             "Maxpath= %d, \n Flags= 0x%X, #Dest %d", attrp->ipa_hca_guid,
4002             attrp->ipa_hca_port_num, attrp->ipa_max_paths, flags,
4003             attrp->ipa_ndst);
4004 
4005         /*
4006          * Validate Path Flags.
4007          * IBT_PATH_AVAIL & IBT_PATH_PERF are mutually exclusive.
4008          */
4009         if ((flags & IBT_PATH_AVAIL) && (flags & IBT_PATH_PERF)) {
4010                 IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: Invalid Flags: 0x%X,"
4011                     "\n\t AVAIL and PERF flags specified together", flags);
4012                 return (IBT_INVALID_PARAM);
4013         }
4014 
4015         /*
4016          * Validate number of records requested.
4017          *
4018          * Max_paths of "0" is invalid.
4019          * Max_paths <= IBT_MAX_SPECIAL_PATHS, if AVAIL or PERF is set.
4020          */
4021         if (attrp->ipa_max_paths == 0) {
4022                 IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: Invalid max_paths %d",
4023                     attrp->ipa_max_paths);
4024                 return (IBT_INVALID_PARAM);
4025         }
4026 
4027         if ((flags & (IBT_PATH_AVAIL | IBT_PATH_PERF)) &&
4028             (attrp->ipa_max_paths > IBT_MAX_SPECIAL_PATHS)) {
4029                 IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: MaxPaths that can be "
4030                     "requested is <%d> \n when IBT_PATH_AVAIL or IBT_PATH_PERF"
4031                     " flag is specified.", IBT_MAX_SPECIAL_PATHS);
4032                 return (IBT_INVALID_PARAM);
4033         }
4034 
4035         /* Only 2 destinations can be specified w/ APM flag. */
4036         if ((flags & IBT_PATH_APM) && (attrp->ipa_ndst > 2)) {
4037                 IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: Max #Dest is 2, with "
4038                     "APM flag");
4039                 return (IBT_INVALID_PARAM);
4040         }
4041 
4042         /* Validate the destination info */
4043         if ((attrp->ipa_ndst == 0) || (attrp->ipa_ndst == NULL)) {
4044                 IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: DstIP Not provided "
4045                     "dst_ip %p, ndst %d", attrp->ipa_dst_ip, attrp->ipa_ndst);
4046                 return (IBT_INVALID_PARAM);
4047         }
4048 
4049         /* Basic validation of Source IPADDR (if provided). */
4050         IBCM_PRINT_IP("ibcm_val_ipattr SrcIP", &attrp->ipa_src_ip);
4051         if ((attrp->ipa_src_ip.family == AF_INET) &&
4052             (attrp->ipa_src_ip.un.ip4addr == htonl(INADDR_LOOPBACK) ||
4053             attrp->ipa_src_ip.un.ip4addr == INADDR_ANY)) {
4054                 IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: SrcIP specified is "
4055                     "LOOPBACK/ZEROs: NOT SUPPORTED");
4056                 return (IBT_NOT_SUPPORTED);
4057         } else if ((attrp->ipa_src_ip.family == AF_INET6) &&
4058             (IN6_IS_ADDR_UNSPECIFIED(&attrp->ipa_src_ip.un.ip6addr) ||
4059             IN6_IS_ADDR_LOOPBACK(&attrp->ipa_src_ip.un.ip6addr))) {
4060                 IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: SrcIP specified is "
4061                     "LOOPBACK/ZEROs: NOT SUPPORTED");
4062                 return (IBT_NOT_SUPPORTED);
4063         }
4064 
4065         if (ibcm_ip6_linklocal_addr_ok &&
4066             (attrp->ipa_src_ip.family == AF_INET6) &&
4067             (IN6_IS_ADDR_LINKLOCAL(&attrp->ipa_src_ip.un.ip6addr))) {
4068                 IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: SrcIP specified is "
4069                     "Link Local Address: NOT SUPPORTED");
4070                 return (IBT_NOT_SUPPORTED);
4071         }
4072 
4073         /* Basic validation of Dest IPADDR. */
4074         for (i = 0; i < attrp->ipa_ndst; i++) {
4075                 ibt_ip_addr_t   dst_ip = attrp->ipa_dst_ip[i];
4076 
4077                 IBCM_PRINT_IP("ibcm_val_ipattr DstIP", &dst_ip);
4078 
4079                 if (dst_ip.family == AF_UNSPEC) {
4080                         IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: ERROR: "
4081                             "Invalid DstIP specified");
4082                         return (IBT_INVALID_PARAM);
4083                 } else if ((dst_ip.family == AF_INET) &&
4084                     (dst_ip.un.ip4addr == htonl(INADDR_LOOPBACK) ||
4085                     dst_ip.un.ip4addr == INADDR_ANY)) {
4086                         IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: DstIP "
4087                             "specified is LOOPBACK/ZEROs: NOT SUPPORTED");
4088                         return (IBT_NOT_SUPPORTED);
4089                 } else if ((dst_ip.family == AF_INET6) &&
4090                     (IN6_IS_ADDR_UNSPECIFIED(&dst_ip.un.ip6addr) ||
4091                     IN6_IS_ADDR_LOOPBACK(&dst_ip.un.ip6addr))) {
4092                         IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: DstIP "
4093                             "specified is LOOPBACK/ZEROs: NOT SUPPORTED");
4094                         return (IBT_NOT_SUPPORTED);
4095                 }
4096 
4097                 /*
4098                  * If SrcIP is specified, make sure that SrcIP and DstIP
4099                  * belong to same family.
4100                  */
4101                 if ((attrp->ipa_src_ip.family != AF_UNSPEC) &&
4102                     (attrp->ipa_src_ip.family != dst_ip.family)) {
4103                         IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: ERROR: "
4104                             "Specified SrcIP (%d) and DstIP(%d) family diffs.",
4105                             attrp->ipa_src_ip.family, dst_ip.family);
4106                         return (IBT_INVALID_PARAM);
4107                 }
4108         }
4109 
4110         return (IBT_SUCCESS);
4111 }
4112 
4113 
4114 static ibt_status_t
4115 ibcm_get_ip_path(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags,
4116     ibt_ip_path_attr_t *attrp, ibt_path_info_t *paths, uint8_t *num_path_p,
4117     ibt_path_ip_src_t *src_ip_p, ibt_ip_path_handler_t func, void  *arg)
4118 {
4119         ibcm_ip_path_tqargs_t   *path_tq;
4120         int             sleep_flag = ((func == NULL) ? KM_SLEEP : KM_NOSLEEP);
4121         uint_t          len, ret;
4122         ibt_status_t    retval;
4123 
4124         retval = ibcm_val_ipattr(attrp, flags);
4125         if (retval != IBT_SUCCESS)
4126                 return (retval);
4127 
4128         len = (attrp->ipa_ndst * sizeof (ibt_ip_addr_t)) +
4129             sizeof (ibcm_ip_path_tqargs_t);
4130         path_tq = kmem_zalloc(len, sleep_flag);
4131         if (path_tq == NULL) {
4132                 IBTF_DPRINTF_L2(cmlog, "ibcm_get_ip_path: "
4133                     "Unable to allocate memory for local usage.");
4134                 return (IBT_INSUFF_KERNEL_RESOURCE);
4135         }
4136 
4137         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*path_tq))
4138         bcopy(attrp, &path_tq->attr, sizeof (ibt_ip_path_attr_t));
4139 
4140         path_tq->attr.ipa_dst_ip = (ibt_ip_addr_t *)(((uchar_t *)path_tq) +
4141             sizeof (ibcm_ip_path_tqargs_t));
4142         bcopy(attrp->ipa_dst_ip, path_tq->attr.ipa_dst_ip,
4143             sizeof (ibt_ip_addr_t) * attrp->ipa_ndst);
4144 
4145         /* Ignore IBT_PATH_AVAIL flag, if only one path is requested. */
4146         if ((flags & IBT_PATH_AVAIL) && (attrp->ipa_max_paths == 1)) {
4147                 flags &= ~IBT_PATH_AVAIL;
4148 
4149                 IBTF_DPRINTF_L4(cmlog, "ibcm_get_ip_path: Ignoring "
4150                     "IBT_PATH_AVAIL flag, as only ONE path info is requested.");
4151         }
4152 
4153         path_tq->flags = flags;
4154         path_tq->ibt_hdl = ibt_hdl;
4155         path_tq->paths = paths;
4156         path_tq->src_ip_p = src_ip_p;
4157         path_tq->num_paths_p = num_path_p;
4158         path_tq->func = func;
4159         path_tq->arg = arg;
4160         path_tq->len = len;
4161         path_tq->ip_done = B_FALSE;
4162         if (func == NULL) {     /* Blocking */
4163                 mutex_init(&path_tq->ip_lock, NULL, MUTEX_DEFAULT, NULL);
4164                 cv_init(&path_tq->ip_cv, NULL, CV_DRIVER, NULL);
4165         }
4166 
4167         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*path_tq))
4168 
4169         sleep_flag = ((func == NULL) ? TQ_SLEEP : TQ_NOSLEEP);
4170         ret = taskq_dispatch(ibcm_taskq, ibcm_process_get_ip_paths, path_tq,
4171             sleep_flag);
4172         if (ret == 0) {
4173                 IBTF_DPRINTF_L2(cmlog, "ibcm_get_ip_path: Failed to dispatch "
4174                     "the TaskQ");
4175                 if (func == NULL) {             /* Blocking */
4176                         cv_destroy(&path_tq->ip_cv);
4177                         mutex_destroy(&path_tq->ip_lock);
4178                 }
4179                 kmem_free(path_tq, len);
4180                 retval = IBT_INSUFF_KERNEL_RESOURCE;
4181         } else {
4182                 if (func != NULL) {             /* Non-Blocking */
4183                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_path: NonBlocking");
4184                         retval = IBT_SUCCESS;
4185                 } else {                /* Blocking */
4186                         IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_path: Blocking");
4187                         mutex_enter(&path_tq->ip_lock);
4188                         while (path_tq->ip_done != B_TRUE)
4189                                 cv_wait(&path_tq->ip_cv, &path_tq->ip_lock);
4190                         retval = path_tq->retval;
4191                         mutex_exit(&path_tq->ip_lock);
4192                         cv_destroy(&path_tq->ip_cv);
4193                         mutex_destroy(&path_tq->ip_lock);
4194                         kmem_free(path_tq, len);
4195                 }
4196         }
4197 
4198         return (retval);
4199 }
4200 
4201 
4202 ibt_status_t
4203 ibt_aget_ip_paths(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags,
4204     ibt_ip_path_attr_t *attrp, ibt_ip_path_handler_t func, void  *arg)
4205 {
4206         IBTF_DPRINTF_L3(cmlog, "ibt_aget_ip_paths(%p (%s), 0x%X, %p, %p, %p)",
4207             ibt_hdl, ibtl_cm_get_clnt_name(ibt_hdl), flags, attrp, func, arg);
4208 
4209         if (func == NULL) {
4210                 IBTF_DPRINTF_L2(cmlog, "ibt_aget_ip_paths: Function Pointer is "
4211                     "NULL - ERROR ");
4212                 return (IBT_INVALID_PARAM);
4213         }
4214 
4215         /* path info will be allocated in ibcm_process_get_ip_paths() */
4216         return (ibcm_get_ip_path(ibt_hdl, flags, attrp, NULL, NULL,
4217             NULL, func, arg));
4218 }
4219 
4220 
4221 ibt_status_t
4222 ibt_get_ip_paths(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags,
4223     ibt_ip_path_attr_t *attrp, ibt_path_info_t *paths, uint8_t *num_paths_p,
4224     ibt_path_ip_src_t *src_ip_p)
4225 {
4226         IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_paths(%p(%s), 0x%X, %p, %p, %p, %p)",
4227             ibt_hdl, ibtl_cm_get_clnt_name(ibt_hdl), flags, attrp, paths,
4228             num_paths_p, src_ip_p);
4229 
4230         if (paths == NULL) {
4231                 IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_paths: Path Info Pointer is "
4232                     "NULL - ERROR ");
4233                 return (IBT_INVALID_PARAM);
4234         }
4235 
4236         if (num_paths_p != NULL)
4237                 *num_paths_p = 0;
4238 
4239         return (ibcm_get_ip_path(ibt_hdl, flags, attrp, paths, num_paths_p,
4240             src_ip_p, NULL, NULL));
4241 }
4242 
4243 
4244 ibt_status_t
4245 ibt_get_ip_alt_path(ibt_channel_hdl_t rc_chan, ibt_path_flags_t flags,
4246     ibt_alt_ip_path_attr_t *attrp, ibt_alt_path_info_t *api_p)
4247 {
4248         sa_multipath_record_t   *mpr_req;
4249         sa_path_record_t        *pr_resp;
4250         ibmf_saa_access_args_t  access_args;
4251         ibt_qp_query_attr_t     qp_attr;
4252         ibtl_cm_hca_port_t      c_hp, n_hp;
4253         ibcm_hca_info_t         *hcap;
4254         void                    *results_p;
4255         uint64_t                c_mask = 0;
4256         ib_gid_t                *gid_ptr = NULL;
4257         ib_gid_t                *sgids_p = NULL,  *dgids_p = NULL;
4258         ib_gid_t                cur_dgid, cur_sgid;
4259         ib_gid_t                new_dgid, new_sgid;
4260         ibmf_saa_handle_t       saa_handle;
4261         size_t                  length;
4262         int                     i, j, template_len, rec_found;
4263         uint_t                  snum = 0, dnum = 0, num_rec;
4264         ibt_status_t            retval;
4265         ib_mtu_t                prim_mtu;
4266 
4267         IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path(%p, %x, %p, %p)",
4268             rc_chan, flags, attrp, api_p);
4269 
4270         /* validate channel */
4271         if (IBCM_INVALID_CHANNEL(rc_chan)) {
4272                 IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: invalid channel");
4273                 return (IBT_CHAN_HDL_INVALID);
4274         }
4275 
4276         if (api_p == NULL) {
4277                 IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: invalid attribute:"
4278                     " AltPathInfo can't be NULL");
4279                 return (IBT_INVALID_PARAM);
4280         }
4281 
4282         retval = ibt_query_qp(rc_chan, &qp_attr);
4283         if (retval != IBT_SUCCESS) {
4284                 IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: ibt_query_qp(%p) "
4285                     "failed %d", rc_chan, retval);
4286                 return (retval);
4287         }
4288 
4289         if (qp_attr.qp_info.qp_trans != IBT_RC_SRV) {
4290                 IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4291                     "Invalid Channel type: Applicable only to RC Channel");
4292                 return (IBT_CHAN_SRV_TYPE_INVALID);
4293         }
4294 
4295         cur_dgid =
4296             qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dgid;
4297         cur_sgid =
4298             qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_sgid;
4299         prim_mtu = qp_attr.qp_info.qp_transport.rc.rc_path_mtu;
4300 
4301         /* If optional attributes are specified, validate them. */
4302         if (attrp) {
4303                 /* Get SGID and DGID for the specified input ip-addr */
4304                 retval = ibcm_arp_get_ibaddr(attrp->apa_zoneid,
4305                     attrp->apa_src_ip, attrp->apa_dst_ip, &new_sgid,
4306                     &new_dgid, NULL);
4307                 if (retval) {
4308                         IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4309                             "ibcm_arp_get_ibaddr() failed: %d", retval);
4310                         return (retval);
4311                 }
4312         } else {
4313                 new_dgid.gid_prefix = 0;
4314                 new_dgid.gid_guid = 0;
4315                 new_sgid.gid_prefix = 0;
4316                 new_sgid.gid_guid = 0;
4317         }
4318 
4319         if ((new_dgid.gid_prefix != 0) && (new_sgid.gid_prefix != 0) &&
4320             (new_dgid.gid_prefix != new_sgid.gid_prefix)) {
4321                 IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: Specified SGID's "
4322                     "SNprefix (%llX) doesn't match with \n specified DGID's "
4323                     "SNprefix: %llX", new_sgid.gid_prefix, new_dgid.gid_prefix);
4324                 return (IBT_INVALID_PARAM);
4325         }
4326 
4327         /* For the specified SGID, get HCA information. */
4328         retval = ibtl_cm_get_hca_port(cur_sgid, 0, &c_hp);
4329         if (retval != IBT_SUCCESS) {
4330                 IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4331                     "Get HCA Port Failed: %d", retval);
4332                 return (retval);
4333         }
4334 
4335         hcap = ibcm_find_hca_entry(c_hp.hp_hca_guid);
4336         if (hcap == NULL) {
4337                 IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: NO HCA found");
4338                 return (IBT_HCA_BUSY_DETACHING);
4339         }
4340 
4341         /* Validate whether this HCA support APM */
4342         if (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG)) {
4343                 IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4344                     "HCA (%llX) - APM NOT SUPPORTED ", c_hp.hp_hca_guid);
4345                 retval = IBT_APM_NOT_SUPPORTED;
4346                 goto get_ip_alt_path_done;
4347         }
4348 
4349         /* Get Companion Port GID of the current Channel's SGID */
4350         if ((new_sgid.gid_guid == 0) || ((new_sgid.gid_guid != 0) &&
4351             (new_sgid.gid_guid != cur_sgid.gid_guid))) {
4352                 IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: SRC: "
4353                     "Get Companion PortGids for - %llX:%llX",
4354                     cur_sgid.gid_prefix, cur_sgid.gid_guid);
4355 
4356                 retval = ibcm_get_comp_pgids(cur_sgid, new_sgid,
4357                     c_hp.hp_hca_guid, &sgids_p, &snum);
4358                 if (retval != IBT_SUCCESS)
4359                         goto get_ip_alt_path_done;
4360         }
4361 
4362         /* Get Companion Port GID of the current Channel's DGID */
4363         if ((new_dgid.gid_guid == 0) || ((new_dgid.gid_guid != 0) &&
4364             (new_dgid.gid_guid != cur_dgid.gid_guid))) {
4365 
4366                 IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: DEST: "
4367                     "Get Companion PortGids for - %llX:%llX",
4368                     cur_dgid.gid_prefix, cur_dgid.gid_guid);
4369 
4370                 retval = ibcm_get_comp_pgids(cur_dgid, new_dgid, 0, &dgids_p,
4371                     &dnum);
4372                 if (retval != IBT_SUCCESS)
4373                         goto get_ip_alt_path_done;
4374         }
4375 
4376         if ((new_dgid.gid_guid == 0) || (new_sgid.gid_guid == 0)) {
4377                 if (new_sgid.gid_guid == 0) {
4378                         for (i = 0; i < snum; i++) {
4379                                 if (new_dgid.gid_guid == 0) {
4380                                         for (j = 0; j < dnum; j++) {
4381                                                 if (sgids_p[i].gid_prefix ==
4382                                                     dgids_p[j].gid_prefix) {
4383                                                         new_dgid = dgids_p[j];
4384                                                         new_sgid = sgids_p[i];
4385 
4386                                                         goto get_ip_alt_proceed;
4387                                                 }
4388                                         }
4389                                         /*  Current DGID */
4390                                         if (sgids_p[i].gid_prefix ==
4391                                             cur_dgid.gid_prefix) {
4392                                                 new_sgid = sgids_p[i];
4393                                                 goto get_ip_alt_proceed;
4394                                         }
4395                                 } else {
4396                                         if (sgids_p[i].gid_prefix ==
4397                                             new_dgid.gid_prefix) {
4398                                                 new_sgid = sgids_p[i];
4399                                                 goto get_ip_alt_proceed;
4400                                         }
4401                                 }
4402                         }
4403                         /* Current SGID */
4404                         if (new_dgid.gid_guid == 0) {
4405                                 for (j = 0; j < dnum; j++) {
4406                                         if (cur_sgid.gid_prefix ==
4407                                             dgids_p[j].gid_prefix) {
4408                                                 new_dgid = dgids_p[j];
4409 
4410                                                 goto get_ip_alt_proceed;
4411                                         }
4412                                 }
4413                         }
4414                 } else if (new_dgid.gid_guid == 0) {
4415                         for (i = 0; i < dnum; i++) {
4416                                 if (dgids_p[i].gid_prefix ==
4417                                     new_sgid.gid_prefix) {
4418                                         new_dgid = dgids_p[i];
4419                                         goto get_ip_alt_proceed;
4420                                 }
4421                         }
4422                         /* Current DGID */
4423                         if (cur_dgid.gid_prefix == new_sgid.gid_prefix) {
4424                                 goto get_ip_alt_proceed;
4425                         }
4426                 }
4427                 /*
4428                  * hmm... No Companion Ports available.
4429                  * so we will be using current or specified attributes only.
4430                  */
4431         }
4432 
4433 get_ip_alt_proceed:
4434         if (new_sgid.gid_guid != 0) {
4435                 retval = ibtl_cm_get_hca_port(new_sgid, 0, &n_hp);
4436                 if (retval != IBT_SUCCESS) {
4437                         IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4438                             "Get HCA Port Failed: %d", retval);
4439                         goto get_ip_alt_path_done;
4440                 }
4441         }
4442 
4443         /* Calculate the size for multi-path records template */
4444         template_len = (2 * sizeof (ib_gid_t)) + sizeof (sa_multipath_record_t);
4445 
4446         mpr_req = kmem_zalloc(template_len, KM_SLEEP);
4447 
4448         ASSERT(mpr_req != NULL);
4449 
4450         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
4451 
4452         gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
4453             sizeof (sa_multipath_record_t));
4454 
4455         /* SGID */
4456         if (new_sgid.gid_guid == 0)
4457                 *gid_ptr = cur_sgid;
4458         else
4459                 *gid_ptr = new_sgid;
4460 
4461         IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: Get Path Between "
4462             " SGID : %llX:%llX", gid_ptr->gid_prefix, gid_ptr->gid_guid);
4463 
4464         gid_ptr++;
4465 
4466         /* DGID */
4467         if (new_dgid.gid_guid == 0)
4468                 *gid_ptr = cur_dgid;
4469         else
4470                 *gid_ptr = new_dgid;
4471 
4472         IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path:\t\t    DGID : %llX:%llX",
4473             gid_ptr->gid_prefix, gid_ptr->gid_guid);
4474 
4475         mpr_req->SGIDCount = 1;
4476         c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
4477 
4478         mpr_req->DGIDCount = 1;
4479         c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
4480 
4481         /* Is Flow Label Specified. */
4482         if (attrp) {
4483                 if (attrp->apa_flow) {
4484                         mpr_req->FlowLabel = attrp->apa_flow;
4485                         c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
4486                 }
4487 
4488                 /* Is HopLimit Specified. */
4489                 if (flags & IBT_PATH_HOP) {
4490                         mpr_req->HopLimit = attrp->apa_hop;
4491                         c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
4492                 }
4493 
4494                 /* Is TClass Specified. */
4495                 if (attrp->apa_tclass) {
4496                         mpr_req->TClass = attrp->apa_tclass;
4497                         c_mask |= SA_MPR_COMPMASK_TCLASS;
4498                 }
4499 
4500                 /* Is SL specified. */
4501                 if (attrp->apa_sl) {
4502                         mpr_req->SL = attrp->apa_sl;
4503                         c_mask |= SA_MPR_COMPMASK_SL;
4504                 }
4505 
4506                 if (flags & IBT_PATH_PERF) {
4507                         mpr_req->PacketLifeTimeSelector = IBT_BEST;
4508                         mpr_req->RateSelector = IBT_BEST;
4509 
4510                         c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
4511                             SA_MPR_COMPMASK_RATESELECTOR;
4512                 } else {
4513                         if (attrp->apa_pkt_lt.p_selector == IBT_BEST) {
4514                                 mpr_req->PacketLifeTimeSelector = IBT_BEST;
4515                                 c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
4516                         }
4517 
4518                         if (attrp->apa_srate.r_selector == IBT_BEST) {
4519                                 mpr_req->RateSelector = IBT_BEST;
4520                                 c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
4521                         }
4522                 }
4523 
4524                 /*
4525                  * Honor individual selection of these attributes,
4526                  * even if IBT_PATH_PERF is set.
4527                  */
4528                 /* Check out whether Packet Life Time is specified. */
4529                 if (attrp->apa_pkt_lt.p_pkt_lt) {
4530                         mpr_req->PacketLifeTime =
4531                             ibt_usec2ib(attrp->apa_pkt_lt.p_pkt_lt);
4532                         mpr_req->PacketLifeTimeSelector =
4533                             attrp->apa_pkt_lt.p_selector;
4534 
4535                         c_mask |= SA_MPR_COMPMASK_PKTLT |
4536                             SA_MPR_COMPMASK_PKTLTSELECTOR;
4537                 }
4538 
4539                 /* Is SRATE specified. */
4540                 if (attrp->apa_srate.r_srate) {
4541                         mpr_req->Rate = attrp->apa_srate.r_srate;
4542                         mpr_req->RateSelector = attrp->apa_srate.r_selector;
4543 
4544                         c_mask |= SA_MPR_COMPMASK_RATE |
4545                             SA_MPR_COMPMASK_RATESELECTOR;
4546                 }
4547         }
4548 
4549         /* Alt PathMTU can be GT or EQU to current channel's Pri PathMTU */
4550 
4551         /* P_Key must be same as that of primary path */
4552         retval = ibt_index2pkey_byguid(c_hp.hp_hca_guid, c_hp.hp_port,
4553             qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix,
4554             &mpr_req->P_Key);
4555         if (retval != IBT_SUCCESS) {
4556                 IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: PKeyIdx2Pkey "
4557                     "Failed: %d", retval);
4558                 goto get_ip_alt_path_done;
4559         }
4560         c_mask |= SA_MPR_COMPMASK_PKEY;
4561 
4562         mpr_req->Reversible = 1;     /* We always get REVERSIBLE paths. */
4563         mpr_req->IndependenceSelector = 1;
4564         c_mask |= SA_MPR_COMPMASK_REVERSIBLE | SA_MPR_COMPMASK_INDEPSEL;
4565 
4566         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
4567 
4568         IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: CMask: 0x%llX", c_mask);
4569 
4570         /* NOTE: We will **NOT** specify how many records we want. */
4571 
4572         IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: Primary: MTU %d, PKey[%d]="
4573             "0x%X\n\tSGID = %llX:%llX, DGID = %llX:%llX", prim_mtu,
4574             qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix, mpr_req->P_Key,
4575             cur_sgid.gid_prefix, cur_sgid.gid_guid, cur_dgid.gid_prefix,
4576             cur_dgid.gid_guid);
4577 
4578         /* Get SA Access Handle. */
4579         if (new_sgid.gid_guid != 0)
4580                 saa_handle = ibcm_get_saa_handle(hcap, n_hp.hp_port);
4581         else
4582                 saa_handle = ibcm_get_saa_handle(hcap, c_hp.hp_port);
4583         if (saa_handle == NULL) {
4584                 retval = IBT_HCA_PORT_NOT_ACTIVE;
4585                 goto get_ip_alt_path_done;
4586         }
4587 
4588         /* Contact SA Access to retrieve Path Records. */
4589         access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
4590         access_args.sq_access_type = IBMF_SAA_RETRIEVE;
4591         access_args.sq_component_mask = c_mask;
4592         access_args.sq_template = mpr_req;
4593         access_args.sq_template_length = sizeof (sa_multipath_record_t);
4594         access_args.sq_callback = NULL;
4595         access_args.sq_callback_arg = NULL;
4596 
4597         retval = ibcm_contact_sa_access(saa_handle, &access_args, &length,
4598             &results_p);
4599         if (retval != IBT_SUCCESS) {
4600                 goto get_ip_alt_path_done;
4601         }
4602 
4603         num_rec = length / sizeof (sa_path_record_t);
4604 
4605         kmem_free(mpr_req, template_len);
4606 
4607         IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: Found %d Paths", num_rec);
4608 
4609         rec_found = 0;
4610         if ((results_p != NULL) && (num_rec > 0)) {
4611                 /* Update the PathInfo with the response Path Records */
4612                 pr_resp = (sa_path_record_t *)results_p;
4613                 for (i = 0; i < num_rec; i++, pr_resp++) {
4614                         if (prim_mtu > pr_resp->Mtu) {
4615                                 IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4616                                     "Alt PathMTU(%d) must be GT or EQU to Pri "
4617                                     "PathMTU(%d). Ignore this rec",
4618                                     pr_resp->Mtu, prim_mtu);
4619                                 continue;
4620                         }
4621 
4622                         if ((new_sgid.gid_guid == 0) &&
4623                             (new_dgid.gid_guid == 0)) {
4624                                 /* Reject PathRec if it same as Primary Path. */
4625                                 if (ibcm_compare_paths(pr_resp,
4626                                     &qp_attr.qp_info.qp_transport.rc.rc_path,
4627                                     &c_hp)) {
4628                                         IBTF_DPRINTF_L3(cmlog,
4629                                             "ibt_get_ip_alt_path: PathRec "
4630                                             "obtained is similar to Prim Path, "
4631                                             "ignore this record");
4632                                         continue;
4633                                 }
4634                         }
4635 
4636                         if (new_sgid.gid_guid == 0) {
4637                                 retval = ibcm_update_cep_info(pr_resp, NULL,
4638                                     &c_hp, &api_p->ap_alt_cep_path);
4639                         } else {
4640                                 retval = ibcm_update_cep_info(pr_resp, NULL,
4641                                     &n_hp, &api_p->ap_alt_cep_path);
4642                         }
4643                         if (retval != IBT_SUCCESS)
4644                                 continue;
4645 
4646                         /* Update some leftovers */
4647                         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*api_p))
4648 
4649                         api_p->ap_alt_pkt_lt = pr_resp->PacketLifeTime;
4650 
4651                         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*api_p))
4652 
4653                         rec_found = 1;
4654                         break;
4655                 }
4656                 kmem_free(results_p, length);
4657         }
4658 
4659         if (rec_found == 0) {
4660                 IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: AltPath cannot"
4661                     " be established");
4662                 retval = IBT_PATH_RECORDS_NOT_FOUND;
4663         } else
4664                 retval = IBT_SUCCESS;
4665 
4666 get_ip_alt_path_done:
4667         if ((snum) && (sgids_p))
4668                 kmem_free(sgids_p, snum * sizeof (ib_gid_t));
4669 
4670         if ((dnum) && (dgids_p))
4671                 kmem_free(dgids_p, dnum * sizeof (ib_gid_t));
4672 
4673         ibcm_dec_hca_acc_cnt(hcap);
4674 
4675         IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: Done (status %d)", retval);
4676 
4677         return (retval);
4678 }
4679 
4680 
4681 /* Routines for warlock */
4682 
4683 /* ARGSUSED */
4684 static void
4685 ibcm_dummy_path_handler(void *arg, ibt_status_t retval, ibt_path_info_t *paths,
4686     uint8_t num_path)
4687 {
4688         ibcm_path_tqargs_t      dummy_path;
4689 
4690         dummy_path.func = ibcm_dummy_path_handler;
4691 
4692         IBTF_DPRINTF_L5(cmlog, "ibcm_dummy_path_handler: "
4693             "dummy_path.func %p", dummy_path.func);
4694 }
4695 
4696 /* ARGSUSED */
4697 static void
4698 ibcm_dummy_ip_path_handler(void *arg, ibt_status_t retval,
4699     ibt_path_info_t *paths, uint8_t num_path, ibt_path_ip_src_t *src_ip)
4700 {
4701         ibcm_ip_path_tqargs_t   dummy_path;
4702 
4703         dummy_path.func = ibcm_dummy_ip_path_handler;
4704 
4705         IBTF_DPRINTF_L5(cmlog, "ibcm_dummy_ip_path_handler: "
4706             "dummy_path.func %p", dummy_path.func);
4707 }