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