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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/ib/mgt/ibcm/ibcm_impl.h> 30 #include <sys/ib/ibtl/ibti.h> 31 32 /* 33 * ibcm_path.c 34 * 35 * ibt_get_paths() implement the Path Informations related functionality. 36 */ 37 38 /* Externs. */ 39 extern char cmlog[]; 40 41 /* ibcm_saa_service_rec() fills in ServiceID and DGID. */ 42 typedef struct ibcm_dest_s { 43 ib_gid_t d_gid; 44 ib_svc_id_t d_sid; 45 ibt_srv_data_t d_sdata; 46 ib_pkey_t d_pkey; 47 uint_t d_tag; /* 0 = Unicast, 1 = Multicast, 2 = LoopBack */ 48 } ibcm_dest_t; 49 50 /* Holds Destination information needed to fill in ibt_path_info_t. */ 51 typedef struct ibcm_dinfo_s { 52 uint8_t num_dest; 53 ib_pkey_t p_key; 54 ibcm_dest_t dest[1]; 55 } ibcm_dinfo_t; 56 57 _NOTE(SCHEME_PROTECTS_DATA("Temporary path storage", ibcm_dinfo_s)) 58 _NOTE(READ_ONLY_DATA(ibt_path_attr_s)) 59 60 typedef struct ibcm_path_tqargs_s { 61 ibt_path_attr_t attr; 62 ibt_path_info_t *paths; 63 uint8_t *num_paths_p; 64 ibt_path_handler_t func; 65 void *arg; 66 ibt_path_flags_t flags; 67 uint8_t max_paths; 68 } ibcm_path_tqargs_t; 69 70 71 /* Prototype Declarations. */ 72 static ibt_status_t ibcm_get_path_rec(ibcm_path_tqargs_t *, ibcm_dinfo_t *, 73 uint8_t *, ibt_path_info_t *); 74 75 static ibt_status_t ibcm_saa_path_rec(ibcm_path_tqargs_t *, 76 ibtl_cm_port_list_t *, ibcm_dinfo_t *, uint8_t *); 77 78 static ibt_status_t ibcm_update_cep_info(sa_path_record_t *, 79 ibtl_cm_port_list_t *, ibtl_cm_hca_port_t *, ibt_cep_path_t *); 80 81 static ibt_status_t ibcm_fillin_loopbackinfo(ibtl_cm_port_list_t *, 82 uint8_t index, ibcm_dinfo_t *, ibt_path_info_t *); 83 84 static ibt_status_t ibcm_saa_service_rec(ibcm_path_tqargs_t *, 85 ibtl_cm_port_list_t *, ibcm_dinfo_t *); 86 87 static ibt_status_t ibcm_get_single_pathrec(ibcm_path_tqargs_t *, 88 ibtl_cm_port_list_t *, ibcm_dinfo_t *, uint8_t, 89 uint8_t *, ibt_path_info_t *); 90 91 static ibt_status_t ibcm_get_multi_pathrec(ibcm_path_tqargs_t *, 92 ibtl_cm_port_list_t *, ibcm_dinfo_t *dinfo, 93 uint8_t *, ibt_path_info_t *); 94 95 static ibt_status_t ibcm_validate_path_attributes(ibt_path_attr_t *attrp, 96 ibt_path_flags_t flags, uint8_t max_paths); 97 98 static ibt_status_t ibcm_handle_get_path(ibt_path_attr_t *attrp, 99 ibt_path_flags_t flags, uint8_t max_paths, ibt_path_info_t *paths, 100 uint8_t *num_path_p, ibt_path_handler_t func, void *arg); 101 102 static void ibcm_process_async_get_paths(void *tq_arg); 103 104 static ibt_status_t ibcm_process_get_paths(void *tq_arg); 105 106 static ibt_status_t ibcm_get_comp_pgids(ib_gid_t, ib_gid_t, ib_guid_t, 107 ib_gid_t **, uint_t *); 108 109 110 /* 111 * Function: 112 * ibt_aget_paths 113 * Input: 114 * ibt_hdl The handle returned to the client by the IBTF from an 115 * ibt_attach() call. Can be used by the IBTF Policy module 116 * and CM in the determination of the "best" path to the 117 * specified destination for this class of driver. 118 * flags Path flags. 119 * attrp Points to an ibt_path_attr_t struct that contains 120 * required and optional attributes. 121 * func A pointer to an ibt_path_handler_t function to call 122 * when ibt_aget_paths() completes. 123 * arg The argument to 'func'. 124 * Returns: 125 * IBT_SUCCESS on early validation of attributes else appropriate error. 126 * Description: 127 * Finds the best path to a specified destination or service 128 * asynchronously (as determined by the IBTL) that satisfies the 129 * requirements specified in an ibt_path_attr_t struct. 130 * ibt_aget_paths() is a Non-Blocking version of ibt_get_paths(). 131 */ 132 ibt_status_t 133 ibt_aget_paths(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags, 134 ibt_path_attr_t *attrp, uint8_t max_paths, ibt_path_handler_t func, 135 void *arg) 136 { 137 IBTF_DPRINTF_L3(cmlog, "ibt_aget_paths(%p, 0x%lX, %p, %d, %p)", 138 ibt_hdl, flags, attrp, max_paths, func); 139 140 if (func == NULL) { 141 IBTF_DPRINTF_L2(cmlog, "ibt_aget_paths: Function Pointer is " 142 "NULL - ERROR "); 143 return (IBT_INVALID_PARAM); 144 } 145 146 /* Memory for path info will be allocated in ibcm_process_get_paths() */ 147 return (ibcm_handle_get_path(attrp, flags, max_paths, NULL, NULL, 148 func, arg)); 149 } 150 151 152 /* 153 * ibt_get_paths() cache consists of one or more of: 154 * 155 * ib_gid_t dgid (attrp->pa_dgids[0]) 156 * ibt_path_attr_t attr 157 * ibt_path_flags_t flags 158 * ibt_path_info_t path 159 * 160 * If the first 3 match, max_paths is 1, sname is NULL, and sid is 0, 161 * then the path is returned immediately. 162 * 163 * Note that a compare of "attr" is non-trivial. Only accept ones 164 * that memcmp() succeeds, i.e., basically assume a bzero was done. 165 * 166 * Cache must be invalidated if PORT_DOWN event or GID_UNAVAIL occurs. 167 * Cache must be freed as part of _fini. 168 */ 169 170 #define IBCM_PATH_CACHE_SIZE 16 /* keep small for linear search */ 171 #define IBCM_PATH_CACHE_TIMEOUT 60 /* purge cache after 60 seconds */ 172 173 typedef struct ibcm_path_cache_s { 174 ib_gid_t dgid; 175 ibt_path_attr_t attr; 176 ibt_path_flags_t flags; 177 ibt_path_info_t path; 178 } ibcm_path_cache_t; 179 180 kmutex_t ibcm_path_cache_mutex; 181 int ibcm_path_cache_invalidate; /* invalidate cache on next ibt_get_paths */ 182 clock_t ibcm_path_cache_timeout = IBCM_PATH_CACHE_TIMEOUT; /* tunable */ 183 timeout_id_t ibcm_path_cache_timeout_id; 184 int ibcm_path_cache_size_init = IBCM_PATH_CACHE_SIZE; /* tunable */ 185 int ibcm_path_cache_size; 186 ibcm_path_cache_t *ibcm_path_cachep; 187 188 struct ibcm_path_cache_stat_s { 189 int hits; 190 int misses; 191 int adds; 192 int already_in_cache; 193 int bad_path_for_cache; 194 int purges; 195 int timeouts; 196 } ibcm_path_cache_stats; 197 198 /*ARGSUSED*/ 199 static void 200 ibcm_path_cache_timeout_cb(void *arg) 201 { 202 clock_t timeout_in_hz; 203 204 timeout_in_hz = drv_usectohz(ibcm_path_cache_timeout * 1000000); 205 mutex_enter(&ibcm_path_cache_mutex); 206 ibcm_path_cache_invalidate = 1; /* invalidate cache on next check */ 207 if (ibcm_path_cache_timeout_id) 208 ibcm_path_cache_timeout_id = timeout(ibcm_path_cache_timeout_cb, 209 NULL, timeout_in_hz); 210 /* else we're in _fini */ 211 mutex_exit(&ibcm_path_cache_mutex); 212 } 213 214 void 215 ibcm_path_cache_init(void) 216 { 217 clock_t timeout_in_hz; 218 int cache_size = ibcm_path_cache_size_init; 219 ibcm_path_cache_t *path_cachep; 220 221 timeout_in_hz = drv_usectohz(ibcm_path_cache_timeout * 1000000); 222 path_cachep = kmem_zalloc(cache_size * sizeof (*path_cachep), KM_SLEEP); 223 mutex_init(&ibcm_path_cache_mutex, NULL, MUTEX_DRIVER, NULL); 224 mutex_enter(&ibcm_path_cache_mutex); 225 ibcm_path_cache_size = cache_size; 226 ibcm_path_cachep = path_cachep; 227 ibcm_path_cache_timeout_id = timeout(ibcm_path_cache_timeout_cb, 228 NULL, timeout_in_hz); 229 mutex_exit(&ibcm_path_cache_mutex); 230 } 231 232 void 233 ibcm_path_cache_fini(void) 234 { 235 timeout_id_t tmp_timeout_id; 236 int cache_size; 237 ibcm_path_cache_t *path_cachep; 238 239 mutex_enter(&ibcm_path_cache_mutex); 240 if (ibcm_path_cache_timeout_id) { 241 tmp_timeout_id = ibcm_path_cache_timeout_id; 242 ibcm_path_cache_timeout_id = 0; /* no more timeouts */ 243 } 244 cache_size = ibcm_path_cache_size; 245 path_cachep = ibcm_path_cachep; 246 mutex_exit(&ibcm_path_cache_mutex); 247 if (tmp_timeout_id) 248 (void) untimeout(tmp_timeout_id); 249 mutex_destroy(&ibcm_path_cache_mutex); 250 kmem_free(path_cachep, cache_size * sizeof (*path_cachep)); 251 } 252 253 static ibcm_status_t 254 ibcm_path_cache_check(ibt_path_flags_t flags, ibt_path_attr_t *attrp, 255 uint8_t max_paths, ibt_path_info_t *path, uint8_t *num_paths_p) 256 { 257 int i; 258 ib_gid_t dgid; 259 ibcm_path_cache_t *path_cachep; 260 261 if (max_paths != 1 || attrp->pa_num_dgids != 1 || 262 attrp->pa_sname != NULL || attrp->pa_sid != 0) { 263 mutex_enter(&ibcm_path_cache_mutex); 264 ibcm_path_cache_stats.bad_path_for_cache++; 265 mutex_exit(&ibcm_path_cache_mutex); 266 return (IBCM_FAILURE); 267 } 268 269 dgid = attrp->pa_dgids[0]; 270 if ((dgid.gid_guid | dgid.gid_prefix) == 0ULL) 271 return (IBCM_FAILURE); 272 273 mutex_enter(&ibcm_path_cache_mutex); 274 if (ibcm_path_cache_invalidate) { /* invalidate all entries */ 275 ibcm_path_cache_stats.timeouts++; 276 ibcm_path_cache_invalidate = 0; 277 path_cachep = ibcm_path_cachep; 278 for (i = 0; i < ibcm_path_cache_size; i++, path_cachep++) { 279 path_cachep->dgid.gid_guid = 0ULL; 280 path_cachep->dgid.gid_prefix = 0ULL; 281 } 282 mutex_exit(&ibcm_path_cache_mutex); 283 return (IBCM_FAILURE); 284 } 285 286 path_cachep = ibcm_path_cachep; 287 for (i = 0; i < ibcm_path_cache_size; i++, path_cachep++) { 288 if (path_cachep->dgid.gid_guid == 0ULL) 289 break; /* end of search, no more valid cache entries */ 290 291 /* make pa_dgids pointers match, so we can use memcmp */ 292 path_cachep->attr.pa_dgids = attrp->pa_dgids; 293 if (path_cachep->flags != flags || 294 path_cachep->dgid.gid_guid != dgid.gid_guid || 295 path_cachep->dgid.gid_prefix != dgid.gid_prefix || 296 memcmp(&(path_cachep->attr), attrp, sizeof (*attrp)) != 0) { 297 /* make pa_dgids NULL again */ 298 path_cachep->attr.pa_dgids = NULL; 299 continue; 300 } 301 /* else we have a match */ 302 /* make pa_dgids NULL again */ 303 path_cachep->attr.pa_dgids = NULL; 304 *path = path_cachep->path; /* retval */ 305 if (num_paths_p) 306 *num_paths_p = 1; /* retval */ 307 ibcm_path_cache_stats.hits++; 308 mutex_exit(&ibcm_path_cache_mutex); 309 return (IBCM_SUCCESS); 310 } 311 ibcm_path_cache_stats.misses++; 312 mutex_exit(&ibcm_path_cache_mutex); 313 return (IBCM_FAILURE); 314 } 315 316 static void 317 ibcm_path_cache_add(ibt_path_flags_t flags, 318 ibt_path_attr_t *attrp, uint8_t max_paths, ibt_path_info_t *path) 319 { 320 int i; 321 ib_gid_t dgid; 322 ibcm_path_cache_t *path_cachep; 323 324 if (max_paths != 1 || attrp->pa_num_dgids != 1 || 325 attrp->pa_sname != NULL || attrp->pa_sid != 0) 326 return; 327 328 dgid = attrp->pa_dgids[0]; 329 if ((dgid.gid_guid | dgid.gid_prefix) == 0ULL) 330 return; 331 332 mutex_enter(&ibcm_path_cache_mutex); 333 path_cachep = ibcm_path_cachep; 334 for (i = 0; i < ibcm_path_cache_size; i++, path_cachep++) { 335 path_cachep->attr.pa_dgids = attrp->pa_dgids; 336 if (path_cachep->flags == flags && 337 path_cachep->dgid.gid_guid == dgid.gid_guid && 338 path_cachep->dgid.gid_prefix == dgid.gid_prefix && 339 memcmp(&(path_cachep->attr), attrp, sizeof (*attrp)) == 0) { 340 /* already in cache */ 341 ibcm_path_cache_stats.already_in_cache++; 342 path_cachep->attr.pa_dgids = NULL; 343 mutex_exit(&ibcm_path_cache_mutex); 344 return; 345 } 346 if (path_cachep->dgid.gid_guid != 0ULL) { 347 path_cachep->attr.pa_dgids = NULL; 348 continue; 349 } 350 /* else the rest of the entries are free, so use this one */ 351 ibcm_path_cache_stats.adds++; 352 path_cachep->flags = flags; 353 path_cachep->attr = *attrp; 354 path_cachep->attr.pa_dgids = NULL; 355 path_cachep->dgid = attrp->pa_dgids[0]; 356 path_cachep->path = *path; 357 mutex_exit(&ibcm_path_cache_mutex); 358 return; 359 } 360 mutex_exit(&ibcm_path_cache_mutex); 361 } 362 363 void 364 ibcm_path_cache_purge(void) 365 { 366 mutex_enter(&ibcm_path_cache_mutex); 367 ibcm_path_cache_invalidate = 1; /* invalidate cache on next check */ 368 ibcm_path_cache_stats.purges++; 369 mutex_exit(&ibcm_path_cache_mutex); 370 } 371 372 /* 373 * Function: 374 * ibt_get_paths 375 * Input: 376 * ibt_hdl The handle returned to the client by the IBTF from an 377 * ibt_attach() call. Can be used by the IBTF Policy module 378 * and CM in the determination of the "best" path to the 379 * specified destination for this class of driver. 380 * flags Path flags. 381 * attrp Points to an ibt_path_attr_t struct that contains 382 * required and optional attributes. 383 * max_paths The size of the "paths" array argument. Also, this 384 * is the limit on the number of paths returned. 385 * max_paths indicates the number of requested paths to 386 * the specified destination(s). 387 * Output: 388 * paths An array of ibt_path_info_t structs filled in by 389 * ibt_get_paths() as output parameters. Upon return, 390 * array elements with non-NULL HCA GUIDs are valid. 391 * num_paths_p If non-NULL, return the actual number of paths found. 392 * Returns: 393 * IBT_SUCCESS on Success else appropriate error. 394 * Description: 395 * Finds the best path to a specified destination (as determined by the 396 * IBTL) that satisfies the requirements specified in an ibt_path_attr_t 397 * struct. 398 * 399 * This routine can not be called from interrupt context. 400 */ 401 ibt_status_t 402 ibt_get_paths(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags, 403 ibt_path_attr_t *attrp, uint8_t max_paths, ibt_path_info_t *paths, 404 uint8_t *num_paths_p) 405 { 406 ibt_status_t retval; 407 408 ASSERT(paths != NULL); 409 410 IBTF_DPRINTF_L3(cmlog, "ibt_get_paths(%p, 0x%lX, %p, %d)", 411 ibt_hdl, flags, attrp, max_paths); 412 413 if (paths == NULL) { 414 IBTF_DPRINTF_L2(cmlog, "ibt_get_paths: Path Info Pointer is " 415 "NULL - ERROR "); 416 return (IBT_INVALID_PARAM); 417 } 418 419 if (num_paths_p != NULL) 420 *num_paths_p = 0; 421 422 if (ibcm_path_cache_check(flags, attrp, max_paths, paths, 423 num_paths_p) == IBCM_SUCCESS) 424 return (IBT_SUCCESS); 425 426 retval = ibcm_handle_get_path(attrp, flags, max_paths, paths, 427 num_paths_p, NULL, NULL); 428 429 if (retval == IBT_SUCCESS) 430 ibcm_path_cache_add(flags, attrp, max_paths, paths); 431 return (retval); 432 } 433 434 435 static ibt_status_t 436 ibcm_handle_get_path(ibt_path_attr_t *attrp, ibt_path_flags_t flags, 437 uint8_t max_paths, ibt_path_info_t *paths, uint8_t *num_path_p, 438 ibt_path_handler_t func, void *arg) 439 { 440 ibcm_path_tqargs_t *path_tq; 441 int sleep_flag = ((func == NULL) ? KM_SLEEP : KM_NOSLEEP); 442 int len; 443 ibt_status_t retval; 444 445 retval = ibcm_validate_path_attributes(attrp, flags, max_paths); 446 if (retval != IBT_SUCCESS) 447 return (retval); 448 449 len = (attrp->pa_num_dgids * sizeof (ib_gid_t)) + 450 sizeof (ibcm_path_tqargs_t); 451 452 path_tq = kmem_alloc(len, sleep_flag); 453 if (path_tq == NULL) { 454 IBTF_DPRINTF_L2(cmlog, "ibcm_handle_get_path: " 455 "Unable to allocate memory for local usage."); 456 return (IBT_INSUFF_KERNEL_RESOURCE); 457 } 458 459 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*path_tq)) 460 461 bcopy(attrp, &path_tq->attr, sizeof (ibt_path_attr_t)); 462 463 if (attrp->pa_num_dgids) { 464 path_tq->attr.pa_dgids = (ib_gid_t *)(((uchar_t *)path_tq) + 465 sizeof (ibcm_path_tqargs_t)); 466 467 bcopy(attrp->pa_dgids, path_tq->attr.pa_dgids, 468 sizeof (ib_gid_t) * attrp->pa_num_dgids); 469 } else { 470 path_tq->attr.pa_dgids = NULL; 471 } 472 473 /* Ignore IBT_PATH_AVAIL flag, if only one path is requested. */ 474 if ((flags & IBT_PATH_AVAIL) && (max_paths == 1)) { 475 flags &= ~IBT_PATH_AVAIL; 476 477 IBTF_DPRINTF_L4(cmlog, "ibcm_handle_get_path: " 478 "Ignoring IBT_PATH_AVAIL flag, as only ONE path " 479 "information is requested."); 480 } 481 482 path_tq->flags = flags; 483 path_tq->max_paths = max_paths; 484 path_tq->paths = paths; 485 path_tq->num_paths_p = num_path_p; 486 path_tq->func = func; 487 path_tq->arg = arg; 488 489 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*path_tq)) 490 491 if (func != NULL) { /* Non-Blocking */ 492 IBTF_DPRINTF_L3(cmlog, "ibcm_handle_get_path: Non Blocking"); 493 if (taskq_dispatch(ibcm_taskq, ibcm_process_async_get_paths, 494 path_tq, TQ_NOSLEEP) == 0) { 495 IBTF_DPRINTF_L2(cmlog, "ibcm_handle_get_path: " 496 "Failed to dispatch the TaskQ"); 497 kmem_free(path_tq, len); 498 return (IBT_INSUFF_KERNEL_RESOURCE); 499 } else 500 return (IBT_SUCCESS); 501 } else { /* Blocking */ 502 IBTF_DPRINTF_L3(cmlog, "ibcm_handle_get_path: Blocking"); 503 return (ibcm_process_get_paths(path_tq)); 504 } 505 } 506 507 508 static void 509 ibcm_process_async_get_paths(void *tq_arg) 510 { 511 (void) ibcm_process_get_paths(tq_arg); 512 } 513 514 515 static ibt_status_t 516 ibcm_validate_path_attributes(ibt_path_attr_t *attrp, ibt_path_flags_t flags, 517 uint8_t max_paths) 518 { 519 uint_t i; 520 521 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: Inputs are: " 522 "HCA (%llX, %d),\n\tSGID(%llX:%llX), SName=\"%s\",\n\tSID= %llX, " 523 "Maxpath= %d, Flags= 0x%X, #Dgid= %d, SDFlag= 0x%llX", 524 attrp->pa_hca_guid, attrp->pa_hca_port_num, 525 attrp->pa_sgid.gid_prefix, attrp->pa_sgid.gid_guid, 526 ((attrp->pa_sname != NULL) ? attrp->pa_sname : ""), attrp->pa_sid, 527 max_paths, flags, attrp->pa_num_dgids, attrp->pa_sd_flags); 528 529 /* 530 * Validate Path Flags. 531 * IBT_PATH_AVAIL & IBT_PATH_PERF are mutually exclusive. 532 */ 533 if ((flags & IBT_PATH_AVAIL) && (flags & IBT_PATH_PERF)) { 534 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: " 535 "Invalid Flags: 0x%X,\n\t AVAIL and PERF flags cannot " 536 "specified together.", flags); 537 return (IBT_INVALID_PARAM); 538 } 539 540 /* Validate number of records requested. */ 541 if ((flags & (IBT_PATH_AVAIL | IBT_PATH_PERF)) && 542 (max_paths > IBT_MAX_SPECIAL_PATHS)) { 543 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: " 544 "Max records that can be requested is <%d> \n" 545 "when IBT_PATH_AVAIL or IBT_PATH_PERF flag is specified.", 546 IBT_MAX_SPECIAL_PATHS); 547 return (IBT_INVALID_PARAM); 548 } 549 550 /* Only 2 destinations can be specified w/ APM flag. */ 551 if ((flags & IBT_PATH_APM) && (attrp->pa_num_dgids > 2)) { 552 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes:\n\t Max " 553 "number of DGIDs that can be specified w/APM flag is 2"); 554 return (IBT_INVALID_PARAM); 555 } 556 557 /* 558 * Max_paths of "0" is invalid. 559 * w/ IBT_PATH_MULTI_SVC_DEST flag, max_paths must be greater than "1". 560 */ 561 if ((max_paths == 0) || 562 ((flags & IBT_PATH_MULTI_SVC_DEST) && (max_paths < 2))) { 563 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: " 564 "Invalid number of records requested:\n flags 0x%X, " 565 "max_paths %d", flags, max_paths); 566 return (IBT_INVALID_PARAM); 567 } 568 569 /* 570 * If IBT_PATH_MULTI_SVC_DEST is set, then ServiceName and/or Service ID 571 * must be specified and DGIDs SHOULD NOT be specified. 572 */ 573 if ((flags & IBT_PATH_MULTI_SVC_DEST) && ((attrp->pa_num_dgids > 0) || 574 ((attrp->pa_sid == 0) && ((attrp->pa_sname == NULL) || 575 ((attrp->pa_sname != NULL) && (strlen(attrp->pa_sname) == 0)))))) { 576 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: " 577 "Invalid Flags: 0x%X, IBT_PATH_MULTI_SVC_DEST flag set " 578 "but Service Name \n or Service ID NOT specified or DGIDs " 579 "are specified.", flags); 580 return (IBT_INVALID_PARAM); 581 } 582 583 /* 584 * User need to specify the destination information, which can be 585 * provided as one or more of the following. 586 * o ServiceName 587 * o ServiceID 588 * o Array of DGIDs w/Num of DGIDs, (max of 2) 589 */ 590 if ((attrp->pa_sid == 0) && (attrp->pa_num_dgids == 0) && 591 ((attrp->pa_sname == NULL) || ((attrp->pa_sname != NULL) && 592 (strlen(attrp->pa_sname) == 0)))) { 593 /* Destination information not provided, bail out. */ 594 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: " 595 "Client's MUST supply DestInfo."); 596 return (IBT_INVALID_PARAM); 597 } 598 599 /* If DGIDs are provided, validate them. */ 600 if (attrp->pa_num_dgids > 0) { 601 if (attrp->pa_dgids == NULL) { 602 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: " 603 "pa_dgids NULL, but pa_num_dgids : %d", 604 attrp->pa_num_dgids); 605 return (IBT_INVALID_PARAM); 606 } 607 608 /* Validate DGIDs */ 609 for (i = 0; i < attrp->pa_num_dgids; i++) { 610 ib_gid_t gid = attrp->pa_dgids[i]; 611 612 IBTF_DPRINTF_L3(cmlog, "ibcm_validate_path_attributes: " 613 "DGID[%d] = %llX:%llX", i, gid.gid_prefix, 614 gid.gid_guid); 615 616 /* APM request for MultiCast destination is invalid. */ 617 if ((gid.gid_prefix >> 56ULL & 0xFF) == 0xFF) { 618 if (flags & IBT_PATH_APM) { 619 IBTF_DPRINTF_L2(cmlog, 620 "ibcm_validate_path_attributes: " 621 "APM for MGIDs not supported."); 622 return (IBT_INVALID_PARAM); 623 } 624 } else if ((gid.gid_prefix == 0) || 625 (gid.gid_guid == 0)) { 626 IBTF_DPRINTF_L2(cmlog, 627 "ibcm_validate_path_attributes: ERROR: " 628 "Invalid DGIDs specified"); 629 return (IBT_INVALID_PARAM); 630 } 631 } 632 } 633 634 /* Check for valid Service Name length. */ 635 if ((attrp->pa_sname != NULL) && 636 (strlen(attrp->pa_sname) >= IB_SVC_NAME_LEN)) { 637 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: " 638 "ServiceName too long"); 639 return (IBT_INVALID_PARAM); 640 } 641 642 /* If P_Key is specified, check for invalid p_key's */ 643 if (flags & IBT_PATH_PKEY) { 644 /* Limited P_Key is NOT supported as of now!. */ 645 if ((attrp->pa_pkey == IB_PKEY_INVALID_FULL) || 646 (attrp->pa_pkey & 0x8000) == 0) { 647 IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: " 648 "Specified P_Key is invalid: 0x%X", attrp->pa_pkey); 649 return (IBT_INVALID_PARAM); 650 } 651 IBTF_DPRINTF_L3(cmlog, "ibcm_validate_path_attributes: " 652 "P_Key= 0x%X", attrp->pa_pkey); 653 } 654 655 return (IBT_SUCCESS); 656 } 657 658 659 static ibt_status_t 660 ibcm_process_get_paths(void *tq_arg) 661 { 662 ibcm_path_tqargs_t *p_arg = (ibcm_path_tqargs_t *)tq_arg; 663 ibcm_dinfo_t *dinfo; 664 int len; 665 uint8_t max_paths, num_path; 666 ibt_status_t retval; 667 ib_gid_t *d_gids_p = NULL; 668 ibtl_cm_port_list_t *slistp = NULL; 669 uint_t dnum = 0, num_dest; 670 uint_t i, j; 671 ibcm_hca_info_t *hcap; 672 ibmf_saa_handle_t saa_handle; 673 674 IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths(%p, 0x%X, %d) ", 675 p_arg, p_arg->flags, p_arg->max_paths); 676 677 max_paths = num_path = p_arg->max_paths; 678 679 /* 680 * Prepare the Destination list based on the input DGIDs and 681 * other attributes. 682 * 683 * APM is requested and pa_dgids are specified. If multiple DGIDs are 684 * specified, check out whether they are companion to each other or if 685 * only one DGID is specified, then get the companion port GID for that. 686 */ 687 if (p_arg->attr.pa_num_dgids) { 688 if (p_arg->flags & IBT_PATH_APM) { 689 ib_gid_t c_gid, n_gid; 690 691 IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: " 692 "DGIDs specified w/ APM Flag"); 693 694 c_gid = p_arg->attr.pa_dgids[0]; 695 if (p_arg->attr.pa_num_dgids > 1) 696 n_gid = p_arg->attr.pa_dgids[1]; 697 else 698 n_gid.gid_prefix = n_gid.gid_guid = 0; 699 700 retval = ibcm_get_comp_pgids(c_gid, n_gid, 0, &d_gids_p, 701 &dnum); 702 if ((retval != IBT_SUCCESS) && 703 (retval != IBT_GIDS_NOT_FOUND)) { 704 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths:" 705 " Invalid DGIDs specified w/ APM Flag"); 706 goto path_error2; 707 } 708 IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: " 709 "Found %d Comp DGID", dnum); 710 } 711 712 if (dnum) { 713 len = 1; 714 } else { 715 len = p_arg->attr.pa_num_dgids - 1; 716 } 717 num_dest = len + 1; 718 719 IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: #dgid %d, dnum " 720 "%d, #dest %d", p_arg->attr.pa_num_dgids, dnum, num_dest); 721 } else { 722 if (p_arg->flags & IBT_PATH_MULTI_SVC_DEST) { 723 IBTF_DPRINTF_L4(cmlog, "ibcm_process_get_paths: " 724 "IBT_PATH_MULTI_SVC_DEST flags set"); 725 len = max_paths - 1; 726 } else if (p_arg->flags & IBT_PATH_APM) { 727 len = 1; 728 } else { 729 len = 0; 730 } 731 num_dest = 0; 732 } 733 734 /* Allocate memory and accumulate all destination information */ 735 len = (len * sizeof (ibcm_dest_t)) + sizeof (ibcm_dinfo_t); 736 737 dinfo = kmem_zalloc(len, KM_SLEEP); 738 dinfo->num_dest = num_dest; 739 if (p_arg->flags & IBT_PATH_PKEY) 740 dinfo->p_key = p_arg->attr.pa_pkey; 741 742 for (i = 0, j = 0; i < num_dest; i++) { 743 if (i < p_arg->attr.pa_num_dgids) 744 dinfo->dest[i].d_gid = p_arg->attr.pa_dgids[i]; 745 else 746 dinfo->dest[i].d_gid = d_gids_p[j++]; 747 } 748 749 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*p_arg)) 750 751 /* IBTF allocates memory for path_info in case of Async Get Paths */ 752 if (p_arg->paths == NULL) 753 p_arg->paths = kmem_zalloc(sizeof (ibt_path_info_t) * max_paths, 754 KM_SLEEP); 755 756 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*p_arg)) 757 758 /* Checkout whether user has specified SGID. */ 759 if (p_arg->attr.pa_sgid.gid_prefix && p_arg->attr.pa_sgid.gid_guid) { 760 ibtl_cm_hca_port_t hport; 761 762 IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: SGID %llX:%llX", 763 p_arg->attr.pa_sgid.gid_prefix, 764 p_arg->attr.pa_sgid.gid_guid); 765 766 /* For the specified SGID, get HCA information. */ 767 retval = ibtl_cm_get_hca_port(p_arg->attr.pa_sgid, 768 p_arg->attr.pa_hca_guid, &hport); 769 if (retval != IBT_SUCCESS) { 770 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: " 771 "Get HCA Port Failed: %d", retval); 772 goto path_error; 773 } 774 775 if ((p_arg->attr.pa_hca_port_num != 0) && 776 (p_arg->attr.pa_hca_port_num != hport.hp_port)) { 777 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: " 778 "Mis-match input HCA PortNum v/s SGID"); 779 retval = IBT_HCA_PORT_INVALID; 780 goto path_error; 781 } 782 783 /* 784 * If a specific MTU is desired, then first check out whether 785 * this source port is capable of this MTU. 786 */ 787 if (p_arg->attr.pa_mtu.r_mtu) { 788 if ((p_arg->attr.pa_mtu.r_selector == IBT_GT) && 789 (p_arg->attr.pa_mtu.r_mtu >= hport.hp_mtu)) { 790 791 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths:" 792 " Required MTU not available on this Port. " 793 "Requested IBT_GT 0x%x but avail 0x%x", 794 p_arg->attr.pa_mtu.r_mtu, hport.hp_mtu); 795 796 retval = IBT_INVALID_PARAM; 797 goto path_error; 798 } else if ((p_arg->attr.pa_mtu.r_selector == IBT_EQU) && 799 (p_arg->attr.pa_mtu.r_mtu > hport.hp_mtu)) { 800 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths:" 801 " Required MTU not available on this Port " 802 "Requested IBT_EQU to 0x%x but avail 0x%x", 803 p_arg->attr.pa_mtu.r_mtu, hport.hp_mtu); 804 805 retval = IBT_INVALID_PARAM; 806 goto path_error; 807 } 808 } 809 810 if (p_arg->flags & IBT_PATH_APM) { 811 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*p_arg)) 812 p_arg->attr.pa_hca_guid = hport.hp_hca_guid; 813 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*p_arg)) 814 815 retval = ibtl_cm_get_active_plist(&p_arg->attr, 816 p_arg->flags, &slistp); 817 if (retval != IBT_SUCCESS) { 818 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths:" 819 " ibtl_cm_get_active_plist returned error " 820 " %d", retval); 821 goto path_error; 822 } 823 } else { 824 slistp = kmem_zalloc(sizeof (ibtl_cm_port_list_t), 825 KM_SLEEP); 826 827 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*slistp)) 828 slistp->p_hca_guid = hport.hp_hca_guid; 829 slistp->p_mtu = hport.hp_mtu; 830 slistp->p_port_num = hport.hp_port; 831 slistp->p_base_lid = hport.hp_base_lid; 832 slistp->p_sgid = p_arg->attr.pa_sgid; 833 slistp->p_sgid_ix = hport.hp_sgid_ix; 834 slistp->p_count = 1; 835 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*slistp)) 836 } 837 } else { 838 /* Source GID is not specified, but so let's find them. */ 839 if (p_arg->attr.pa_hca_guid) 840 IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: Get " 841 "Paths from HCA (%llX)", p_arg->attr.pa_hca_guid); 842 else 843 IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: SRC " 844 "Point not specified, flags(%X)", p_arg->flags); 845 /* 846 * Get list of active HCA<->Port list, that matches input 847 * specified attr. 848 */ 849 retval = ibtl_cm_get_active_plist(&p_arg->attr, p_arg->flags, 850 &slistp); 851 if (retval != IBT_SUCCESS) { 852 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: " 853 "HCA capable of requested source attributes NOT " 854 "available."); 855 goto path_error; 856 } 857 } 858 859 IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: HCA (%llX, %d)", 860 slistp->p_hca_guid, slistp->p_port_num); 861 862 hcap = ibcm_find_hca_entry(slistp->p_hca_guid); 863 if (hcap == NULL) { 864 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: " 865 "NO HCA found"); 866 retval = IBT_HCA_BUSY_DETACHING; 867 goto path_error; 868 } 869 870 /* Get SA Access Handle. */ 871 for (i = 0; i < slistp->p_count; i++) { 872 if (i == 0) { 873 /* Validate whether this HCA supports APM */ 874 if ((p_arg->flags & IBT_PATH_APM) && 875 (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG))) { 876 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths:" 877 " HCA (%llX): APM NOT SUPPORTED ", 878 slistp[i].p_hca_guid); 879 retval = IBT_APM_NOT_SUPPORTED; 880 goto path_error1; 881 } 882 } 883 884 saa_handle = ibcm_get_saa_handle(hcap, slistp[i].p_port_num); 885 if (saa_handle == NULL) { 886 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: " 887 "SAA HDL NULL, HCA (%llX:%d) NOT ACTIVE", 888 slistp[i].p_hca_guid, slistp[i].p_port_num); 889 retval = IBT_HCA_PORT_NOT_ACTIVE; 890 goto path_error1; 891 } 892 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*slistp)) 893 slistp[i].p_saa_hdl = saa_handle; 894 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*slistp)) 895 } 896 897 /* 898 * If Service Name or Service ID are specified, first retrieve 899 * Service Records. 900 */ 901 if ((p_arg->attr.pa_sid != 0) || ((p_arg->attr.pa_sname != NULL) && 902 (strlen(p_arg->attr.pa_sname) != 0))) { 903 904 IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: Get Service " 905 "Record for \n\t(%llX, \"%s\")", p_arg->attr.pa_sid, 906 ((p_arg->attr.pa_sname != NULL) ? 907 p_arg->attr.pa_sname : "")); 908 909 /* Get Service Records. */ 910 retval = ibcm_saa_service_rec(p_arg, slistp, dinfo); 911 if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA)) { 912 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: Status=" 913 "%d, Failed to get Service Record for \n\t" 914 "(%llX, \"%s\")", retval, p_arg->attr.pa_sid, 915 ((p_arg->attr.pa_sname != NULL) ? 916 p_arg->attr.pa_sname : "")); 917 goto path_error1; 918 } 919 } 920 921 /* Get Path Records. */ 922 retval = ibcm_saa_path_rec(p_arg, slistp, dinfo, &num_path); 923 924 path_error1: 925 ibcm_dec_hca_acc_cnt(hcap); 926 927 path_error: 928 if (slistp) 929 ibtl_cm_free_active_plist(slistp); 930 931 if (dinfo) 932 kmem_free(dinfo, len); 933 934 path_error2: 935 if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA)) 936 num_path = 0; 937 938 if (p_arg->num_paths_p != NULL) 939 *p_arg->num_paths_p = num_path; 940 941 if ((dnum) && (d_gids_p)) 942 kmem_free(d_gids_p, dnum * sizeof (ib_gid_t)); 943 944 if (p_arg->func) { /* Do these only for Async Get Paths */ 945 ibt_path_info_t *tmp_path_p; 946 947 if (retval == IBT_INSUFF_DATA) { 948 /* 949 * We allocated earlier memory based on "max_paths", 950 * but we got lesser path-records, so re-adjust that 951 * buffer so that caller can free the correct memory. 952 */ 953 tmp_path_p = kmem_alloc( 954 sizeof (ibt_path_info_t) * num_path, KM_SLEEP); 955 956 bcopy(p_arg->paths, tmp_path_p, 957 num_path * sizeof (ibt_path_info_t)); 958 959 kmem_free(p_arg->paths, 960 sizeof (ibt_path_info_t) * max_paths); 961 } else if (retval != IBT_SUCCESS) { 962 if (p_arg->paths) 963 kmem_free(p_arg->paths, 964 sizeof (ibt_path_info_t) * max_paths); 965 tmp_path_p = NULL; 966 } else { 967 tmp_path_p = p_arg->paths; 968 } 969 (*(p_arg->func))(p_arg->arg, retval, tmp_path_p, num_path); 970 } 971 972 len = (sizeof (ib_gid_t) * p_arg->attr.pa_num_dgids) + 973 sizeof (ibcm_path_tqargs_t); 974 975 if (p_arg && len) 976 kmem_free(p_arg, len); 977 978 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: done: status %d, " 979 "Found %d/%d Path Records", retval, num_path, max_paths); 980 981 return (retval); 982 } 983 984 985 /* 986 * Perform SA Access to retrieve Path Records. 987 */ 988 static ibt_status_t 989 ibcm_saa_path_rec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl, 990 ibcm_dinfo_t *dinfo, uint8_t *max_count) 991 { 992 uint8_t num_path = *max_count; 993 uint8_t num_path_plus; 994 uint_t extra, idx, rec_found = 0; 995 ibt_status_t retval = IBT_SUCCESS; 996 int unicast_dgid_present = 0; 997 uint8_t i; 998 999 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec(%p, %p, %p, 0x%X, %d)", 1000 p_arg, sl, dinfo, p_arg->flags, *max_count); 1001 1002 if ((dinfo->num_dest == 0) || (num_path == 0) || (sl == NULL)) { 1003 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: Invalid Counters"); 1004 return (IBT_INVALID_PARAM); 1005 } 1006 1007 /* 1008 * Of the total needed "X" number of paths to "Y" number of destination 1009 * we need to get X/Y plus X%Y extra paths to each destination, 1010 * We do this so that we can choose the required number of path records 1011 * for the specific destination. 1012 */ 1013 num_path /= dinfo->num_dest; 1014 extra = (*max_count % dinfo->num_dest); 1015 1016 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: numpath %d extra %d dest %d", 1017 num_path, extra, dinfo->num_dest); 1018 1019 /* 1020 * Find out whether we need to get PathRecord for a MGID as DGID or 1021 * qualifies for a LoopBack. 1022 */ 1023 for (idx = 0; idx < dinfo->num_dest; idx++) { 1024 ib_gid_t dgid = dinfo->dest[idx].d_gid; 1025 1026 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: DGID[%d]: %llX:%llX", 1027 idx, dgid.gid_prefix, dgid.gid_guid); 1028 1029 if ((dgid.gid_prefix >> 56ULL & 0xFF) == 0xFF) { 1030 if (extra) 1031 num_path_plus = num_path + 1; 1032 else 1033 num_path_plus = num_path; 1034 1035 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: Get %d Paths" 1036 "- MGID(%016llX%016llX)", num_path_plus, 1037 dgid.gid_prefix, dgid.gid_guid); 1038 1039 dinfo->dest[idx].d_tag = 1; /* MultiCast */ 1040 1041 /* Yes, it's Single PathRec query for MGID as DGID. */ 1042 retval = ibcm_get_single_pathrec(p_arg, sl, dinfo, idx, 1043 &num_path_plus, &p_arg->paths[rec_found]); 1044 if ((retval != IBT_SUCCESS) && 1045 (retval != IBT_INSUFF_DATA)) { 1046 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: " 1047 "Failed to get PathRec for MGID %d", 1048 retval); 1049 continue; 1050 } 1051 if (extra) 1052 extra--; 1053 1054 rec_found += num_path_plus; 1055 } else { 1056 /* 1057 * Check out whether we are looking for loop-back path 1058 * info. In this case, we should not contact SA Access 1059 * for Path Records, but instead we need to "synthesize" 1060 * a loop back path record. 1061 */ 1062 for (i = 0; i < sl->p_count; i++) { 1063 if ((sl[i].p_sgid.gid_prefix == 1064 dgid.gid_prefix) && 1065 (sl[i].p_sgid.gid_guid == dgid.gid_guid)) { 1066 1067 dinfo->dest[idx].d_tag = 2; 1068 1069 /* Yes, it's loop back case. */ 1070 retval = ibcm_fillin_loopbackinfo( 1071 &sl[i], idx, dinfo, 1072 &p_arg->paths[rec_found]); 1073 if (retval != IBT_SUCCESS) 1074 break; 1075 1076 /* 1077 * We update only one record for 1078 * loop-back case. 1079 */ 1080 rec_found++; 1081 if (rec_found == *max_count) 1082 break; 1083 } 1084 } 1085 } 1086 if (rec_found == *max_count) 1087 break; 1088 } 1089 1090 for (i = 0; i < dinfo->num_dest; i++) { 1091 if (dinfo->dest[i].d_tag == 0) { 1092 unicast_dgid_present++; 1093 } 1094 } 1095 1096 num_path_plus = *max_count - rec_found; 1097 1098 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: Recfound: %d, need to find " 1099 "%d, UniCastGID present %d", rec_found, num_path_plus, 1100 unicast_dgid_present); 1101 1102 if ((unicast_dgid_present != 0) && (num_path_plus > 0)) { 1103 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: MultiSM=%X, #SRC=%d," 1104 "Dest%d", sl->p_multi, sl->p_count, unicast_dgid_present); 1105 1106 if ((sl->p_multi != IBTL_CM_SIMPLE_SETUP) || 1107 ((unicast_dgid_present == 1) && (sl->p_count == 1))) { 1108 /* 1109 * Use SinglePathRec if we are dealing w/ MultiSM or 1110 * request is for one SGID to one DGID. 1111 */ 1112 retval = ibcm_get_single_pathrec(p_arg, sl, dinfo, 0xFF, 1113 &num_path_plus, &p_arg->paths[rec_found]); 1114 } else { 1115 /* MultiPathRec will be used for other queries. */ 1116 retval = ibcm_get_multi_pathrec(p_arg, sl, dinfo, 1117 &num_path_plus, &p_arg->paths[rec_found]); 1118 } 1119 if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA)) { 1120 IBTF_DPRINTF_L2(cmlog, "ibcm_saa_path_rec: " 1121 "Failed to get PathRec: Status %d", retval); 1122 } else { 1123 rec_found += num_path_plus; 1124 } 1125 } 1126 1127 if ((rec_found == 0) && (retval == IBT_SUCCESS)) 1128 retval = IBT_PATH_RECORDS_NOT_FOUND; 1129 else if (rec_found != *max_count) 1130 retval = IBT_INSUFF_DATA; 1131 else if (rec_found != 0) 1132 retval = IBT_SUCCESS; 1133 1134 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: done. Status = %d, " 1135 "Found %d/%d Paths", retval, rec_found, *max_count); 1136 1137 *max_count = rec_found; /* Update the return count. */ 1138 1139 return (retval); 1140 } 1141 1142 ibt_status_t 1143 ibcm_contact_sa_access(ibmf_saa_handle_t saa_handle, 1144 ibmf_saa_access_args_t *access_args, size_t *length, void **results_p) 1145 { 1146 int retry; 1147 int sa_retval; 1148 1149 IBTF_DPRINTF_L3(cmlog, "ibcm_contact_sa_access(%p, %p)", 1150 saa_handle, access_args); 1151 1152 ibcm_sa_access_enter(); 1153 1154 for (retry = 0; retry < ibcm_max_sa_retries; retry++) { 1155 sa_retval = ibmf_sa_access(saa_handle, access_args, 0, 1156 length, results_p); 1157 if (sa_retval != IBMF_TRANS_TIMEOUT) 1158 break; 1159 1160 IBTF_DPRINTF_L2(cmlog, "ibcm_contact_sa_access: " 1161 "ibmf_sa_access() - Timed Out (%d)", sa_retval); 1162 delay(ibcm_sa_timeout_delay); 1163 } 1164 1165 ibcm_sa_access_exit(); 1166 1167 if ((sa_retval == IBMF_SUCCESS) || (sa_retval == IBMF_NO_RECORDS) || 1168 (sa_retval == IBMF_REQ_INVALID)) { 1169 IBTF_DPRINTF_L3(cmlog, "ibcm_contact_sa_access: " 1170 "ibmf_sa_access() returned (%d)", sa_retval); 1171 return (IBT_SUCCESS); 1172 } else { 1173 IBTF_DPRINTF_L2(cmlog, "ibcm_contact_sa_access: " 1174 "ibmf_sa_access(): Failed (%d)", sa_retval); 1175 return (ibcm_ibmf_analyze_error(sa_retval)); 1176 } 1177 } 1178 1179 1180 static ibt_status_t 1181 ibcm_update_pri(sa_path_record_t *pr_resp, ibtl_cm_port_list_t *sl, 1182 ibcm_dinfo_t *dinfo, ibt_path_info_t *paths) 1183 { 1184 ibt_status_t retval = IBT_SUCCESS; 1185 int d, s; 1186 1187 retval = ibcm_update_cep_info(pr_resp, sl, NULL, 1188 &paths->pi_prim_cep_path); 1189 if (retval != IBT_SUCCESS) 1190 return (retval); 1191 1192 /* Update some leftovers */ 1193 paths->pi_prim_pkt_lt = pr_resp->PacketLifeTime; 1194 paths->pi_path_mtu = pr_resp->Mtu; 1195 1196 for (d = 0; d < dinfo->num_dest; d++) { 1197 if (pr_resp->DGID.gid_guid == dinfo->dest[d].d_gid.gid_guid) { 1198 paths->pi_sid = dinfo->dest[d].d_sid; 1199 if (paths->pi_sid != 0) { 1200 bcopy(&dinfo->dest[d].d_sdata, 1201 &paths->pi_sdata, sizeof (ibt_srv_data_t)); 1202 } 1203 break; 1204 } 1205 } 1206 1207 for (s = 0; s < sl->p_count; s++) { 1208 if (pr_resp->SGID.gid_guid == sl[s].p_sgid.gid_guid) { 1209 paths->pi_hca_guid = sl[s].p_hca_guid; 1210 } 1211 } 1212 1213 /* Set Alternate Path to invalid state. */ 1214 paths->pi_alt_cep_path.cep_hca_port_num = 0; 1215 paths->pi_alt_cep_path.cep_adds_vect.av_dlid = 0; 1216 1217 IBTF_DPRINTF_L5(cmlog, "Path: HCA GUID = 0x%llX", paths->pi_hca_guid); 1218 IBTF_DPRINTF_L5(cmlog, "Path: ServiceID = 0x%llX", paths->pi_sid); 1219 1220 return (retval); 1221 } 1222 1223 1224 static ibt_status_t 1225 ibcm_get_single_pathrec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl, 1226 ibcm_dinfo_t *dinfo, uint8_t idx, uint8_t *num_path, ibt_path_info_t *paths) 1227 { 1228 sa_path_record_t pathrec_req; 1229 sa_path_record_t *pr_resp; 1230 ibmf_saa_access_args_t access_args; 1231 uint64_t c_mask = 0; 1232 void *results_p; 1233 uint8_t num_rec; 1234 size_t length; 1235 ibt_status_t retval; 1236 int i, j, k; 1237 int found, p_fnd; 1238 ibt_path_attr_t *attrp = &p_arg->attr; 1239 ibmf_saa_handle_t saa_handle; 1240 1241 IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec(%p, %p, %p, %d)", 1242 p_arg, sl, dinfo, *num_path); 1243 1244 bzero(&pathrec_req, sizeof (sa_path_record_t)); 1245 1246 /* Is Flow Label Specified. */ 1247 if (attrp->pa_flow) { 1248 pathrec_req.FlowLabel = attrp->pa_flow; 1249 c_mask |= SA_PR_COMPMASK_FLOWLABEL; 1250 } 1251 1252 /* Is HopLimit Specified. */ 1253 if (p_arg->flags & IBT_PATH_HOP) { 1254 pathrec_req.HopLimit = attrp->pa_hop; 1255 c_mask |= SA_PR_COMPMASK_HOPLIMIT; 1256 } 1257 1258 /* Is P_Key Specified. */ 1259 if (dinfo->p_key) { 1260 IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: " 1261 "Specified or Global PKEY 0x%X", dinfo->p_key); 1262 pathrec_req.P_Key = dinfo->p_key; 1263 c_mask |= SA_PR_COMPMASK_PKEY; 1264 } 1265 1266 /* Is TClass Specified. */ 1267 if (attrp->pa_tclass) { 1268 pathrec_req.TClass = attrp->pa_tclass; 1269 c_mask |= SA_PR_COMPMASK_TCLASS; 1270 } 1271 1272 /* Is SL specified. */ 1273 if (attrp->pa_sl) { 1274 pathrec_req.SL = attrp->pa_sl; 1275 c_mask |= SA_PR_COMPMASK_SL; 1276 } 1277 1278 /* If IBT_PATH_PERF is set, then mark all selectors to BEST. */ 1279 if (p_arg->flags & IBT_PATH_PERF) { 1280 pathrec_req.PacketLifeTimeSelector = IBT_BEST; 1281 pathrec_req.MtuSelector = IBT_BEST; 1282 pathrec_req.RateSelector = IBT_BEST; 1283 1284 c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR | 1285 SA_PR_COMPMASK_RATESELECTOR | SA_PR_COMPMASK_MTUSELECTOR; 1286 } else { 1287 if (attrp->pa_pkt_lt.p_selector == IBT_BEST) { 1288 pathrec_req.PacketLifeTimeSelector = IBT_BEST; 1289 c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR; 1290 } 1291 1292 if (attrp->pa_srate.r_selector == IBT_BEST) { 1293 pathrec_req.RateSelector = IBT_BEST; 1294 c_mask |= SA_PR_COMPMASK_RATESELECTOR; 1295 } 1296 1297 if (attrp->pa_mtu.r_selector == IBT_BEST) { 1298 pathrec_req.MtuSelector = IBT_BEST; 1299 c_mask |= SA_PR_COMPMASK_MTUSELECTOR; 1300 } 1301 } 1302 1303 /* 1304 * Honor individual selection of these attributes, 1305 * even if IBT_PATH_PERF is set. 1306 */ 1307 /* Check out whether Packet Life Time is specified. */ 1308 if (attrp->pa_pkt_lt.p_pkt_lt) { 1309 pathrec_req.PacketLifeTime = 1310 ibt_usec2ib(attrp->pa_pkt_lt.p_pkt_lt); 1311 pathrec_req.PacketLifeTimeSelector = 1312 attrp->pa_pkt_lt.p_selector; 1313 1314 c_mask |= SA_PR_COMPMASK_PKTLT | SA_PR_COMPMASK_PKTLTSELECTOR; 1315 } 1316 1317 /* Is SRATE specified. */ 1318 if (attrp->pa_srate.r_srate) { 1319 pathrec_req.Rate = attrp->pa_srate.r_srate; 1320 pathrec_req.RateSelector = attrp->pa_srate.r_selector; 1321 1322 c_mask |= SA_PR_COMPMASK_RATE | SA_PR_COMPMASK_RATESELECTOR; 1323 } 1324 1325 /* Is MTU specified. */ 1326 if (attrp->pa_mtu.r_mtu) { 1327 pathrec_req.Mtu = attrp->pa_mtu.r_mtu; 1328 pathrec_req.MtuSelector = attrp->pa_mtu.r_selector; 1329 1330 c_mask |= SA_PR_COMPMASK_MTU | SA_PR_COMPMASK_MTUSELECTOR; 1331 } 1332 1333 /* We always get REVERSIBLE paths. */ 1334 pathrec_req.Reversible = 1; 1335 c_mask |= SA_PR_COMPMASK_REVERSIBLE; 1336 1337 pathrec_req.NumbPath = *num_path; 1338 c_mask |= SA_PR_COMPMASK_NUMBPATH; 1339 1340 if (idx != 0xFF) { 1341 /* MGID */ 1342 pathrec_req.DGID = dinfo->dest[idx].d_gid; 1343 c_mask |= SA_PR_COMPMASK_DGID; 1344 } 1345 1346 p_fnd = found = 0; 1347 1348 for (i = 0; i < sl->p_count; i++) { 1349 /* SGID */ 1350 pathrec_req.SGID = sl[i].p_sgid; 1351 c_mask |= SA_PR_COMPMASK_SGID; 1352 saa_handle = sl[i].p_saa_hdl; 1353 1354 for (k = 0; k < dinfo->num_dest; k++) { 1355 if (idx == 0xFF) { /* DGID */ 1356 if (dinfo->dest[k].d_tag != 0) 1357 continue; 1358 1359 if (pathrec_req.SGID.gid_prefix != 1360 dinfo->dest[k].d_gid.gid_prefix) { 1361 IBTF_DPRINTF_L3(cmlog, 1362 "ibcm_get_single_pathrec: SGID_pfx=" 1363 "%llX, DGID_pfx=%llX doesn't match", 1364 pathrec_req.SGID.gid_prefix, 1365 dinfo->dest[k].d_gid.gid_prefix); 1366 continue; 1367 } else if (pathrec_req.SGID.gid_guid == 1368 pathrec_req.DGID.gid_guid) { 1369 IBTF_DPRINTF_L3(cmlog, 1370 "ibcm_get_single_pathrec: Why " 1371 "LoopBack request came here!!!! " 1372 "GID(%llX:%llX)", 1373 pathrec_req.SGID.gid_prefix, 1374 pathrec_req.SGID.gid_guid); 1375 continue; 1376 } 1377 1378 pathrec_req.DGID = dinfo->dest[k].d_gid; 1379 c_mask |= SA_PR_COMPMASK_DGID; 1380 1381 /* 1382 * If we had performed Service Look-up, then we 1383 * got P_Key from ServiceRecord, so get path 1384 * records that satisfy this particular P_Key. 1385 */ 1386 if ((dinfo->p_key == 0) && 1387 (dinfo->dest[k].d_pkey != 0)) { 1388 pathrec_req.P_Key = 1389 dinfo->dest[k].d_pkey; 1390 c_mask |= SA_PR_COMPMASK_PKEY; 1391 } 1392 } 1393 1394 IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: " 1395 "Get %d Path(s) between\n\tSGID(%llX:%llX) " 1396 "DGID(%llX:%llX)", pathrec_req.NumbPath, 1397 pathrec_req.SGID.gid_prefix, 1398 pathrec_req.SGID.gid_guid, 1399 pathrec_req.DGID.gid_prefix, 1400 pathrec_req.DGID.gid_guid); 1401 1402 IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: CMask" 1403 "=0x%llX, PKey=0x%X", c_mask, pathrec_req.P_Key); 1404 1405 /* Contact SA Access to retrieve Path Records. */ 1406 access_args.sq_attr_id = SA_PATHRECORD_ATTRID; 1407 access_args.sq_template = &pathrec_req; 1408 access_args.sq_access_type = IBMF_SAA_RETRIEVE; 1409 access_args.sq_template_length = 1410 sizeof (sa_path_record_t); 1411 access_args.sq_component_mask = c_mask; 1412 access_args.sq_callback = NULL; 1413 access_args.sq_callback_arg = NULL; 1414 1415 retval = ibcm_contact_sa_access(saa_handle, 1416 &access_args, &length, &results_p); 1417 if (retval != IBT_SUCCESS) { 1418 *num_path = 0; 1419 return (retval); 1420 } 1421 1422 num_rec = length / sizeof (sa_path_record_t); 1423 1424 IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: " 1425 "FOUND %d/%d path requested", num_rec, *num_path); 1426 1427 if ((results_p == NULL) || (num_rec == 0)) { 1428 if (idx != 0xFF) 1429 break; 1430 else 1431 continue; 1432 } 1433 1434 /* Update the PathInfo from the response. */ 1435 pr_resp = (sa_path_record_t *)results_p; 1436 for (j = 0; j < num_rec; j++, pr_resp++) { 1437 if ((p_fnd != 0) && 1438 (p_arg->flags & IBT_PATH_APM)) { 1439 IBTF_DPRINTF_L3(cmlog, 1440 "ibcm_get_single_pathrec: " 1441 "Fill Alternate Path"); 1442 retval = ibcm_update_cep_info(pr_resp, 1443 sl, NULL, 1444 &paths[found - 1].pi_alt_cep_path); 1445 if (retval != IBT_SUCCESS) 1446 continue; 1447 1448 /* Update some leftovers */ 1449 paths[found - 1].pi_alt_pkt_lt = 1450 pr_resp->PacketLifeTime; 1451 p_fnd = 0; 1452 } else { 1453 IBTF_DPRINTF_L3(cmlog, 1454 "ibcm_get_single_pathrec: " 1455 "Fill Primary Path"); 1456 1457 if (found == *num_path) 1458 break; 1459 1460 retval = ibcm_update_pri(pr_resp, sl, 1461 dinfo, &paths[found]); 1462 if (retval != IBT_SUCCESS) 1463 continue; 1464 p_fnd = 1; 1465 found++; 1466 } 1467 1468 } 1469 /* Deallocate the memory for results_p. */ 1470 kmem_free(results_p, length); 1471 1472 if (idx != 0xFF) 1473 break; /* We r here for MGID */ 1474 } 1475 if ((idx != 0xFF) && (found == *num_path)) 1476 break; /* We r here for MGID */ 1477 } 1478 1479 if (found == 0) 1480 retval = IBT_PATH_RECORDS_NOT_FOUND; 1481 else if (found != *num_path) 1482 retval = IBT_INSUFF_DATA; 1483 else 1484 retval = IBT_SUCCESS; 1485 1486 IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: done. Status %d, " 1487 "Found %d/%d Paths", retval, found, *num_path); 1488 1489 *num_path = found; 1490 1491 return (retval); 1492 } 1493 1494 1495 static ibt_status_t 1496 ibcm_get_multi_pathrec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl, 1497 ibcm_dinfo_t *dinfo, uint8_t *num_path, ibt_path_info_t *paths) 1498 { 1499 sa_multipath_record_t *mpr_req; 1500 sa_path_record_t *pr_resp; 1501 ibmf_saa_access_args_t access_args; 1502 void *results_p; 1503 uint64_t c_mask = 0; 1504 ib_gid_t *gid_ptr, *gid_s_ptr; 1505 size_t length; 1506 int template_len, found, num_rec; 1507 int i, k; 1508 ibt_status_t retval; 1509 uint8_t sgid_cnt, dgid_cnt; 1510 ibt_path_attr_t *attrp = &p_arg->attr; 1511 1512 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec(%p, %p, %p, %d)", 1513 attrp, sl, dinfo, *num_path); 1514 1515 for (i = 0, dgid_cnt = 0; i < dinfo->num_dest; i++) { 1516 if (dinfo->dest[i].d_tag == 0) 1517 dgid_cnt++; 1518 } 1519 1520 sgid_cnt = sl->p_count; 1521 1522 if ((sgid_cnt == 0) || (dgid_cnt == 0)) { 1523 IBTF_DPRINTF_L2(cmlog, "ibcm_get_multi_pathrec: sgid_cnt(%d) or" 1524 " dgid_cnt(%d) is zero", sgid_cnt, dgid_cnt); 1525 return (IBT_INVALID_PARAM); 1526 } 1527 1528 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: Get %d records between " 1529 "%d Src(s) <=> %d Dest(s)", *num_path, sgid_cnt, dgid_cnt); 1530 1531 /* 1532 * Calculate the size for multi-path records template, which includes 1533 * constant portion of the multipath record, plus variable size for 1534 * SGID (sgid_cnt) and DGID (dgid_cnt). 1535 */ 1536 template_len = ((dgid_cnt + sgid_cnt) * sizeof (ib_gid_t)) + 1537 sizeof (sa_multipath_record_t); 1538 1539 mpr_req = kmem_zalloc(template_len, KM_SLEEP); 1540 1541 ASSERT(mpr_req != NULL); 1542 1543 gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) + 1544 sizeof (sa_multipath_record_t)); 1545 1546 /* Get the starting pointer where GIDs are stored. */ 1547 gid_s_ptr = gid_ptr; 1548 1549 /* SGID */ 1550 for (i = 0; i < sl->p_count; i++) { 1551 *gid_ptr = sl[i].p_sgid; 1552 1553 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: SGID[%d] = " 1554 "(%llX:%llX)", i, gid_ptr->gid_prefix, gid_ptr->gid_guid); 1555 1556 gid_ptr++; 1557 } 1558 1559 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req)) 1560 1561 mpr_req->SGIDCount = sgid_cnt; 1562 c_mask = SA_MPR_COMPMASK_SGIDCOUNT; 1563 1564 /* DGIDs */ 1565 for (i = 0; i < dinfo->num_dest; i++) { 1566 if (dinfo->dest[i].d_tag == 0) { 1567 *gid_ptr = dinfo->dest[i].d_gid; 1568 1569 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: " 1570 "DGID[%d] = (%llX:%llX)", i, gid_ptr->gid_prefix, 1571 gid_ptr->gid_guid); 1572 gid_ptr++; 1573 } 1574 } 1575 1576 mpr_req->DGIDCount = dgid_cnt; 1577 c_mask |= SA_MPR_COMPMASK_DGIDCOUNT; 1578 1579 /* Is Flow Label Specified. */ 1580 if (attrp->pa_flow) { 1581 mpr_req->FlowLabel = attrp->pa_flow; 1582 c_mask |= SA_MPR_COMPMASK_FLOWLABEL; 1583 } 1584 1585 /* Is HopLimit Specified. */ 1586 if (p_arg->flags & IBT_PATH_HOP) { 1587 mpr_req->HopLimit = attrp->pa_hop; 1588 c_mask |= SA_MPR_COMPMASK_HOPLIMIT; 1589 } 1590 1591 /* Is TClass Specified. */ 1592 if (attrp->pa_tclass) { 1593 mpr_req->TClass = attrp->pa_tclass; 1594 c_mask |= SA_MPR_COMPMASK_TCLASS; 1595 } 1596 1597 /* Is SL specified. */ 1598 if (attrp->pa_sl) { 1599 mpr_req->SL = attrp->pa_sl; 1600 c_mask |= SA_MPR_COMPMASK_SL; 1601 } 1602 1603 if (p_arg->flags & IBT_PATH_PERF) { 1604 mpr_req->PacketLifeTimeSelector = IBT_BEST; 1605 mpr_req->RateSelector = IBT_BEST; 1606 mpr_req->MtuSelector = IBT_BEST; 1607 1608 c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR | 1609 SA_MPR_COMPMASK_RATESELECTOR | SA_MPR_COMPMASK_MTUSELECTOR; 1610 } else { 1611 if (attrp->pa_pkt_lt.p_selector == IBT_BEST) { 1612 mpr_req->PacketLifeTimeSelector = IBT_BEST; 1613 c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR; 1614 } 1615 1616 if (attrp->pa_srate.r_selector == IBT_BEST) { 1617 mpr_req->RateSelector = IBT_BEST; 1618 c_mask |= SA_MPR_COMPMASK_RATESELECTOR; 1619 } 1620 1621 if (attrp->pa_mtu.r_selector == IBT_BEST) { 1622 mpr_req->MtuSelector = IBT_BEST; 1623 c_mask |= SA_MPR_COMPMASK_MTUSELECTOR; 1624 } 1625 } 1626 1627 /* 1628 * Honor individual selection of these attributes, 1629 * even if IBT_PATH_PERF is set. 1630 */ 1631 /* Check out whether Packet Life Time is specified. */ 1632 if (attrp->pa_pkt_lt.p_pkt_lt) { 1633 mpr_req->PacketLifeTime = 1634 ibt_usec2ib(attrp->pa_pkt_lt.p_pkt_lt); 1635 mpr_req->PacketLifeTimeSelector = 1636 attrp->pa_pkt_lt.p_selector; 1637 1638 c_mask |= SA_MPR_COMPMASK_PKTLT | 1639 SA_MPR_COMPMASK_PKTLTSELECTOR; 1640 } 1641 1642 /* Is SRATE specified. */ 1643 if (attrp->pa_srate.r_srate) { 1644 mpr_req->Rate = attrp->pa_srate.r_srate; 1645 mpr_req->RateSelector = attrp->pa_srate.r_selector; 1646 1647 c_mask |= SA_MPR_COMPMASK_RATE | 1648 SA_MPR_COMPMASK_RATESELECTOR; 1649 } 1650 1651 /* Is MTU specified. */ 1652 if (attrp->pa_mtu.r_mtu) { 1653 mpr_req->Mtu = attrp->pa_mtu.r_mtu; 1654 mpr_req->MtuSelector = attrp->pa_mtu.r_selector; 1655 1656 c_mask |= SA_MPR_COMPMASK_MTU | 1657 SA_MPR_COMPMASK_MTUSELECTOR; 1658 } 1659 1660 /* Is P_Key Specified or obtained during Service Look-up. */ 1661 if (dinfo->p_key) { 1662 mpr_req->P_Key = dinfo->p_key; 1663 c_mask |= SA_MPR_COMPMASK_PKEY; 1664 } 1665 1666 /* We always get REVERSIBLE paths. */ 1667 mpr_req->Reversible = 1; 1668 c_mask |= SA_MPR_COMPMASK_REVERSIBLE; 1669 1670 if (p_arg->flags & IBT_PATH_AVAIL) { 1671 mpr_req->IndependenceSelector = 1; 1672 c_mask |= SA_MPR_COMPMASK_INDEPSEL; 1673 } 1674 1675 /* we will not specify how many records we want. */ 1676 1677 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req)) 1678 1679 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: CMask: %llX Pkey: %X", 1680 c_mask, mpr_req->P_Key); 1681 1682 /* Contact SA Access to retrieve Path Records. */ 1683 access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID; 1684 access_args.sq_access_type = IBMF_SAA_RETRIEVE; 1685 access_args.sq_component_mask = c_mask; 1686 access_args.sq_template = mpr_req; 1687 access_args.sq_template_length = sizeof (sa_multipath_record_t); 1688 access_args.sq_callback = NULL; 1689 access_args.sq_callback_arg = NULL; 1690 1691 retval = ibcm_contact_sa_access(sl->p_saa_hdl, &access_args, &length, 1692 &results_p); 1693 if (retval != IBT_SUCCESS) { 1694 *num_path = 0; /* Update the return count. */ 1695 kmem_free(mpr_req, template_len); 1696 return (retval); 1697 } 1698 1699 num_rec = length / sizeof (sa_path_record_t); 1700 1701 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: Found %d Paths", 1702 num_rec); 1703 1704 found = 0; 1705 if ((results_p != NULL) && (num_rec > 0)) { 1706 /* Update the PathInfo with the response Path Records */ 1707 pr_resp = (sa_path_record_t *)results_p; 1708 1709 for (i = 0; i < num_rec; i++) { 1710 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: " 1711 "P[%d]: SG %llX, DG %llX", i, 1712 pr_resp[i].SGID.gid_guid, pr_resp[i].DGID.gid_guid); 1713 } 1714 1715 if (p_arg->flags & IBT_PATH_APM) { 1716 sa_path_record_t *p_resp = NULL, *a_resp = NULL; 1717 int p_found = 0, a_found = 0; 1718 ib_gid_t p_sg, a_sg, p_dg, a_dg; 1719 int s_spec; 1720 1721 s_spec = p_arg->attr.pa_sgid.gid_guid != 0 ? 1 : 0; 1722 1723 p_sg = gid_s_ptr[0]; 1724 if (sgid_cnt > 1) 1725 a_sg = gid_s_ptr[1]; 1726 else 1727 a_sg = p_sg; 1728 1729 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: " 1730 "REQ: P_SG: %llX, A_SG: %llX", 1731 p_sg.gid_guid, a_sg.gid_guid); 1732 1733 p_dg = gid_s_ptr[sgid_cnt]; 1734 if (dgid_cnt > 1) 1735 a_dg = gid_s_ptr[sgid_cnt + 1]; 1736 else 1737 a_dg = p_dg; 1738 1739 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: " 1740 "REQ: P_DG: %llX, A_DG: %llX", 1741 p_dg.gid_guid, a_dg.gid_guid); 1742 1743 /* 1744 * If SGID and/or DGID is specified by user, make sure 1745 * he gets his primary-path on those node points. 1746 */ 1747 for (i = 0; i < num_rec; i++, pr_resp++) { 1748 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec:" 1749 " PF %d, AF %d,\n\t\t P[%d] = SG: %llX, " 1750 "DG: %llX", p_found, a_found, i, 1751 pr_resp->SGID.gid_guid, 1752 pr_resp->DGID.gid_guid); 1753 1754 if ((!p_found) && 1755 (p_dg.gid_guid == pr_resp->DGID.gid_guid)) { 1756 IBTF_DPRINTF_L3(cmlog, 1757 "ibcm_get_multi_pathrec: " 1758 "Pri DGID Match.. "); 1759 if ((s_spec == 0) || (p_sg.gid_guid == 1760 pr_resp->SGID.gid_guid)) { 1761 p_found = 1; 1762 p_resp = pr_resp; 1763 IBTF_DPRINTF_L3(cmlog, 1764 "ibcm_get_multi_pathrec: " 1765 "Primary Path Found"); 1766 1767 if (a_found) 1768 break; 1769 else 1770 continue; 1771 } 1772 IBTF_DPRINTF_L3(cmlog, 1773 "ibcm_get_multi_pathrec:" 1774 "Pri SGID Don't Match.. "); 1775 } 1776 1777 if ((!a_found) && 1778 (a_dg.gid_guid == pr_resp->DGID.gid_guid)) { 1779 IBTF_DPRINTF_L3(cmlog, 1780 "ibcm_get_multi_pathrec:" 1781 "Alt DGID Match.. "); 1782 if ((s_spec == 0) || (a_sg.gid_guid == 1783 pr_resp->SGID.gid_guid)) { 1784 a_found = 1; 1785 a_resp = pr_resp; 1786 1787 IBTF_DPRINTF_L3(cmlog, 1788 "ibcm_get_multi_pathrec:" 1789 "Alternate Path Found "); 1790 1791 if (p_found) 1792 break; 1793 else 1794 continue; 1795 } 1796 IBTF_DPRINTF_L3(cmlog, 1797 "ibcm_get_multi_pathrec:" 1798 "Alt SGID Don't Match.. "); 1799 } 1800 } 1801 1802 if ((p_found == 0) && (a_found == 0)) { 1803 IBTF_DPRINTF_L2(cmlog, "ibcm_get_multi_pathrec:" 1804 " Path to desired node points NOT " 1805 "Available."); 1806 retval = IBT_PATH_RECORDS_NOT_FOUND; 1807 goto get_multi_pathrec_end; 1808 } 1809 1810 if ((p_resp == NULL) && (a_resp != NULL)) { 1811 p_resp = a_resp; 1812 a_resp = NULL; 1813 } 1814 1815 /* Fill in Primary Path */ 1816 retval = ibcm_update_pri(p_resp, sl, dinfo, 1817 &paths[found]); 1818 if (retval != IBT_SUCCESS) 1819 goto get_multi_pathrec_end; 1820 1821 /* Fill in Alternate Path */ 1822 if (a_resp != NULL) { 1823 /* a_resp will point to AltPathInfo buffer. */ 1824 retval = ibcm_update_cep_info(a_resp, sl, 1825 NULL, &paths[found].pi_alt_cep_path); 1826 if (retval != IBT_SUCCESS) 1827 goto get_multi_pathrec_end; 1828 1829 /* Update some leftovers */ 1830 paths[found].pi_alt_pkt_lt = 1831 a_resp->PacketLifeTime; 1832 } else { 1833 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec:" 1834 " Alternate Path NOT Available."); 1835 retval = IBT_INSUFF_DATA; 1836 } 1837 found++; 1838 } else { /* If NOT APM */ 1839 boolean_t check_pkey = B_FALSE; 1840 1841 /* mark flag whether to validate PKey or not. */ 1842 if ((dinfo->p_key == 0) && (dinfo->dest[0].d_pkey != 0)) 1843 check_pkey = B_TRUE; 1844 1845 for (i = 0; i < num_rec; i++, pr_resp++) { 1846 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec:" 1847 " PKeyCheck - %s, PKey=0x%X, DGID(%llX)", 1848 ((check_pkey == B_TRUE)?"REQD":"NOT_REQD"), 1849 pr_resp->P_Key, pr_resp->DGID.gid_guid); 1850 1851 if (check_pkey == B_TRUE) { 1852 boolean_t match_found = B_FALSE; 1853 1854 /* For all DGIDs */ 1855 for (k = 0; k < dinfo->num_dest; k++) { 1856 if (dinfo->dest[k].d_tag != 0) 1857 continue; 1858 1859 if ((dinfo->dest[k].d_gid. 1860 gid_guid == 1861 pr_resp->DGID.gid_guid) && 1862 (dinfo->dest[k].d_pkey == 1863 pr_resp->P_Key)) { 1864 match_found = B_TRUE; 1865 break; 1866 } 1867 } 1868 if (match_found == B_FALSE) 1869 continue; 1870 } 1871 /* Fill in Primary Path */ 1872 retval = ibcm_update_pri(pr_resp, sl, dinfo, 1873 &paths[found]); 1874 if (retval != IBT_SUCCESS) 1875 continue; 1876 1877 if (++found == *num_path) 1878 break; 1879 } 1880 } 1881 get_multi_pathrec_end: 1882 kmem_free(results_p, length); 1883 } 1884 kmem_free(mpr_req, template_len); 1885 1886 if (found == 0) 1887 retval = IBT_PATH_RECORDS_NOT_FOUND; 1888 else if (found != *num_path) 1889 retval = IBT_INSUFF_DATA; 1890 else 1891 retval = IBT_SUCCESS; 1892 1893 IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: Done (status %d). " 1894 "Found %d/%d Paths", retval, found, *num_path); 1895 1896 *num_path = found; /* Update the return count. */ 1897 1898 return (retval); 1899 } 1900 1901 1902 /* 1903 * Here we "synthesize" loop back path record information. 1904 * 1905 * Currently the synthesize values are assumed as follows: 1906 * SLID, DLID = Base LID from Query HCA Port. 1907 * FlowLabel, HopLimit, TClass = 0, as GRH is False. 1908 * RawTraffic = 0. 1909 * P_Key = first valid one in P_Key table as obtained from Query HCA Port. 1910 * SL = as from Query HCA Port. 1911 * MTU = from Query HCA Port. 1912 * Rate = 2 (arbitrary). 1913 * PacketLifeTime = 0 (4.096 usec). 1914 */ 1915 static ibt_status_t 1916 ibcm_fillin_loopbackinfo(ibtl_cm_port_list_t *sl, uint8_t index, 1917 ibcm_dinfo_t *dinfo, ibt_path_info_t *paths) 1918 { 1919 ibt_status_t retval; 1920 ib_pkey_t pkey = 0; 1921 1922 IBTF_DPRINTF_L3(cmlog, "ibcm_fillin_loopbackinfo(%p, %p)", sl, dinfo); 1923 1924 /* Synthesize path record with appropriate loop back information. */ 1925 if (dinfo->p_key) 1926 pkey = dinfo->p_key; 1927 else 1928 pkey = dinfo->dest[index].d_pkey; 1929 if (pkey) { 1930 /* Convert P_Key to P_Key_Index */ 1931 retval = ibt_pkey2index_byguid(sl->p_hca_guid, sl->p_port_num, 1932 pkey, &paths->pi_prim_cep_path.cep_pkey_ix); 1933 if (retval != IBT_SUCCESS) { 1934 /* Failed to get pkey_index from pkey */ 1935 IBTF_DPRINTF_L2(cmlog, "ibcm_fillin_loopbackinfo: " 1936 "Pkey2Index (P_Key = %X) conversion failed: %d", 1937 pkey, retval); 1938 return (retval); 1939 } 1940 } else { 1941 paths->pi_prim_cep_path.cep_pkey_ix = 1942 ibtl_cm_get_1st_full_pkey_ix(sl->p_hca_guid, 1943 sl->p_port_num); 1944 IBTF_DPRINTF_L3(cmlog, "ibcm_fillin_loopbackinfo: " 1945 "1st Full Member P_Key_ix = %d", 1946 paths->pi_prim_cep_path.cep_pkey_ix); 1947 } 1948 1949 paths->pi_hca_guid = sl->p_hca_guid; 1950 paths->pi_prim_cep_path.cep_adds_vect.av_dgid = 1951 dinfo->dest[index].d_gid; 1952 paths->pi_prim_cep_path.cep_adds_vect.av_sgid = sl->p_sgid; 1953 paths->pi_prim_cep_path.cep_adds_vect.av_srate = IBT_SRATE_1X; 1954 paths->pi_prim_cep_path.cep_adds_vect.av_srvl = 0; /* SL */ 1955 1956 paths->pi_prim_cep_path.cep_adds_vect.av_send_grh = B_FALSE; 1957 paths->pi_prim_cep_path.cep_adds_vect.av_flow = 0; 1958 paths->pi_prim_cep_path.cep_adds_vect.av_tclass = 0; 1959 paths->pi_prim_cep_path.cep_adds_vect.av_hop = 0; 1960 1961 /* SLID and DLID will be equal to BLID. */ 1962 paths->pi_prim_cep_path.cep_adds_vect.av_dlid = sl->p_base_lid; 1963 paths->pi_prim_cep_path.cep_adds_vect.av_src_path = 0; 1964 paths->pi_prim_cep_path.cep_adds_vect.av_sgid_ix = sl->p_sgid_ix; 1965 paths->pi_prim_cep_path.cep_adds_vect.av_port_num = 1966 paths->pi_prim_cep_path.cep_hca_port_num = sl->p_port_num; 1967 paths->pi_prim_cep_path.cep_timeout = 0; /* To be filled in by CM. */ 1968 paths->pi_path_mtu = sl->p_mtu; /* MTU */ 1969 paths->pi_prim_pkt_lt = 0; /* Packet Life Time. */ 1970 paths->pi_alt_pkt_lt = 0; /* Packet Life Time. */ 1971 1972 paths->pi_sid = dinfo->dest[index].d_sid; 1973 1974 if (paths->pi_sid != 0) 1975 bcopy(&dinfo->dest[index].d_sdata, &paths->pi_sdata, 1976 sizeof (ibt_srv_data_t)); 1977 1978 IBTF_DPRINTF_L3(cmlog, "ibcm_fillin_loopbackinfo: HCA %llX:%d SID %llX" 1979 "\n\t SGID %llX:%llX DGID %llX:%llX", paths->pi_hca_guid, 1980 paths->pi_prim_cep_path.cep_hca_port_num, paths->pi_sid, 1981 sl->p_sgid.gid_prefix, sl->p_sgid.gid_guid, 1982 dinfo->dest[index].d_gid.gid_prefix, 1983 dinfo->dest[index].d_gid.gid_guid); 1984 1985 /* Set Alternate Path to invalid state. */ 1986 paths->pi_alt_cep_path.cep_hca_port_num = 0; 1987 paths->pi_alt_cep_path.cep_adds_vect.av_dlid = 0; 1988 1989 return (IBT_SUCCESS); 1990 } 1991 1992 1993 /* 1994 * Update the output path records buffer with the values as obtained from 1995 * SA Access retrieve call results for Path Records. 1996 */ 1997 static ibt_status_t 1998 ibcm_update_cep_info(sa_path_record_t *prec_resp, ibtl_cm_port_list_t *sl, 1999 ibtl_cm_hca_port_t *hport, ibt_cep_path_t *cep_p) 2000 { 2001 ibt_status_t retval; 2002 int i; 2003 2004 IBCM_DUMP_PATH_REC(prec_resp); 2005 2006 /* 2007 * If path's packet life time is more than 4 seconds, IBCM cannot 2008 * handle this path connection, so discard this path record. 2009 */ 2010 if (prec_resp->PacketLifeTime > ibcm_max_ib_pkt_lt) { 2011 IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: Path's Packet " 2012 "LifeTime too high %d, Maximum allowed %d IB Time (4 sec)", 2013 prec_resp->PacketLifeTime, ibcm_max_ib_pkt_lt); 2014 return (ibt_get_module_failure(IBT_FAILURE_IBSM, 0)); 2015 } 2016 2017 if ((prec_resp->Mtu > IB_MTU_4K) || (prec_resp->Mtu < IB_MTU_256)) { 2018 IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: MTU (%d) from " 2019 "pathrecord is invalid, reject it.", prec_resp->Mtu); 2020 return (ibt_get_module_failure(IBT_FAILURE_IBSM, 0)); 2021 } 2022 2023 /* Source Node Information. */ 2024 cep_p->cep_adds_vect.av_sgid = prec_resp->SGID; 2025 if (hport != NULL) { 2026 /* Convert P_Key to P_Key_Index */ 2027 retval = ibt_pkey2index_byguid(hport->hp_hca_guid, 2028 hport->hp_port, prec_resp->P_Key, &cep_p->cep_pkey_ix); 2029 if (retval != IBT_SUCCESS) { 2030 /* Failed to get pkey_index from pkey */ 2031 IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: " 2032 "Pkey2Index conversion failed: %d", retval); 2033 return (ibt_get_module_failure(IBT_FAILURE_IBSM, 0)); 2034 } 2035 cep_p->cep_adds_vect.av_sgid_ix = hport->hp_sgid_ix; 2036 cep_p->cep_adds_vect.av_src_path = 2037 prec_resp->SLID - hport->hp_base_lid; 2038 cep_p->cep_adds_vect.av_port_num = cep_p->cep_hca_port_num = 2039 hport->hp_port; 2040 } else if (sl != NULL) { 2041 for (i = 0; i < sl->p_count; i++) { 2042 if (prec_resp->SGID.gid_guid == sl[i].p_sgid.gid_guid) { 2043 /* Convert P_Key to P_Key_Index */ 2044 retval = ibt_pkey2index_byguid(sl[i].p_hca_guid, 2045 sl[i].p_port_num, prec_resp->P_Key, 2046 &cep_p->cep_pkey_ix); 2047 if (retval != IBT_SUCCESS) { 2048 /* Failed to get pkey_index from pkey */ 2049 IBTF_DPRINTF_L2(cmlog, 2050 "ibcm_update_cep_info: Pkey2Index " 2051 "conversion failed: %d", retval); 2052 return (ibt_get_module_failure( 2053 IBT_FAILURE_IBSM, 0)); 2054 } 2055 2056 cep_p->cep_adds_vect.av_sgid_ix = 2057 sl[i].p_sgid_ix; 2058 cep_p->cep_adds_vect.av_src_path = 2059 prec_resp->SLID - sl[i].p_base_lid; 2060 cep_p->cep_adds_vect.av_port_num = 2061 sl[i].p_port_num; 2062 cep_p->cep_hca_port_num = sl[i].p_port_num; 2063 2064 break; 2065 } 2066 } 2067 } else { 2068 IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: Sl or Hport " 2069 "must be non-null"); 2070 return (IBT_INVALID_PARAM); 2071 } 2072 2073 switch (prec_resp->Rate) { 2074 case IBT_SRATE_1X: 2075 case IBT_SRATE_4X: 2076 case IBT_SRATE_12X: 2077 cep_p->cep_adds_vect.av_srate = prec_resp->Rate; 2078 break; 2079 default: 2080 IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: SRate (%d) from " 2081 "pathrecord is invalid, reject it.", prec_resp->Rate); 2082 return (ibt_get_module_failure(IBT_FAILURE_IBSM, 0)); 2083 } 2084 /* 2085 * If both Source and Destination GID prefix are same, then GRH is not 2086 * valid, so make it as false, else set this field as true. 2087 */ 2088 if (prec_resp->SGID.gid_prefix == prec_resp->DGID.gid_prefix) 2089 cep_p->cep_adds_vect.av_send_grh = B_FALSE; 2090 else 2091 cep_p->cep_adds_vect.av_send_grh = B_TRUE; 2092 2093 /* SGID and SGID Index. */ 2094 cep_p->cep_adds_vect.av_sgid = prec_resp->SGID; 2095 cep_p->cep_adds_vect.av_flow = prec_resp->FlowLabel; 2096 cep_p->cep_adds_vect.av_tclass = prec_resp->TClass; 2097 cep_p->cep_adds_vect.av_hop = prec_resp->HopLimit; 2098 2099 /* Address Vector Definition. */ 2100 cep_p->cep_adds_vect.av_dlid = prec_resp->DLID; 2101 cep_p->cep_adds_vect.av_srvl = prec_resp->SL; 2102 2103 /* DGID */ 2104 cep_p->cep_adds_vect.av_dgid = prec_resp->DGID; 2105 2106 /* CEP Timeout is NOT filled in by PATH routines. */ 2107 cep_p->cep_timeout = 0; 2108 2109 IBTF_DPRINTF_L3(cmlog, "ibcm_update_cep_info: Done. Port[%d]\n" 2110 "SGID=%llX:%llX DGID=%llX:%llX", 2111 cep_p->cep_adds_vect.av_port_num, 2112 prec_resp->SGID.gid_prefix, prec_resp->SGID.gid_guid, 2113 prec_resp->DGID.gid_prefix, prec_resp->DGID.gid_guid); 2114 2115 return (IBT_SUCCESS); 2116 } 2117 2118 2119 static void 2120 ibcm_fill_svcinfo(sa_service_record_t *sr_resp, ibcm_dest_t *dest) 2121 { 2122 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dest)) 2123 2124 dest->d_gid = sr_resp->ServiceGID; 2125 dest->d_sid = sr_resp->ServiceID; 2126 ibcm_swizzle_to_srv(sr_resp->ServiceData, &dest->d_sdata); 2127 dest->d_pkey = sr_resp->ServiceP_Key; 2128 2129 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*dest)) 2130 2131 IBTF_DPRINTF_L3(cmlog, "ibcm_fill_svcinfo: SID(%llX), GID(%llX:%llX)" 2132 "\n\tSvcPKey 0x%X", dest->d_sid, dest->d_gid.gid_prefix, 2133 dest->d_gid.gid_guid, dest->d_pkey); 2134 } 2135 2136 2137 static ib_gid_t 2138 ibcm_saa_get_agid(ibtl_cm_port_list_t *sl, ib_gid_t *gidp, uint_t ngid) 2139 { 2140 int k, l; 2141 ib_gid_t a_gid; 2142 2143 a_gid.gid_prefix = a_gid.gid_guid = 0; 2144 2145 for (k = 0; k < sl->p_count; k++) { 2146 for (l = 0; l < ngid; l++) { 2147 2148 if (gidp->gid_prefix == sl->p_sgid.gid_prefix) { 2149 a_gid = *gidp; 2150 break; 2151 } 2152 if (a_gid.gid_guid && a_gid.gid_prefix) 2153 break; 2154 gidp++; 2155 } 2156 if (a_gid.gid_guid && a_gid.gid_prefix) 2157 break; 2158 sl++; 2159 } 2160 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_get_agid: AltGID = %llX:%llX", 2161 a_gid.gid_prefix, a_gid.gid_guid); 2162 2163 return (a_gid); 2164 } 2165 2166 /* 2167 * Perform SA Access to retrieve Service Records. 2168 * On Success, returns ServiceID and ServiceGID info in '*dinfo'. 2169 */ 2170 static ibt_status_t 2171 ibcm_saa_service_rec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl, 2172 ibcm_dinfo_t *dinfo) 2173 { 2174 sa_service_record_t svcrec_req; 2175 sa_service_record_t *svcrec_resp; 2176 void *results_p; 2177 uint64_t component_mask = 0; 2178 size_t length; 2179 uint8_t i, j, k, rec_found, s; 2180 ibmf_saa_access_args_t access_args; 2181 ibt_status_t retval; 2182 ibt_path_attr_t *attrp = &p_arg->attr; 2183 uint64_t tmp_sd_flag = attrp->pa_sd_flags; 2184 uint8_t num_req; 2185 2186 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec(%p, %p)", p_arg, sl); 2187 2188 bzero(&svcrec_req, sizeof (svcrec_req)); 2189 2190 /* Service Name */ 2191 if ((attrp->pa_sname != NULL) && (strlen(attrp->pa_sname) != 0)) { 2192 (void) strncpy((char *)(svcrec_req.ServiceName), 2193 attrp->pa_sname, IB_SVC_NAME_LEN); 2194 2195 component_mask |= SA_SR_COMPMASK_NAME; 2196 } 2197 2198 /* Service ID */ 2199 if (attrp->pa_sid) { 2200 svcrec_req.ServiceID = attrp->pa_sid; 2201 component_mask |= SA_SR_COMPMASK_ID; 2202 } 2203 2204 /* Is P_Key Specified. */ 2205 if (p_arg->flags & IBT_PATH_PKEY) { 2206 svcrec_req.ServiceP_Key = attrp->pa_pkey; 2207 component_mask |= SA_SR_COMPMASK_PKEY; 2208 } 2209 2210 /* Is ServiceData Specified. */ 2211 if (attrp->pa_sd_flags != IBT_NO_SDATA) { 2212 /* Handle endianess for service data. */ 2213 ibcm_swizzle_from_srv(&attrp->pa_sdata, svcrec_req.ServiceData); 2214 2215 /* 2216 * Lets not interpret each and every ServiceData flags, 2217 * just pass it on to SAA. Shift the flag, to suit 2218 * SA_SR_COMPMASK_ALL_DATA definition. 2219 */ 2220 component_mask |= (tmp_sd_flag << 7); 2221 } 2222 2223 if (dinfo->num_dest == 1) { 2224 2225 /* If a single DGID is specified, provide it */ 2226 svcrec_req.ServiceGID = dinfo->dest->d_gid; 2227 component_mask |= SA_SR_COMPMASK_GID; 2228 2229 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec:%llX:%llX", 2230 svcrec_req.ServiceGID.gid_prefix, 2231 svcrec_req.ServiceGID.gid_guid); 2232 } 2233 2234 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: " 2235 "Perform SA Access: Mask: 0x%X", component_mask); 2236 2237 /* 2238 * Call in SA Access retrieve routine to get Service Records. 2239 * 2240 * SA Access framework allocated memory for the "results_p". 2241 * Make sure to deallocate once we are done with the results_p. 2242 * The size of the buffer allocated will be as returned in 2243 * "length" field. 2244 */ 2245 access_args.sq_attr_id = SA_SERVICERECORD_ATTRID; 2246 access_args.sq_access_type = IBMF_SAA_RETRIEVE; 2247 access_args.sq_component_mask = component_mask; 2248 access_args.sq_template = &svcrec_req; 2249 access_args.sq_template_length = sizeof (sa_service_record_t); 2250 access_args.sq_callback = NULL; 2251 access_args.sq_callback_arg = NULL; 2252 2253 for (s = 0; s < sl->p_count; s++) { 2254 retval = ibcm_contact_sa_access(sl[s].p_saa_hdl, &access_args, 2255 &length, &results_p); 2256 if (retval != IBT_SUCCESS) 2257 if (sl[s].p_multi & IBTL_CM_MULTI_SM) 2258 continue; 2259 else 2260 return (retval); 2261 2262 if ((results_p == NULL) || (length == 0)) { 2263 IBTF_DPRINTF_L2(cmlog, "ibcm_saa_service_rec: SvcRec " 2264 "Not Found: res_p %p, len %d", results_p, length); 2265 if (sl[s].p_multi & IBTL_CM_MULTI_SM) { 2266 retval = IBT_SERVICE_RECORDS_NOT_FOUND; 2267 continue; 2268 } else 2269 return (IBT_SERVICE_RECORDS_NOT_FOUND); 2270 } 2271 2272 /* if we are here, we got some records. so break. */ 2273 break; 2274 } 2275 2276 if (retval != IBT_SUCCESS) 2277 return (retval); 2278 2279 num_req = length / sizeof (sa_service_record_t); 2280 2281 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Got %d Service Records.", 2282 num_req); 2283 2284 svcrec_resp = (sa_service_record_t *)results_p; 2285 rec_found = 0; 2286 2287 /* Update the return values. */ 2288 if (dinfo->num_dest) { 2289 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Get ServiceRec " 2290 "for Specified DGID: %d", dinfo->num_dest); 2291 2292 for (i = 0; i < num_req; i++, svcrec_resp++) { 2293 /* Limited P_Key is NOT supported as of now!. */ 2294 if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) { 2295 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: " 2296 "SvcPkey 0x%X limited, reject the record.", 2297 svcrec_resp->ServiceP_Key); 2298 continue; 2299 } 2300 2301 for (j = 0; j < dinfo->num_dest; j++) { 2302 if (dinfo->dest[j].d_gid.gid_guid == 2303 svcrec_resp->ServiceGID.gid_guid) { 2304 ibcm_fill_svcinfo(svcrec_resp, 2305 &dinfo->dest[j]); 2306 rec_found++; 2307 } 2308 if (rec_found == dinfo->num_dest) 2309 break; 2310 } 2311 if (rec_found == dinfo->num_dest) 2312 break; 2313 } 2314 if (rec_found != dinfo->num_dest) { 2315 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Did NOT " 2316 "find ServiceRec for all DGIDs: (%d/%d)", rec_found, 2317 dinfo->num_dest); 2318 retval = IBT_INSUFF_DATA; 2319 } 2320 } else if (p_arg->flags & IBT_PATH_APM) { 2321 ib_gid_t p_gid, a_gid, last_p_gid; 2322 ib_gid_t *gidp = NULL; 2323 uint_t n_gids; 2324 sa_service_record_t *stmp; 2325 boolean_t pri_fill_done = B_FALSE; 2326 boolean_t alt_fill_done = B_FALSE; 2327 ib_pkey_t p_pkey = 0, a_pkey = 0; 2328 2329 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Need to " 2330 "find ServiceRec that can satisfy APM"); 2331 2332 p_gid.gid_prefix = p_gid.gid_guid = 0; 2333 a_gid.gid_prefix = a_gid.gid_guid = 0; 2334 last_p_gid.gid_prefix = last_p_gid.gid_guid = 0; 2335 2336 for (i = 0; i < num_req; i++, svcrec_resp++) { 2337 ibt_status_t ret; 2338 boolean_t local_node_check_done = B_FALSE; 2339 2340 /* Limited P_Key is NOT supported as of now!. */ 2341 if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) { 2342 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: " 2343 "SvcPkey 0x%X limited, reject the record.", 2344 svcrec_resp->ServiceP_Key); 2345 continue; 2346 } 2347 2348 p_gid = svcrec_resp->ServiceGID; 2349 2350 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: " 2351 "Let DGID(%llX:%llX) be Primary", 2352 p_gid.gid_prefix, p_gid.gid_guid); 2353 2354 /* Let's avoid LoopBack Nodes. */ 2355 if (p_gid.gid_guid == sl->p_sgid.gid_guid) { 2356 local_node_check_done = B_TRUE; 2357 2358 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: " 2359 "Lets Avoid Local Node, " 2360 "search for remote node."); 2361 } 2362 2363 if (local_node_check_done == B_TRUE) { 2364 if ((i + 1) < num_req) { 2365 p_gid.gid_prefix = 0; 2366 p_gid.gid_guid = 0; 2367 continue; 2368 } else if (last_p_gid.gid_prefix != 0) { 2369 p_gid = last_p_gid; 2370 break; 2371 } 2372 } 2373 2374 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: " 2375 "Finally let Primary DGID = %llX:%llX", 2376 p_gid.gid_prefix, p_gid.gid_guid); 2377 2378 ret = ibt_get_companion_port_gids(p_gid, 0, 0, 2379 &gidp, &n_gids); 2380 if (ret == IBT_SUCCESS) { 2381 IBTF_DPRINTF_L3(cmlog, 2382 "ibcm_saa_service_rec: Found %d " 2383 "CompGID for %llX:%llX", n_gids, 2384 p_gid.gid_prefix, p_gid.gid_guid); 2385 2386 stmp = (sa_service_record_t *)results_p; 2387 a_gid.gid_prefix = a_gid.gid_guid = 0; 2388 2389 if (sl->p_multi & IBTL_CM_MULTI_SM) { 2390 /* validate sn_pfx */ 2391 a_gid = ibcm_saa_get_agid(sl, 2392 gidp, n_gids); 2393 } else { 2394 for (k = 0; k < num_req; k++) { 2395 ib_gid_t sg = stmp->ServiceGID; 2396 2397 IBTF_DPRINTF_L3(cmlog, 2398 "ibcm_saa_service_rec: " 2399 "SvcGID[%d] = %llX:%llX", k, 2400 sg.gid_prefix, sg.gid_guid); 2401 2402 for (j = 0; j < n_gids; j++) { 2403 if (gidp[j].gid_guid == 2404 sg.gid_guid) { 2405 a_gid = gidp[j]; 2406 break; 2407 } 2408 } 2409 if (a_gid.gid_guid) 2410 break; 2411 stmp++; 2412 } 2413 if (a_gid.gid_guid == 0) { 2414 /* Rec not found for Alt. */ 2415 for (j = 0; j < n_gids; j++) { 2416 if (gidp[j].gid_prefix 2417 == p_gid.gid_prefix) { 2418 a_gid = gidp[j]; 2419 break; 2420 } 2421 } 2422 } 2423 } 2424 kmem_free(gidp, 2425 n_gids * sizeof (ib_gid_t)); 2426 2427 if (a_gid.gid_guid) 2428 break; 2429 } else if (ret == IBT_GIDS_NOT_FOUND) { 2430 last_p_gid = p_gid; 2431 IBTF_DPRINTF_L3(cmlog, 2432 "ibcm_saa_service_rec: Didn't find " 2433 "CompGID for %llX:%llX, ret=%d", 2434 p_gid.gid_prefix, p_gid.gid_guid, 2435 ret); 2436 } else { 2437 IBTF_DPRINTF_L3(cmlog, 2438 "ibcm_saa_service_rec: Call to " 2439 "ibt_get_companion_port_gids(%llX:" 2440 "%llX) Failed = %d", 2441 p_gid.gid_prefix, p_gid.gid_guid, 2442 ret); 2443 } 2444 } 2445 2446 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: \n\t" 2447 "Pri DGID(%llX:%llX), Alt DGID(%llX:%llX)", 2448 p_gid.gid_prefix, p_gid.gid_guid, a_gid.gid_prefix, 2449 a_gid.gid_guid); 2450 2451 svcrec_resp = (sa_service_record_t *)results_p; 2452 2453 for (i = 0, j = 0; i < num_req; i++, svcrec_resp++) { 2454 /* Limited P_Key is NOT supported as of now!. */ 2455 if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) { 2456 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: " 2457 "SvcPkey 0x%X limited, reject the record.", 2458 svcrec_resp->ServiceP_Key); 2459 continue; 2460 } 2461 2462 if ((pri_fill_done == B_FALSE) && 2463 (p_gid.gid_guid == 2464 svcrec_resp->ServiceGID.gid_guid)) { 2465 p_pkey = svcrec_resp->ServiceP_Key; 2466 if ((a_pkey != 0) && 2467 (a_pkey != p_pkey)) { 2468 IBTF_DPRINTF_L3(cmlog, 2469 "ibcm_saa_service_rec: " 2470 "Pri(0x%X) & Alt (0x%X) " 2471 "PKey must match.", 2472 p_pkey, a_pkey); 2473 p_pkey = 0; 2474 continue; 2475 } 2476 ibcm_fill_svcinfo(svcrec_resp, 2477 &dinfo->dest[j++]); 2478 rec_found++; 2479 pri_fill_done = B_TRUE; 2480 } else if ((alt_fill_done == B_FALSE) && 2481 (a_gid.gid_guid == 2482 svcrec_resp->ServiceGID.gid_guid)) { 2483 a_pkey = svcrec_resp->ServiceP_Key; 2484 if ((p_pkey != 0) && 2485 (a_pkey != p_pkey)) { 2486 IBTF_DPRINTF_L3(cmlog, 2487 "ibcm_saa_service_rec: " 2488 "Pri(0x%X) & Alt (0x%X) " 2489 "PKey must match.", 2490 p_pkey, a_pkey); 2491 a_pkey = 0; 2492 continue; 2493 } 2494 ibcm_fill_svcinfo(svcrec_resp, 2495 &dinfo->dest[j++]); 2496 rec_found++; 2497 alt_fill_done = B_TRUE; 2498 } 2499 2500 if (rec_found == 2) 2501 break; 2502 } 2503 if ((alt_fill_done == B_FALSE) && (a_gid.gid_guid)) { 2504 dinfo->dest[j].d_gid = a_gid; 2505 dinfo->dest[j].d_pkey = p_pkey; 2506 rec_found++; 2507 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: " 2508 "Let Alt Pkey=%X, DGID=%llX:%llX", p_pkey, 2509 a_gid.gid_prefix, a_gid.gid_guid); 2510 } 2511 2512 if (rec_found == 1) 2513 retval = IBT_INSUFF_DATA; 2514 } else if (p_arg->flags & IBT_PATH_MULTI_SVC_DEST) { 2515 for (i = 0; i < num_req; i++, svcrec_resp++) { 2516 /* Limited P_Key is NOT supported as of now!. */ 2517 if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) { 2518 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: " 2519 "SvcPkey 0x%X limited, reject the record.", 2520 svcrec_resp->ServiceP_Key); 2521 continue; 2522 } 2523 ibcm_fill_svcinfo(svcrec_resp, 2524 &dinfo->dest[rec_found]); 2525 rec_found++; 2526 if (rec_found == p_arg->max_paths) 2527 break; 2528 } 2529 2530 if (rec_found < p_arg->max_paths) 2531 retval = IBT_INSUFF_DATA; 2532 } else { 2533 for (i = 0; i < num_req; i++) { 2534 /* Limited P_Key is NOT supported as of now!. */ 2535 if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) { 2536 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: " 2537 "SvcPkey 0x%X limited, reject the record.", 2538 svcrec_resp->ServiceP_Key); 2539 svcrec_resp++; 2540 continue; 2541 } 2542 2543 ibcm_fill_svcinfo(svcrec_resp, &dinfo->dest[0]); 2544 rec_found = 1; 2545 2546 /* Avoid having loopback node */ 2547 if (svcrec_resp->ServiceGID.gid_guid != 2548 sl->p_sgid.gid_guid) { 2549 break; 2550 } else { 2551 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: " 2552 "avoid LoopBack node."); 2553 svcrec_resp++; 2554 } 2555 } 2556 } 2557 2558 /* Deallocate the memory for results_p. */ 2559 kmem_free(results_p, length); 2560 if (dinfo->num_dest == 0) 2561 dinfo->num_dest = rec_found; 2562 2563 /* 2564 * Check out whether all Service Path we looking for are on the same 2565 * P_key. If yes, then set the global p_key field with that value, 2566 * to make it easy during SA Path Query. 2567 */ 2568 if ((dinfo->num_dest) && (dinfo->p_key == 0)) { 2569 ib_pkey_t pk = dinfo->dest[0].d_pkey; 2570 2571 if (dinfo->num_dest == 1) { 2572 dinfo->p_key = pk; 2573 } else { 2574 for (i = 1; i < (dinfo->num_dest - 1); i++) { 2575 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: " 2576 "pk= 0x%X, pk[%d]= 0x%X", pk, i, 2577 dinfo->dest[i].d_pkey); 2578 if (pk != dinfo->dest[i].d_pkey) { 2579 dinfo->p_key = 0; 2580 break; 2581 } else { 2582 dinfo->p_key = pk; 2583 } 2584 } 2585 } 2586 } 2587 2588 if (rec_found == 0) { 2589 IBTF_DPRINTF_L2(cmlog, "ibcm_saa_service_rec: " 2590 "ServiceRec NOT Found"); 2591 retval = IBT_SERVICE_RECORDS_NOT_FOUND; 2592 } 2593 2594 IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: done. Status %d, " 2595 "PKey 0x%X, Found %d SvcRec", retval, dinfo->p_key, rec_found); 2596 2597 return (retval); 2598 } 2599 2600 2601 static boolean_t 2602 ibcm_compare_paths(sa_path_record_t *pr_resp, ibt_cep_path_t *rc_path, 2603 ibtl_cm_hca_port_t *c_hp) 2604 { 2605 if ((rc_path->cep_hca_port_num == c_hp->hp_port) && 2606 (rc_path->cep_adds_vect.av_src_path == 2607 (pr_resp->SLID - c_hp->hp_base_lid)) && 2608 (rc_path->cep_adds_vect.av_dlid == pr_resp->DLID) && 2609 (rc_path->cep_adds_vect.av_srate == pr_resp->Rate)) { 2610 return (B_TRUE); 2611 } else { 2612 return (B_FALSE); 2613 } 2614 } 2615 2616 /* 2617 * ibcm_get_comp_pgids() routine gets the companion port for 'gid'. 2618 * 2619 * On success: 2620 * If 'n_gid' is specified, then verify whether 'n_gid' is indeed a 2621 * companion portgid of 'gid'. If matches return success or else error. 2622 * 2623 * If 'n_gid' is NOT specified, then return back SUCCESS along with 2624 * obtained Companion PortGids 'gid_p', where 'num' indicated number 2625 * of companion portgids returned in 'gid_p'. 2626 */ 2627 2628 static ibt_status_t 2629 ibcm_get_comp_pgids(ib_gid_t gid, ib_gid_t n_gid, ib_guid_t hca_guid, 2630 ib_gid_t **gid_p, uint_t *num) 2631 { 2632 ibt_status_t ret; 2633 int i; 2634 2635 ret = ibt_get_companion_port_gids(gid, hca_guid, 0, gid_p, num); 2636 if ((ret != IBT_SUCCESS) && (ret != IBT_GIDS_NOT_FOUND)) { 2637 IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: " 2638 "ibt_get_companion_port_gids(%llX:%llX) Failed: %d", 2639 gid.gid_prefix, gid.gid_guid, ret); 2640 } else if ((ret == IBT_GIDS_NOT_FOUND) && (n_gid.gid_guid != 0)) { 2641 IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: Specified GID " 2642 "(%llX:%llX) is NOT a Companion \n\t to current channel's " 2643 "GID(%llX:%llX)", n_gid.gid_prefix, n_gid.gid_guid, 2644 gid.gid_prefix, gid.gid_guid); 2645 ret = IBT_INVALID_PARAM; 2646 } else if (n_gid.gid_guid != 0) { 2647 /* 2648 * We found some Comp GIDs and n_gid is specified. Validate 2649 * whether the 'n_gid' specified is indeed the companion port 2650 * GID of 'gid'. 2651 */ 2652 for (i = 0; i < *num; i++) { 2653 if ((n_gid.gid_prefix == gid_p[i]->gid_prefix) && 2654 (n_gid.gid_guid == gid_p[i]->gid_guid)) { 2655 IBTF_DPRINTF_L3(cmlog, "ibcm_get_comp_pgids: " 2656 "Matching Found!. Done."); 2657 return (IBT_SUCCESS); 2658 } 2659 } 2660 IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: GID (%llX:%llX)\n" 2661 "\t and (%llX:%llX) are NOT Companion Port GIDS", 2662 n_gid.gid_prefix, n_gid.gid_guid, gid.gid_prefix, 2663 gid.gid_guid); 2664 ret = IBT_INVALID_PARAM; 2665 } else { 2666 ret = IBT_SUCCESS; 2667 } 2668 2669 IBTF_DPRINTF_L3(cmlog, "ibcm_get_comp_pgids: done. Status = %d", ret); 2670 return (ret); 2671 } 2672 2673 /* 2674 * Function: 2675 * ibt_get_alt_path 2676 * Input: 2677 * rc_chan An RC channel handle returned in a previous call 2678 * ibt_alloc_rc_channel(9F), specifies the channel to open. 2679 * flags Path flags. 2680 * attrp A pointer to an ibt_alt_path_attr_t(9S) structure that 2681 * specifies required attributes of the selected path(s). 2682 * Output: 2683 * api_p An ibt_alt_path_info_t(9S) struct filled in as output 2684 * parameters. 2685 * Returns: 2686 * IBT_SUCCESS on Success else appropriate error. 2687 * Description: 2688 * Finds the best alternate path to a specified channel (as determined by 2689 * the IBTL) that satisfies the requirements specified in an 2690 * ibt_alt_path_attr_t struct. The specified channel must have been 2691 * previously opened successfully using ibt_open_rc_channel. 2692 * This function also ensures that the service being accessed by the 2693 * channel is available at the selected alternate port. 2694 * 2695 * Note: The apa_dgid must be on the same destination channel adapter, 2696 * if specified. 2697 * This routine can not be called from interrupt context. 2698 */ 2699 ibt_status_t 2700 ibt_get_alt_path(ibt_channel_hdl_t rc_chan, ibt_path_flags_t flags, 2701 ibt_alt_path_attr_t *attrp, ibt_alt_path_info_t *api_p) 2702 { 2703 sa_multipath_record_t *mpr_req; 2704 sa_path_record_t *pr_resp; 2705 ibmf_saa_access_args_t access_args; 2706 ibt_qp_query_attr_t qp_attr; 2707 ibtl_cm_hca_port_t c_hp, n_hp; 2708 ibcm_hca_info_t *hcap; 2709 void *results_p; 2710 uint64_t c_mask = 0; 2711 ib_gid_t *gid_ptr = NULL; 2712 ib_gid_t *sgids_p = NULL, *dgids_p = NULL; 2713 ib_gid_t cur_dgid, cur_sgid; 2714 ib_gid_t new_dgid, new_sgid; 2715 ibmf_saa_handle_t saa_handle; 2716 size_t length; 2717 int i, j, template_len, rec_found; 2718 uint_t snum = 0, dnum = 0, num_rec; 2719 ibt_status_t retval; 2720 ib_mtu_t prim_mtu; 2721 2722 IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path(%p, %x, %p, %p)", 2723 rc_chan, flags, attrp, api_p); 2724 2725 /* validate channel */ 2726 if (IBCM_INVALID_CHANNEL(rc_chan)) { 2727 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: invalid channel"); 2728 return (IBT_CHAN_HDL_INVALID); 2729 } 2730 2731 if (api_p == NULL) { 2732 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: invalid attribute: " 2733 " AltPathInfo can't be NULL"); 2734 return (IBT_INVALID_PARAM); 2735 } 2736 2737 retval = ibt_query_qp(rc_chan, &qp_attr); 2738 if (retval != IBT_SUCCESS) { 2739 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: ibt_query_qp(%p) " 2740 "failed %d", rc_chan, retval); 2741 return (retval); 2742 } 2743 2744 if (qp_attr.qp_info.qp_trans != IBT_RC_SRV) { 2745 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: " 2746 "Invalid Channel type: Applicable only to RC Channel"); 2747 return (IBT_CHAN_SRV_TYPE_INVALID); 2748 } 2749 2750 cur_dgid = 2751 qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dgid; 2752 cur_sgid = 2753 qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_sgid; 2754 prim_mtu = qp_attr.qp_info.qp_transport.rc.rc_path_mtu; 2755 2756 /* If optional attributes are specified, validate them. */ 2757 if (attrp) { 2758 new_dgid = attrp->apa_dgid; 2759 new_sgid = attrp->apa_sgid; 2760 } else { 2761 new_dgid.gid_prefix = 0; 2762 new_dgid.gid_guid = 0; 2763 new_sgid.gid_prefix = 0; 2764 new_sgid.gid_guid = 0; 2765 } 2766 2767 if ((new_dgid.gid_prefix != 0) && (new_sgid.gid_prefix != 0) && 2768 (new_dgid.gid_prefix != new_sgid.gid_prefix)) { 2769 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: Specified SGID's " 2770 "SNprefix (%llX) doesn't match with \n specified DGID's " 2771 "SNprefix: %llX", new_sgid.gid_prefix, new_dgid.gid_prefix); 2772 return (IBT_INVALID_PARAM); 2773 } 2774 2775 /* For the specified SGID, get HCA information. */ 2776 retval = ibtl_cm_get_hca_port(cur_sgid, 0, &c_hp); 2777 if (retval != IBT_SUCCESS) { 2778 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: " 2779 "Get HCA Port Failed: %d", retval); 2780 return (retval); 2781 } 2782 2783 hcap = ibcm_find_hca_entry(c_hp.hp_hca_guid); 2784 if (hcap == NULL) { 2785 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: NO HCA found"); 2786 return (IBT_HCA_BUSY_DETACHING); 2787 } 2788 2789 /* Validate whether this HCA support APM */ 2790 if (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG)) { 2791 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: " 2792 "HCA (%llX) - APM NOT SUPPORTED ", c_hp.hp_hca_guid); 2793 retval = IBT_APM_NOT_SUPPORTED; 2794 goto get_alt_path_done; 2795 } 2796 2797 /* Get Companion Port GID of the current Channel's SGID */ 2798 if ((new_sgid.gid_guid == 0) || ((new_sgid.gid_guid != 0) && 2799 (new_sgid.gid_guid != cur_sgid.gid_guid))) { 2800 IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: SRC: " 2801 "Get Companion PortGids for - %llX:%llX", 2802 cur_sgid.gid_prefix, cur_sgid.gid_guid); 2803 2804 retval = ibcm_get_comp_pgids(cur_sgid, new_sgid, 2805 c_hp.hp_hca_guid, &sgids_p, &snum); 2806 if (retval != IBT_SUCCESS) 2807 goto get_alt_path_done; 2808 } 2809 2810 /* Get Companion Port GID of the current Channel's DGID */ 2811 if ((new_dgid.gid_guid == 0) || ((new_dgid.gid_guid != 0) && 2812 (new_dgid.gid_guid != cur_dgid.gid_guid))) { 2813 2814 IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: DEST: " 2815 "Get Companion PortGids for - %llX:%llX", 2816 cur_dgid.gid_prefix, cur_dgid.gid_guid); 2817 2818 retval = ibcm_get_comp_pgids(cur_dgid, new_dgid, 0, &dgids_p, 2819 &dnum); 2820 if (retval != IBT_SUCCESS) 2821 goto get_alt_path_done; 2822 } 2823 2824 if ((new_dgid.gid_guid == 0) || (new_sgid.gid_guid == 0)) { 2825 if (new_sgid.gid_guid == 0) { 2826 for (i = 0; i < snum; i++) { 2827 if (new_dgid.gid_guid == 0) { 2828 for (j = 0; j < dnum; j++) { 2829 if (sgids_p[i].gid_prefix == 2830 dgids_p[j].gid_prefix) { 2831 new_dgid = dgids_p[j]; 2832 new_sgid = sgids_p[i]; 2833 2834 goto get_alt_proceed; 2835 } 2836 } 2837 /* Current DGID */ 2838 if (sgids_p[i].gid_prefix == 2839 cur_dgid.gid_prefix) { 2840 new_sgid = sgids_p[i]; 2841 goto get_alt_proceed; 2842 } 2843 } else { 2844 if (sgids_p[i].gid_prefix == 2845 new_dgid.gid_prefix) { 2846 new_sgid = sgids_p[i]; 2847 goto get_alt_proceed; 2848 } 2849 } 2850 } 2851 /* Current SGID */ 2852 if (new_dgid.gid_guid == 0) { 2853 for (j = 0; j < dnum; j++) { 2854 if (cur_sgid.gid_prefix == 2855 dgids_p[j].gid_prefix) { 2856 new_dgid = dgids_p[j]; 2857 2858 goto get_alt_proceed; 2859 } 2860 } 2861 } 2862 } else if (new_dgid.gid_guid == 0) { 2863 for (i = 0; i < dnum; i++) { 2864 if (dgids_p[i].gid_prefix == 2865 new_sgid.gid_prefix) { 2866 new_dgid = dgids_p[i]; 2867 goto get_alt_proceed; 2868 } 2869 } 2870 /* Current DGID */ 2871 if (cur_dgid.gid_prefix == new_sgid.gid_prefix) { 2872 goto get_alt_proceed; 2873 } 2874 } 2875 /* 2876 * hmm... No Companion Ports available. 2877 * so we will be using current or specified attributes only. 2878 */ 2879 } 2880 2881 get_alt_proceed: 2882 2883 if (new_sgid.gid_guid != 0) { 2884 retval = ibtl_cm_get_hca_port(new_sgid, 0, &n_hp); 2885 if (retval != IBT_SUCCESS) { 2886 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: " 2887 "Get HCA Port Failed: %d", retval); 2888 goto get_alt_path_done; 2889 } 2890 } 2891 2892 /* Calculate the size for multi-path records template */ 2893 template_len = (2 * sizeof (ib_gid_t)) + sizeof (sa_multipath_record_t); 2894 2895 mpr_req = kmem_zalloc(template_len, KM_SLEEP); 2896 2897 ASSERT(mpr_req != NULL); 2898 2899 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req)) 2900 2901 gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) + 2902 sizeof (sa_multipath_record_t)); 2903 2904 /* SGID */ 2905 if (new_sgid.gid_guid == 0) 2906 *gid_ptr = cur_sgid; 2907 else 2908 *gid_ptr = new_sgid; 2909 2910 IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Get Path Between " 2911 " SGID : %llX:%llX", gid_ptr->gid_prefix, gid_ptr->gid_guid); 2912 2913 gid_ptr++; 2914 2915 /* DGID */ 2916 if (new_dgid.gid_guid == 0) 2917 *gid_ptr = cur_dgid; 2918 else 2919 *gid_ptr = new_dgid; 2920 2921 IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path:\t\t DGID : %llX:%llX", 2922 gid_ptr->gid_prefix, gid_ptr->gid_guid); 2923 2924 mpr_req->SGIDCount = 1; 2925 c_mask = SA_MPR_COMPMASK_SGIDCOUNT; 2926 2927 mpr_req->DGIDCount = 1; 2928 c_mask |= SA_MPR_COMPMASK_DGIDCOUNT; 2929 2930 /* Is Flow Label Specified. */ 2931 if (attrp) { 2932 if (attrp->apa_flow) { 2933 mpr_req->FlowLabel = attrp->apa_flow; 2934 c_mask |= SA_MPR_COMPMASK_FLOWLABEL; 2935 } 2936 2937 /* Is HopLimit Specified. */ 2938 if (flags & IBT_PATH_HOP) { 2939 mpr_req->HopLimit = attrp->apa_hop; 2940 c_mask |= SA_MPR_COMPMASK_HOPLIMIT; 2941 } 2942 2943 /* Is TClass Specified. */ 2944 if (attrp->apa_tclass) { 2945 mpr_req->TClass = attrp->apa_tclass; 2946 c_mask |= SA_MPR_COMPMASK_TCLASS; 2947 } 2948 2949 /* Is SL specified. */ 2950 if (attrp->apa_sl) { 2951 mpr_req->SL = attrp->apa_sl; 2952 c_mask |= SA_MPR_COMPMASK_SL; 2953 } 2954 2955 if (flags & IBT_PATH_PERF) { 2956 mpr_req->PacketLifeTimeSelector = IBT_BEST; 2957 mpr_req->RateSelector = IBT_BEST; 2958 2959 c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR | 2960 SA_MPR_COMPMASK_RATESELECTOR; 2961 } else { 2962 if (attrp->apa_pkt_lt.p_selector == IBT_BEST) { 2963 mpr_req->PacketLifeTimeSelector = IBT_BEST; 2964 c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR; 2965 } 2966 2967 if (attrp->apa_srate.r_selector == IBT_BEST) { 2968 mpr_req->RateSelector = IBT_BEST; 2969 c_mask |= SA_MPR_COMPMASK_RATESELECTOR; 2970 } 2971 } 2972 2973 /* 2974 * Honor individual selection of these attributes, 2975 * even if IBT_PATH_PERF is set. 2976 */ 2977 /* Check out whether Packet Life Time is specified. */ 2978 if (attrp->apa_pkt_lt.p_pkt_lt) { 2979 mpr_req->PacketLifeTime = 2980 ibt_usec2ib(attrp->apa_pkt_lt.p_pkt_lt); 2981 mpr_req->PacketLifeTimeSelector = 2982 attrp->apa_pkt_lt.p_selector; 2983 2984 c_mask |= SA_MPR_COMPMASK_PKTLT | 2985 SA_MPR_COMPMASK_PKTLTSELECTOR; 2986 } 2987 2988 /* Is SRATE specified. */ 2989 if (attrp->apa_srate.r_srate) { 2990 mpr_req->Rate = attrp->apa_srate.r_srate; 2991 mpr_req->RateSelector = attrp->apa_srate.r_selector; 2992 2993 c_mask |= SA_MPR_COMPMASK_RATE | 2994 SA_MPR_COMPMASK_RATESELECTOR; 2995 } 2996 } 2997 2998 /* Alt PathMTU can be GT or EQU to current channel's Pri PathMTU */ 2999 3000 /* P_Key must be same as that of primary path */ 3001 retval = ibt_index2pkey_byguid(c_hp.hp_hca_guid, c_hp.hp_port, 3002 qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix, 3003 &mpr_req->P_Key); 3004 if (retval != IBT_SUCCESS) { 3005 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: Idx2Pkey Failed: %d", 3006 retval); 3007 goto get_alt_path_done; 3008 } 3009 c_mask |= SA_MPR_COMPMASK_PKEY; 3010 3011 mpr_req->Reversible = 1; /* We always get REVERSIBLE paths. */ 3012 mpr_req->IndependenceSelector = 1; 3013 c_mask |= SA_MPR_COMPMASK_REVERSIBLE | SA_MPR_COMPMASK_INDEPSEL; 3014 3015 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req)) 3016 3017 IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: CMask: 0x%llX", c_mask); 3018 3019 /* NOTE: We will **NOT** specify how many records we want. */ 3020 3021 IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Primary: MTU %d, PKey[%d]=" 3022 "0x%X\n\tSGID = %llX:%llX, DGID = %llX:%llX", prim_mtu, 3023 qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix, mpr_req->P_Key, 3024 cur_sgid.gid_prefix, cur_sgid.gid_guid, cur_dgid.gid_prefix, 3025 cur_dgid.gid_guid); 3026 3027 /* Get SA Access Handle. */ 3028 if (new_sgid.gid_guid != 0) 3029 saa_handle = ibcm_get_saa_handle(hcap, n_hp.hp_port); 3030 else 3031 saa_handle = ibcm_get_saa_handle(hcap, c_hp.hp_port); 3032 if (saa_handle == NULL) { 3033 retval = IBT_HCA_PORT_NOT_ACTIVE; 3034 goto get_alt_path_done; 3035 } 3036 3037 /* Contact SA Access to retrieve Path Records. */ 3038 access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID; 3039 access_args.sq_access_type = IBMF_SAA_RETRIEVE; 3040 access_args.sq_component_mask = c_mask; 3041 access_args.sq_template = mpr_req; 3042 access_args.sq_template_length = sizeof (sa_multipath_record_t); 3043 access_args.sq_callback = NULL; 3044 access_args.sq_callback_arg = NULL; 3045 3046 retval = ibcm_contact_sa_access(saa_handle, &access_args, &length, 3047 &results_p); 3048 if (retval != IBT_SUCCESS) { 3049 goto get_alt_path_done; 3050 } 3051 3052 num_rec = length / sizeof (sa_path_record_t); 3053 3054 kmem_free(mpr_req, template_len); 3055 3056 IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Found %d Paths", num_rec); 3057 3058 rec_found = 0; 3059 if ((results_p != NULL) && (num_rec > 0)) { 3060 /* Update the PathInfo with the response Path Records */ 3061 pr_resp = (sa_path_record_t *)results_p; 3062 for (i = 0; i < num_rec; i++, pr_resp++) { 3063 if (prim_mtu > pr_resp->Mtu) { 3064 IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: " 3065 "Alt PathMTU(%d) must be GT or EQU to Pri " 3066 "PathMTU(%d). Ignore this rec", 3067 pr_resp->Mtu, prim_mtu); 3068 continue; 3069 } 3070 3071 if ((new_sgid.gid_guid == 0) && 3072 (new_dgid.gid_guid == 0)) { 3073 /* Reject PathRec if it same as Primary Path. */ 3074 if (ibcm_compare_paths(pr_resp, 3075 &qp_attr.qp_info.qp_transport.rc.rc_path, 3076 &c_hp) == B_TRUE) { 3077 IBTF_DPRINTF_L3(cmlog, 3078 "ibt_get_alt_path: PathRec obtained" 3079 " is similar to Prim Path, ignore " 3080 "this record"); 3081 continue; 3082 } 3083 } 3084 3085 if (new_sgid.gid_guid == 0) { 3086 retval = ibcm_update_cep_info(pr_resp, NULL, 3087 &c_hp, &api_p->ap_alt_cep_path); 3088 } else { 3089 retval = ibcm_update_cep_info(pr_resp, NULL, 3090 &n_hp, &api_p->ap_alt_cep_path); 3091 } 3092 if (retval != IBT_SUCCESS) 3093 continue; 3094 3095 /* Update some leftovers */ 3096 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*api_p)) 3097 3098 api_p->ap_alt_pkt_lt = pr_resp->PacketLifeTime; 3099 3100 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*api_p)) 3101 3102 rec_found = 1; 3103 break; 3104 } 3105 kmem_free(results_p, length); 3106 } 3107 3108 if (rec_found == 0) { 3109 IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Alternate Path cannot" 3110 " be established"); 3111 retval = IBT_PATH_RECORDS_NOT_FOUND; 3112 } else 3113 retval = IBT_SUCCESS; 3114 3115 get_alt_path_done: 3116 if ((snum) && (sgids_p)) 3117 kmem_free(sgids_p, snum * sizeof (ib_gid_t)); 3118 3119 if ((dnum) && (dgids_p)) 3120 kmem_free(dgids_p, dnum * sizeof (ib_gid_t)); 3121 3122 ibcm_dec_hca_acc_cnt(hcap); 3123 3124 IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Done (status %d).", retval); 3125 3126 return (retval); 3127 } 3128 3129 3130 /* Routines for warlock */ 3131 3132 /* ARGSUSED */ 3133 static void 3134 ibcm_dummy_path_handler(void *arg, ibt_status_t retval, ibt_path_info_t *paths, 3135 uint8_t num_path) 3136 { 3137 ibcm_path_tqargs_t dummy_path; 3138 3139 dummy_path.func = ibcm_dummy_path_handler; 3140 3141 IBTF_DPRINTF_L5(cmlog, "ibcm_dummy_path_handler: " 3142 "dummy_path.func %p", dummy_path.func); 3143 } 3144