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