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