1 /* 2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. 4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5 * 6 * This software is available to you under a choice of one of two 7 * licenses. You may choose to be licensed under the terms of the GNU 8 * General Public License (GPL) Version 2, available from the file 9 * COPYING in the main directory of this source tree, or the 10 * OpenIB.org BSD license below: 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer. 19 * 20 * - Redistributions in binary form must reproduce the above 21 * copyright notice, this list of conditions and the following 22 * disclaimer in the documentation and/or other materials 23 * provided with the distribution. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * SOFTWARE. 33 * 34 */ 35 36 #if HAVE_CONFIG_H 37 # include <config.h> 38 #endif /* HAVE_CONFIG_H */ 39 40 #if defined(OSM_VENDOR_INTF_MTL) | defined(OSM_VENDOR_INTF_TS) 41 #undef IN 42 #undef OUT 43 #include <stdlib.h> 44 #include <vapi_types.h> 45 #include <evapi.h> 46 #include <vendor/osm_vendor_api.h> 47 #include <opensm/osm_log.h> 48 #include <stdio.h> 49 50 /******************************************************************************** 51 * 52 * Provide the functionality for selecting an HCA Port and Obtaining it's guid. 53 * 54 ********************************************************************************/ 55 56 /********************************************************************** 57 * Convert the given GID to GUID by copy of it's upper 8 bytes 58 * 59 * 60 **********************************************************************/ 61 62 ib_api_status_t 63 __osm_vendor_gid_to_guid(IN u_int8_t * gid, OUT VAPI_gid_t * guid) 64 { 65 memcpy(guid, gid + 8, 8); 66 return (IB_SUCCESS); 67 } 68 69 /****f* OpenSM: CA Info/osm_ca_info_get_pi_ptr 70 * NAME 71 * osm_ca_info_get_pi_ptr 72 * 73 * DESCRIPTION 74 * Returns a pointer to the port attribute of the specified port 75 * owned by this CA. 76 * 77 * SYNOPSIS 78 */ 79 static ib_port_attr_t *__osm_ca_info_get_port_attr_ptr(IN const osm_ca_info_t * 80 const p_ca_info, 81 IN const uint8_t index) 82 { 83 return (&p_ca_info->p_attr->p_port_attr[index]); 84 } 85 86 /* 87 * PARAMETERS 88 * p_ca_info 89 * [in] Pointer to a CA Info object. 90 * 91 * index 92 * [in] Port "index" for which to retrieve the port attribute. 93 * The index is the offset into the ca's internal array 94 * of port attributes. 95 * 96 * RETURN VALUE 97 * Returns a pointer to the port attribute of the specified port 98 * owned by this CA. 99 * 100 * NOTES 101 * 102 * SEE ALSO 103 *********/ 104 105 /******************************************************************************** 106 * get the CA names ava`ilable on the system 107 * NOTE: user of this function needs to deallocate p_hca_ids after usage. 108 ********************************************************************************/ 109 static ib_api_status_t 110 __osm_vendor_get_ca_ids(IN osm_vendor_t * const p_vend, 111 IN VAPI_hca_id_t ** const p_hca_ids, 112 IN uint32_t * const p_num_guids) 113 { 114 ib_api_status_t status; 115 VAPI_ret_t vapi_res; 116 117 OSM_LOG_ENTER(p_vend->p_log); 118 119 CL_ASSERT(p_hca_ids); 120 CL_ASSERT(p_num_guids); 121 122 /* first call is just to get the number */ 123 vapi_res = EVAPI_list_hcas(0, p_num_guids, NULL); 124 125 /* fail ? */ 126 if (vapi_res == VAPI_EINVAL_PARAM) { 127 osm_log(p_vend->p_log, OSM_LOG_ERROR, 128 "__osm_vendor_get_ca_ids: ERR 7101: " 129 "Bad parameter in calling: EVAPI_list_hcas. (%d)\n", 130 vapi_res); 131 status = IB_ERROR; 132 goto Exit; 133 } 134 135 /* NO HCA ? */ 136 if (*p_num_guids == 0) { 137 osm_log(p_vend->p_log, OSM_LOG_ERROR, 138 "__osm_vendor_get_ca_ids: ERR 7102: " 139 "No available channel adapters.\n"); 140 status = IB_INSUFFICIENT_RESOURCES; 141 goto Exit; 142 } 143 144 /* allocate and really call - user of this function needs to deallocate it */ 145 *p_hca_ids = 146 (VAPI_hca_id_t *) malloc(*p_num_guids * sizeof(VAPI_hca_id_t)); 147 148 /* now call it really */ 149 vapi_res = EVAPI_list_hcas(*p_num_guids, p_num_guids, *p_hca_ids); 150 151 /* too many ? */ 152 if (vapi_res == VAPI_EAGAIN) { 153 osm_log(p_vend->p_log, OSM_LOG_ERROR, 154 "__osm_vendor_get_ca_ids: ERR 7103: " 155 "More CA GUIDs than allocated array (%d).\n", 156 *p_num_guids); 157 status = IB_ERROR; 158 goto Exit; 159 } 160 161 /* fail ? */ 162 if (vapi_res != VAPI_OK) { 163 osm_log(p_vend->p_log, OSM_LOG_ERROR, 164 "__osm_vendor_get_ca_ids: ERR 7104: " 165 "Bad parameter in calling: EVAPI_list_hcas.\n"); 166 status = IB_ERROR; 167 goto Exit; 168 } 169 170 if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { 171 osm_log(p_vend->p_log, OSM_LOG_DEBUG, 172 "__osm_vendor_get_ca_ids: " 173 "Detected %u local channel adapters.\n", *p_num_guids); 174 } 175 176 status = IB_SUCCESS; 177 178 Exit: 179 OSM_LOG_EXIT(p_vend->p_log); 180 return (status); 181 } 182 183 /********************************************************************** 184 * Initialize an Info Struct for the Given HCA by its Id 185 **********************************************************************/ 186 static ib_api_status_t 187 __osm_ca_info_init(IN osm_vendor_t * const p_vend, 188 IN VAPI_hca_id_t ca_id, OUT osm_ca_info_t * const p_ca_info) 189 { 190 ib_api_status_t status = IB_ERROR; 191 VAPI_ret_t vapi_res; 192 VAPI_hca_hndl_t hca_hndl; 193 VAPI_hca_vendor_t hca_vendor; 194 VAPI_hca_cap_t hca_cap; 195 VAPI_hca_port_t hca_port; 196 uint8_t port_num; 197 IB_gid_t *p_port_gid; 198 uint16_t maxNumGids; 199 200 OSM_LOG_ENTER(p_vend->p_log); 201 202 /* get the HCA handle */ 203 vapi_res = EVAPI_get_hca_hndl(ca_id, &hca_hndl); 204 if (vapi_res != VAPI_OK) { 205 osm_log(p_vend->p_log, OSM_LOG_ERROR, 206 "__osm_ca_info_init: ERR 7105: " 207 "Fail to get HCA handle (%u).\n", vapi_res); 208 goto Exit; 209 } 210 211 if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { 212 osm_log(p_vend->p_log, OSM_LOG_DEBUG, 213 "__osm_ca_info_init: " "Querying CA %s.\n", ca_id); 214 } 215 216 /* query and get the HCA capability */ 217 vapi_res = VAPI_query_hca_cap(hca_hndl, &hca_vendor, &hca_cap); 218 if (vapi_res != VAPI_OK) { 219 osm_log(p_vend->p_log, OSM_LOG_ERROR, 220 "__osm_ca_info_init: ERR 7106: " 221 "Fail to get HCA Capabilities (%u).\n", vapi_res); 222 goto Exit; 223 } 224 225 /* get the guid of the HCA */ 226 memcpy(&(p_ca_info->guid), hca_cap.node_guid, 8 * sizeof(u_int8_t)); 227 p_ca_info->attr_size = 1; 228 p_ca_info->p_attr = (ib_ca_attr_t *) malloc(sizeof(ib_ca_attr_t)); 229 memcpy(&(p_ca_info->p_attr->ca_guid), hca_cap.node_guid, 230 8 * sizeof(u_int8_t)); 231 232 /* now obtain the attributes of the ports */ 233 p_ca_info->p_attr->num_ports = hca_cap.phys_port_num; 234 p_ca_info->p_attr->p_port_attr = 235 (ib_port_attr_t *) malloc(hca_cap.phys_port_num * 236 sizeof(ib_port_attr_t)); 237 238 for (port_num = 0; port_num < p_ca_info->p_attr->num_ports; port_num++) { 239 240 /* query the port attributes */ 241 vapi_res = 242 VAPI_query_hca_port_prop(hca_hndl, port_num + 1, &hca_port); 243 if (vapi_res != VAPI_OK) { 244 osm_log(p_vend->p_log, OSM_LOG_ERROR, 245 "__osm_ca_info_init: ERR 7107: " 246 "Fail to get HCA Port Attributes (%d).\n", 247 vapi_res); 248 goto Exit; 249 } 250 251 /* first call to know the size of the gid table */ 252 vapi_res = 253 VAPI_query_hca_gid_tbl(hca_hndl, port_num + 1, 0, 254 &maxNumGids, NULL); 255 p_port_gid = (IB_gid_t *) malloc(maxNumGids * sizeof(IB_gid_t)); 256 257 vapi_res = 258 VAPI_query_hca_gid_tbl(hca_hndl, port_num + 1, maxNumGids, 259 &maxNumGids, p_port_gid); 260 if (vapi_res != VAPI_OK) { 261 osm_log(p_vend->p_log, OSM_LOG_ERROR, 262 "__osm_ca_info_init: ERR 7108: " 263 "Fail to get HCA Port GID (%d).\n", vapi_res); 264 goto Exit; 265 } 266 267 __osm_vendor_gid_to_guid(p_port_gid[0], 268 (IB_gid_t *) & p_ca_info->p_attr-> 269 p_port_attr[port_num].port_guid); 270 p_ca_info->p_attr->p_port_attr[port_num].lid = hca_port.lid; 271 p_ca_info->p_attr->p_port_attr[port_num].link_state = 272 hca_port.state; 273 p_ca_info->p_attr->p_port_attr[port_num].sm_lid = 274 hca_port.sm_lid; 275 276 free(p_port_gid); 277 } 278 279 status = IB_SUCCESS; 280 Exit: 281 OSM_LOG_EXIT(p_vend->p_log); 282 return (status); 283 } 284 285 void 286 osm_ca_info_destroy(IN osm_vendor_t * const p_vend, 287 IN osm_ca_info_t * const p_ca_info) 288 { 289 OSM_LOG_ENTER(p_vend->p_log); 290 291 if (p_ca_info->p_attr) { 292 if (p_ca_info->p_attr->num_ports) { 293 free(p_ca_info->p_attr->p_port_attr); 294 } 295 free(p_ca_info->p_attr); 296 } 297 298 free(p_ca_info); 299 300 OSM_LOG_EXIT(p_vend->p_log); 301 } 302 303 /********************************************************************** 304 * Fill in the array of port_attr with all available ports on ALL the 305 * avilable CAs on this machine. 306 * ALSO - 307 * UPDATE THE VENDOR OBJECT LIST OF CA_INFO STRUCTS 308 **********************************************************************/ 309 ib_api_status_t 310 osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, 311 IN ib_port_attr_t * const p_attr_array, 312 IN uint32_t * const p_num_ports) 313 { 314 ib_api_status_t status; 315 316 uint32_t ca; 317 uint32_t ca_count; 318 uint32_t port_count = 0; 319 uint8_t port_num; 320 uint32_t total_ports = 0; 321 VAPI_hca_id_t *p_ca_ids = NULL; 322 osm_ca_info_t *p_ca_info; 323 324 OSM_LOG_ENTER(p_vend->p_log); 325 326 CL_ASSERT(p_vend); 327 328 /* 329 * 1) Determine the number of CA's 330 * 2) Allocate an array big enough to hold the ca info objects. 331 * 3) Call again to retrieve the guids. 332 */ 333 status = __osm_vendor_get_ca_ids(p_vend, &p_ca_ids, &ca_count); 334 if (status != IB_SUCCESS) { 335 osm_log(p_vend->p_log, OSM_LOG_ERROR, 336 "osm_vendor_get_all_port_attr: ERR 7109: " 337 "Fail to get CA Ids.\n"); 338 goto Exit; 339 } 340 341 /* we keep track of all the CAs in this info array */ 342 p_vend->p_ca_info = malloc(ca_count * sizeof(*p_vend->p_ca_info)); 343 if (p_vend->p_ca_info == NULL) { 344 osm_log(p_vend->p_log, OSM_LOG_ERROR, 345 "osm_vendor_get_all_port_attr: ERR 7110: " 346 "Unable to allocate CA information array.\n"); 347 goto Exit; 348 } 349 350 memset(p_vend->p_ca_info, 0, ca_count * sizeof(*p_vend->p_ca_info)); 351 p_vend->ca_count = ca_count; 352 353 /* 354 * For each CA, retrieve the CA info attributes 355 */ 356 for (ca = 0; ca < ca_count; ca++) { 357 p_ca_info = &p_vend->p_ca_info[ca]; 358 359 status = __osm_ca_info_init(p_vend, p_ca_ids[ca], p_ca_info); 360 361 if (status != IB_SUCCESS) { 362 osm_log(p_vend->p_log, OSM_LOG_ERROR, 363 "osm_vendor_get_all_port_attr: ERR 7111: " 364 "Unable to initialize CA Info object (%s).\n", 365 ib_get_err_str(status)); 366 } 367 368 total_ports += osm_ca_info_get_num_ports(p_ca_info); 369 370 osm_log(p_vend->p_log, OSM_LOG_DEBUG, 371 "osm_vendor_get_all_port_attr: " 372 "osm_vendor_get_all_port_attr: %u got %u ports total:%u\n", 373 ca, osm_ca_info_get_num_ports(p_ca_info), total_ports); 374 375 } 376 377 /* 378 * If the user supplied enough storage, return the port guids, 379 * otherwise, return the appropriate error. 380 */ 381 if (*p_num_ports >= total_ports) { 382 for (ca = 0; ca < ca_count; ca++) { 383 uint32_t num_ports; 384 385 p_ca_info = &p_vend->p_ca_info[ca]; 386 387 num_ports = osm_ca_info_get_num_ports(p_ca_info); 388 389 for (port_num = 0; port_num < num_ports; port_num++) { 390 p_attr_array[port_count] = 391 *__osm_ca_info_get_port_attr_ptr(p_ca_info, 392 port_num); 393 port_count++; 394 } 395 } 396 } else { 397 status = IB_INSUFFICIENT_MEMORY; 398 goto Exit; 399 } 400 401 status = IB_SUCCESS; 402 403 Exit: 404 *p_num_ports = total_ports; 405 406 if (p_ca_ids) 407 free(p_ca_ids); 408 409 OSM_LOG_EXIT(p_vend->p_log); 410 return (status); 411 } 412 413 /********************************************************************** 414 * Given the vendor obj and a guid 415 * return the ca id and port number that have that guid 416 **********************************************************************/ 417 418 ib_api_status_t 419 osm_vendor_get_guid_ca_and_port(IN osm_vendor_t * const p_vend, 420 IN ib_net64_t const guid, 421 OUT VAPI_hca_hndl_t * p_hca_hndl, 422 OUT VAPI_hca_id_t * p_hca_id, 423 OUT uint32_t * p_port_num) 424 { 425 426 ib_api_status_t status; 427 VAPI_hca_id_t *p_ca_ids = NULL; 428 VAPI_ret_t vapi_res; 429 VAPI_hca_hndl_t hca_hndl; 430 VAPI_hca_vendor_t hca_vendor; 431 VAPI_hca_cap_t hca_cap; 432 IB_gid_t *p_port_gid = NULL; 433 uint16_t maxNumGids; 434 ib_net64_t port_guid; 435 uint32_t ca, portIdx, ca_count; 436 437 OSM_LOG_ENTER(p_vend->p_log); 438 439 CL_ASSERT(p_vend); 440 441 /* 442 * 1) Determine the number of CA's 443 * 2) Allocate an array big enough to hold the ca info objects. 444 * 3) Call again to retrieve the guids. 445 */ 446 status = __osm_vendor_get_ca_ids(p_vend, &p_ca_ids, &ca_count); 447 if (status != IB_SUCCESS) { 448 osm_log(p_vend->p_log, OSM_LOG_ERROR, 449 "osm_vendor_get_guid_ca_and_port: ERR 7112: " 450 "Fail to get CA Ids.\n"); 451 goto Exit; 452 } 453 454 /* 455 * For each CA, retrieve the CA info attributes 456 */ 457 for (ca = 0; ca < ca_count; ca++) { 458 /* get the HCA handle */ 459 vapi_res = EVAPI_get_hca_hndl(p_ca_ids[ca], &hca_hndl); 460 if (vapi_res != VAPI_OK) { 461 osm_log(p_vend->p_log, OSM_LOG_ERROR, 462 "osm_vendor_get_guid_ca_and_port: ERR 7113: " 463 "Fail to get HCA handle (%u).\n", vapi_res); 464 goto Exit; 465 } 466 467 /* get the CA attributes - to know how many ports it has: */ 468 if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { 469 osm_log(p_vend->p_log, OSM_LOG_DEBUG, 470 "osm_vendor_get_guid_ca_and_port: " 471 "Querying CA %s.\n", p_ca_ids[ca]); 472 } 473 474 /* query and get the HCA capability */ 475 vapi_res = VAPI_query_hca_cap(hca_hndl, &hca_vendor, &hca_cap); 476 if (vapi_res != VAPI_OK) { 477 osm_log(p_vend->p_log, OSM_LOG_ERROR, 478 "osm_vendor_get_guid_ca_and_port: ERR 7114: " 479 "Fail to get HCA Capabilities (%u).\n", 480 vapi_res); 481 goto Exit; 482 } 483 484 /* go over all ports - to obtail their guids */ 485 for (portIdx = 0; portIdx < hca_cap.phys_port_num; portIdx++) { 486 vapi_res = 487 VAPI_query_hca_gid_tbl(hca_hndl, portIdx + 1, 0, 488 &maxNumGids, NULL); 489 p_port_gid = 490 (IB_gid_t *) malloc(maxNumGids * sizeof(IB_gid_t)); 491 492 /* get the port guid */ 493 vapi_res = 494 VAPI_query_hca_gid_tbl(hca_hndl, portIdx + 1, 495 maxNumGids, &maxNumGids, 496 p_port_gid); 497 if (vapi_res != VAPI_OK) { 498 osm_log(p_vend->p_log, OSM_LOG_ERROR, 499 "osm_vendor_get_guid_ca_and_port: ERR 7115: " 500 "Fail to get HCA Port GID (%d).\n", 501 vapi_res); 502 goto Exit; 503 } 504 505 /* convert to SF style */ 506 __osm_vendor_gid_to_guid(p_port_gid[0], 507 (VAPI_gid_t *) & port_guid); 508 509 /* finally did we find it ? */ 510 if (port_guid == guid) { 511 *p_hca_hndl = hca_hndl; 512 memcpy(p_hca_id, p_ca_ids[ca], 513 sizeof(VAPI_hca_id_t)); 514 *p_port_num = portIdx + 1; 515 status = IB_SUCCESS; 516 goto Exit; 517 } 518 519 free(p_port_gid); 520 p_port_gid = NULL; 521 } /* ALL PORTS */ 522 } /* all HCAs */ 523 524 osm_log(p_vend->p_log, OSM_LOG_ERROR, 525 "osm_vendor_get_guid_ca_and_port: ERR 7116: " 526 "Fail to find HCA and Port for Port Guid 0x%" PRIx64 "\n", 527 cl_ntoh64(guid)); 528 status = IB_INVALID_GUID; 529 530 Exit: 531 if (p_ca_ids != NULL) 532 free(p_ca_ids); 533 if (p_port_gid != NULL) 534 free(p_port_gid); 535 OSM_LOG_EXIT(p_vend->p_log); 536 return (status); 537 } 538 539 #ifdef __TEST_HCA_GUID__ 540 541 #define GUID_ARRAY_SIZE 64 542 543 #include <stdio.h> 544 545 ib_net64_t get_port_guid() 546 { 547 uint32_t i; 548 uint32_t choice = 0; 549 boolean_t done_flag = FALSE; 550 ib_api_status_t status; 551 uint32_t num_ports = GUID_ARRAY_SIZE; 552 ib_port_attr_t attr_array[GUID_ARRAY_SIZE]; 553 VAPI_hca_id_t ca_id; 554 uint32_t portNum; 555 osm_vendor_t vend; 556 osm_vendor_t *p_vend; 557 osm_log_t *p_osm_log, tlog; 558 559 p_osm_log = &tlog; 560 561 status = osm_log_init(p_osm_log, FALSE); 562 if (status != IB_SUCCESS) 563 return (status); 564 565 osm_log(p_osm_log, OSM_LOG_FUNCS, "get_port_guid: [\n"); 566 567 p_vend = &vend; 568 p_vend->p_log = p_osm_log; 569 570 /* 571 * Call the transport layer for a list of local port 572 * GUID values. 573 */ 574 status = osm_vendor_get_all_port_attr(p_vend, attr_array, &num_ports); 575 if (status != IB_SUCCESS) { 576 printf("\nError from osm_opensm_init (%x)\n", status); 577 return (0); 578 } 579 580 if (num_ports == 0) { 581 printf("\nNo local ports detected!\n"); 582 return (0); 583 } 584 585 while (done_flag == FALSE) { 586 printf("\nChoose a local port number with which to bind:\n\n"); 587 for (i = 0; i < num_ports; i++) { 588 /* 589 * Print the index + 1 since by convention, port numbers 590 * start with 1 on host channel adapters. 591 */ 592 593 printf("\t%u: GUID = 0x%8" PRIx64 594 ", lid = 0x%04X, state = %s\n", i + 1, 595 cl_ntoh64(attr_array[i].port_guid), 596 cl_ntoh16(attr_array[i].lid), 597 ib_get_port_state_str(attr_array[i].link_state)); 598 } 599 600 printf("\nEnter choice (1-%u): ", i); 601 fflush(stdout); 602 scanf("%u", &choice); 603 if (choice > num_ports) 604 printf("\nError: Lame choice!\n"); 605 else 606 done_flag = TRUE; 607 } 608 609 status = 610 osm_vendor_get_guid_ca_and_port(p_vend, 611 attr_array[choice - 1].port_guid, 612 &ca_id, &portNum); 613 if (status != IB_SUCCESS) { 614 printf("Error obtaining back the HCA and Port\n"); 615 return (0); 616 } 617 618 printf("Selected: CA:%s Port:%d\n", ca_id, portNum); 619 620 return (attr_array[choice - 1].port_guid); 621 } 622 623 int main(int argc, char **argv) 624 { 625 get_port_guid(); 626 return (0); 627 } 628 629 #endif 630 631 #endif 632