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