1/* 2 * Copyright (c) 2004-2006 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 62ib_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 */ 79static 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 ********************************************************************************/ 109static 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 178Exit: 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 **********************************************************************/ 186static 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; 280Exit: 281 OSM_LOG_EXIT(p_vend->p_log); 282 return (status); 283} 284 285/********************************************************************** 286 **********************************************************************/ 287void 288osm_ca_info_destroy(IN osm_vendor_t * const p_vend, 289 IN osm_ca_info_t * const p_ca_info) 290{ 291 OSM_LOG_ENTER(p_vend->p_log); 292 293 if (p_ca_info->p_attr) { 294 if (p_ca_info->p_attr->num_ports) { 295 free(p_ca_info->p_attr->p_port_attr); 296 } 297 free(p_ca_info->p_attr); 298 } 299 300 free(p_ca_info); 301 302 OSM_LOG_EXIT(p_vend->p_log); 303} 304 305/********************************************************************** 306 * Fill in the array of port_attr with all available ports on ALL the 307 * avilable CAs on this machine. 308 * ALSO - 309 * UPDATE THE VENDOR OBJECT LIST OF CA_INFO STRUCTS 310 **********************************************************************/ 311ib_api_status_t 312osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, 313 IN ib_port_attr_t * const p_attr_array, 314 IN uint32_t * const p_num_ports) 315{ 316 ib_api_status_t status; 317 318 uint32_t ca; 319 uint32_t ca_count; 320 uint32_t port_count = 0; 321 uint8_t port_num; 322 uint32_t total_ports = 0; 323 VAPI_hca_id_t *p_ca_ids = NULL; 324 osm_ca_info_t *p_ca_info; 325 326 OSM_LOG_ENTER(p_vend->p_log); 327 328 CL_ASSERT(p_vend); 329 330 /* 331 * 1) Determine the number of CA's 332 * 2) Allocate an array big enough to hold the ca info objects. 333 * 3) Call again to retrieve the guids. 334 */ 335 status = __osm_vendor_get_ca_ids(p_vend, &p_ca_ids, &ca_count); 336 if (status != IB_SUCCESS) { 337 osm_log(p_vend->p_log, OSM_LOG_ERROR, 338 "osm_vendor_get_all_port_attr: ERR 7109: " 339 "Fail to get CA Ids.\n"); 340 goto Exit; 341 } 342 343 /* we keep track of all the CAs in this info array */ 344 p_vend->p_ca_info = malloc(ca_count * sizeof(*p_vend->p_ca_info)); 345 if (p_vend->p_ca_info == NULL) { 346 osm_log(p_vend->p_log, OSM_LOG_ERROR, 347 "osm_vendor_get_all_port_attr: ERR 7110: " 348 "Unable to allocate CA information array.\n"); 349 goto Exit; 350 } 351 352 memset(p_vend->p_ca_info, 0, ca_count * sizeof(*p_vend->p_ca_info)); 353 p_vend->ca_count = ca_count; 354 355 /* 356 * For each CA, retrieve the CA info attributes 357 */ 358 for (ca = 0; ca < ca_count; ca++) { 359 p_ca_info = &p_vend->p_ca_info[ca]; 360 361 status = __osm_ca_info_init(p_vend, p_ca_ids[ca], p_ca_info); 362 363 if (status != IB_SUCCESS) { 364 osm_log(p_vend->p_log, OSM_LOG_ERROR, 365 "osm_vendor_get_all_port_attr: ERR 7111: " 366 "Unable to initialize CA Info object (%s).\n", 367 ib_get_err_str(status)); 368 } 369 370 total_ports += osm_ca_info_get_num_ports(p_ca_info); 371 372 osm_log(p_vend->p_log, OSM_LOG_DEBUG, 373 "osm_vendor_get_all_port_attr: " 374 "osm_vendor_get_all_port_attr: %u got %u ports total:%u\n", 375 ca, osm_ca_info_get_num_ports(p_ca_info), total_ports); 376 377 } 378 379 /* 380 * If the user supplied enough storage, return the port guids, 381 * otherwise, return the appropriate error. 382 */ 383 if (*p_num_ports >= total_ports) { 384 for (ca = 0; ca < ca_count; ca++) { 385 uint32_t num_ports; 386 387 p_ca_info = &p_vend->p_ca_info[ca]; 388 389 num_ports = osm_ca_info_get_num_ports(p_ca_info); 390 391 for (port_num = 0; port_num < num_ports; port_num++) { 392 p_attr_array[port_count] = 393 *__osm_ca_info_get_port_attr_ptr(p_ca_info, 394 port_num); 395 port_count++; 396 } 397 } 398 } else { 399 status = IB_INSUFFICIENT_MEMORY; 400 goto Exit; 401 } 402 403 status = IB_SUCCESS; 404 405Exit: 406 *p_num_ports = total_ports; 407 408 if (p_ca_ids) 409 free(p_ca_ids); 410 411 OSM_LOG_EXIT(p_vend->p_log); 412 return (status); 413} 414 415/********************************************************************** 416 * Given the vendor obj and a guid 417 * return the ca id and port number that have that guid 418 **********************************************************************/ 419 420ib_api_status_t 421osm_vendor_get_guid_ca_and_port(IN osm_vendor_t * const p_vend, 422 IN ib_net64_t const guid, 423 OUT VAPI_hca_hndl_t * p_hca_hndl, 424 OUT VAPI_hca_id_t * p_hca_id, 425 OUT uint32_t * p_port_num) 426{ 427 428 ib_api_status_t status; 429 VAPI_hca_id_t *p_ca_ids = NULL; 430 VAPI_ret_t vapi_res; 431 VAPI_hca_hndl_t hca_hndl; 432 VAPI_hca_vendor_t hca_vendor; 433 VAPI_hca_cap_t hca_cap; 434 IB_gid_t *p_port_gid = NULL; 435 uint16_t maxNumGids; 436 ib_net64_t port_guid; 437 uint32_t ca, portIdx, ca_count; 438 439 OSM_LOG_ENTER(p_vend->p_log); 440 441 CL_ASSERT(p_vend); 442 443 /* 444 * 1) Determine the number of CA's 445 * 2) Allocate an array big enough to hold the ca info objects. 446 * 3) Call again to retrieve the guids. 447 */ 448 status = __osm_vendor_get_ca_ids(p_vend, &p_ca_ids, &ca_count); 449 if (status != IB_SUCCESS) { 450 osm_log(p_vend->p_log, OSM_LOG_ERROR, 451 "osm_vendor_get_guid_ca_and_port: ERR 7112: " 452 "Fail to get CA Ids.\n"); 453 goto Exit; 454 } 455 456 /* 457 * For each CA, retrieve the CA info attributes 458 */ 459 for (ca = 0; ca < ca_count; ca++) { 460 /* get the HCA handle */ 461 vapi_res = EVAPI_get_hca_hndl(p_ca_ids[ca], &hca_hndl); 462 if (vapi_res != VAPI_OK) { 463 osm_log(p_vend->p_log, OSM_LOG_ERROR, 464 "osm_vendor_get_guid_ca_and_port: ERR 7113: " 465 "Fail to get HCA handle (%u).\n", vapi_res); 466 goto Exit; 467 } 468 469 /* get the CA attributes - to know how many ports it has: */ 470 if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { 471 osm_log(p_vend->p_log, OSM_LOG_DEBUG, 472 "osm_vendor_get_guid_ca_and_port: " 473 "Querying CA %s.\n", p_ca_ids[ca]); 474 } 475 476 /* query and get the HCA capability */ 477 vapi_res = VAPI_query_hca_cap(hca_hndl, &hca_vendor, &hca_cap); 478 if (vapi_res != VAPI_OK) { 479 osm_log(p_vend->p_log, OSM_LOG_ERROR, 480 "osm_vendor_get_guid_ca_and_port: ERR 7114: " 481 "Fail to get HCA Capabilities (%u).\n", 482 vapi_res); 483 goto Exit; 484 } 485 486 /* go over all ports - to obtail their guids */ 487 for (portIdx = 0; portIdx < hca_cap.phys_port_num; portIdx++) { 488 vapi_res = 489 VAPI_query_hca_gid_tbl(hca_hndl, portIdx + 1, 0, 490 &maxNumGids, NULL); 491 p_port_gid = 492 (IB_gid_t *) malloc(maxNumGids * sizeof(IB_gid_t)); 493 494 /* get the port guid */ 495 vapi_res = 496 VAPI_query_hca_gid_tbl(hca_hndl, portIdx + 1, 497 maxNumGids, &maxNumGids, 498 p_port_gid); 499 if (vapi_res != VAPI_OK) { 500 osm_log(p_vend->p_log, OSM_LOG_ERROR, 501 "osm_vendor_get_guid_ca_and_port: ERR 7115: " 502 "Fail to get HCA Port GID (%d).\n", 503 vapi_res); 504 goto Exit; 505 } 506 507 /* convert to SF style */ 508 __osm_vendor_gid_to_guid(p_port_gid[0], 509 (VAPI_gid_t *) & port_guid); 510 511 /* finally did we find it ? */ 512 if (port_guid == guid) { 513 *p_hca_hndl = hca_hndl; 514 memcpy(p_hca_id, p_ca_ids[ca], 515 sizeof(VAPI_hca_id_t)); 516 *p_port_num = portIdx + 1; 517 status = IB_SUCCESS; 518 goto Exit; 519 } 520 521 free(p_port_gid); 522 p_port_gid = NULL; 523 } /* ALL PORTS */ 524 } /* all HCAs */ 525 526 osm_log(p_vend->p_log, OSM_LOG_ERROR, 527 "osm_vendor_get_guid_ca_and_port: ERR 7116: " 528 "Fail to find HCA and Port for Port Guid 0x%" PRIx64 "\n", 529 cl_ntoh64(guid)); 530 status = IB_INVALID_GUID; 531 532Exit: 533 if (p_ca_ids != NULL) 534 free(p_ca_ids); 535 if (p_port_gid != NULL) 536 free(p_port_gid); 537 OSM_LOG_EXIT(p_vend->p_log); 538 return (status); 539} 540 541#ifdef __TEST_HCA_GUID__ 542 543#define GUID_ARRAY_SIZE 64 544 545#include <stdio.h> 546 547/********************************************************************** 548 **********************************************************************/ 549ib_net64_t get_port_guid() 550{ 551 uint32_t i; 552 uint32_t choice = 0; 553 boolean_t done_flag = FALSE; 554 ib_api_status_t status; 555 uint32_t num_ports = GUID_ARRAY_SIZE; 556 ib_port_attr_t attr_array[GUID_ARRAY_SIZE]; 557 VAPI_hca_id_t ca_id; 558 uint32_t portNum; 559 osm_vendor_t vend; 560 osm_vendor_t *p_vend; 561 osm_log_t *p_osm_log, tlog; 562 563 p_osm_log = &tlog; 564 565 status = osm_log_init(p_osm_log, FALSE); 566 if (status != IB_SUCCESS) 567 return (status); 568 569 osm_log(p_osm_log, OSM_LOG_FUNCS, "get_port_guid: [\n"); 570 571 p_vend = &vend; 572 p_vend->p_log = p_osm_log; 573 574 /* 575 * Call the transport layer for a list of local port 576 * GUID values. 577 */ 578 status = osm_vendor_get_all_port_attr(p_vend, attr_array, &num_ports); 579 if (status != IB_SUCCESS) { 580 printf("\nError from osm_opensm_init (%x)\n", status); 581 return (0); 582 } 583 584 if (num_ports == 0) { 585 printf("\nNo local ports detected!\n"); 586 return (0); 587 } 588 589 while (done_flag == FALSE) { 590 printf("\nChoose a local port number with which to bind:\n\n"); 591 for (i = 0; i < num_ports; i++) { 592 /* 593 * Print the index + 1 since by convention, port numbers 594 * start with 1 on host channel adapters. 595 */ 596 597 printf("\t%u: GUID = 0x%8" PRIx64 598 ", lid = 0x%04X, state = %s\n", i + 1, 599 cl_ntoh64(attr_array[i].port_guid), 600 cl_ntoh16(attr_array[i].lid), 601 ib_get_port_state_str(attr_array[i].link_state)); 602 } 603 604 printf("\nEnter choice (1-%u): ", i); 605 fflush(stdout); 606 scanf("%u", &choice); 607 if (choice > num_ports) 608 printf("\nError: Lame choice!\n"); 609 else 610 done_flag = TRUE; 611 } 612 613 status = 614 osm_vendor_get_guid_ca_and_port(p_vend, 615 attr_array[choice - 1].port_guid, 616 &ca_id, &portNum); 617 if (status != IB_SUCCESS) { 618 printf("Error obtaining back the HCA and Port\n"); 619 return (0); 620 } 621 622 printf("Selected: CA:%s Port:%d\n", ca_id, portNum); 623 624 return (attr_array[choice - 1].port_guid); 625} 626 627int main(int argc, char **argv) 628{ 629 get_port_guid(); 630 return (0); 631} 632 633#endif 634 635#endif 636