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