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