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