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