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