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.
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:
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
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.
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
38 #endif /* HAVE_CONFIG_H */
40 #if defined(OSM_VENDOR_INTF_MTL) | defined(OSM_VENDOR_INTF_TS)
43 #include <vendor/osm_vendor_api.h>
44 #include <opensm/osm_log.h>
47 #include <sys/types.h>
54 /********************************************************************************
56 * Provides the functionality for selecting an HCA Port and Obtaining it's guid.
57 * This version is based on /proc/infiniband file system. So it is limited to
58 * The gen1 of openib.org stack.
60 ********************************************************************************/
62 typedef struct _osm_ca_info {
69 /**********************************************************************
70 * Returns a pointer to the port attribute of the specified port
72 ************************************************************************/
73 static ib_port_attr_t *__osm_ca_info_get_port_attr_ptr(IN const osm_ca_info_t *
75 IN const uint8_t index)
77 return (&p_ca_info->p_attr->p_port_attr[index]);
80 /**********************************************************************
81 * Obtain the number of local CAs by scanning /proc/infiniband/core
82 **********************************************************************/
83 int __hca_pfs_get_num_cas()
89 dp = opendir("/proc/infiniband/core");
91 while ((ep = readdir(dp))) {
92 /* CAs are directories with the format ca[1-9][0-9]* */
93 if ((ep->d_type == DT_DIR)
94 && !strncmp(ep->d_name, "ca", 2)) {
106 node GUID: 0002:c900:0120:3470
111 FW revision: 0x300020080
113 typedef struct _pfs_ca_info {
124 /**********************************************************************
125 * Parse the CA Info file available in /proc/infiniband/core/caN/info
126 **********************************************************************/
127 static ib_api_status_t
128 __parse_ca_info_file(IN osm_vendor_t * const p_vend,
129 IN uint32_t idx, OUT pfs_ca_info_t * pfs_ca_info)
131 ib_api_status_t status = IB_ERROR;
134 char file_buffer[3200];
140 OSM_LOG_ENTER(p_vend->p_log);
142 osm_log(p_vend->p_log, OSM_LOG_DEBUG,
143 "__parse_ca_info_file: " "Querying CA %d.\n", idx);
145 /* we use the proc file system so we must be able to open the info file .. */
146 sprintf(file_name, "/proc/infiniband/core/ca%d/info", idx);
147 info_file = open(file_name, O_RDONLY);
149 osm_log(p_vend->p_log, OSM_LOG_ERROR,
150 "__parse_ca_info_file: ERR 5205: "
151 "Fail to open HCA:%d info file:(%s).\n", idx,
156 /* read in the file */
157 len = read(info_file, file_buffer, 3200);
159 file_buffer[len] = '\0';
165 node GUID: 0002:c900:0120:3470
170 FW revision: 0x300020080
172 if (!(p_ch = strstr(file_buffer, "name:"))) {
173 osm_log(p_vend->p_log, OSM_LOG_ERROR,
174 "__parse_ca_info_file: ERR 5206: "
175 "Fail to obtain HCA name. In info file:(%s).\n",
179 if (sscanf(p_ch, "name: %s", pfs_ca_info->name) != 1) {
180 osm_log(p_vend->p_log, OSM_LOG_ERROR,
181 "__parse_ca_info_file: ERR 5207: "
182 "Fail to parse name in info file:(%s).\n", p_ch);
186 /* get the guid of the HCA */
187 if (!(p_ch = strstr(file_buffer, "node GUID:"))) {
188 osm_log(p_vend->p_log, OSM_LOG_ERROR,
189 "__parse_ca_info_file: ERR 5208: "
190 "Fail to obtain GUID in info file:(%s).\n",
194 if (sscanf(p_ch, "node GUID: %x:%x:%x:%x", &g1, &g2, &g3, &g4) != 4) {
195 osm_log(p_vend->p_log, OSM_LOG_ERROR,
196 "__parse_ca_info_file: ERR 5209: "
197 "Fail to parse GUID in info file:(%s).\n", p_ch);
200 pfs_ca_info->guid = (uint64_t) g1 << 48 | (uint64_t) g1 << 32
201 | (uint64_t) g1 << 16 | (uint64_t) g3;
203 /* obtain number of ports */
204 if (!(p_ch = strstr(file_buffer, "ports:"))) {
205 osm_log(p_vend->p_log, OSM_LOG_ERROR,
206 "__parse_ca_info_file: ERR 5210: "
207 "Fail to obtain number of ports in info file:(%s).\n",
211 if (sscanf(p_ch, "ports: %d", &num_ports) != 1) {
212 osm_log(p_vend->p_log, OSM_LOG_ERROR,
213 "__parse_ca_info_file: ERR 5211: "
214 "Fail to parse num ports in info file:(%s).\n", p_ch);
217 pfs_ca_info->num_ports = num_ports;
219 osm_log(p_vend->p_log, OSM_LOG_DEBUG,
220 "__parse_ca_info_file: "
221 "CA1 = name:%s guid:0x%016llx ports:%d\n",
222 pfs_ca_info->name, pfs_ca_info->guid, pfs_ca_info->num_ports);
226 OSM_LOG_EXIT(p_vend->p_log);
238 IsAutomaticMigrationSupported
241 IsSystemImageGUIDSupported
242 IsVendorClassSupported
243 IsCapabilityMaskNoticeSupported
245 typedef struct _pfs_port_info {
253 /**********************************************************************
254 * Parse the Port Info file available in /proc/infiniband/core/caN/portM/info
256 **********************************************************************/
257 static ib_api_status_t
258 __parse_port_info_file(IN osm_vendor_t * const p_vend,
260 IN uint8_t port_num, OUT pfs_port_info_t * pfs_port_info)
262 ib_api_status_t status = IB_ERROR;
265 char file_buffer[3200];
268 int lid, sm_lid, lmc, sm_sl;
271 OSM_LOG_ENTER(p_vend->p_log);
273 osm_log(p_vend->p_log, OSM_LOG_DEBUG,
274 "__parse_port_info_file: "
275 "Parsing Proc File System Port Info CA %d Port %d.\n", hca_idx,
278 /* we use the proc file system so we must be able to open the info file .. */
279 sprintf(file_name, "/proc/infiniband/core/ca%d/port%d/info", hca_idx,
281 info_file = open(file_name, O_RDONLY);
283 osm_log(p_vend->p_log, OSM_LOG_ERROR,
284 "__parse_port_info_file: ERR 5212: "
285 "Fail to open HCA:%d Port:%d info file:(%s).\n",
286 hca_idx, port_num, file_name);
290 /* read in the file */
291 len = read(info_file, file_buffer, 3200);
293 file_buffer[len] = '\0';
304 if (!(p_ch = strstr(file_buffer, "state:"))) {
305 osm_log(p_vend->p_log, OSM_LOG_ERROR,
306 "__parse_port_info_file: ERR 5213: "
307 "Fail to obtain port state. In info file:(%s).\n",
311 if (sscanf(p_ch, "state: %s", state) != 1) {
312 osm_log(p_vend->p_log, OSM_LOG_ERROR,
313 "__parse_port_info_file: ERR 5214: "
314 "Fail to parse state from info file:(%s).\n", p_ch);
318 if (!strcmp(state, "ACTIVE"))
319 pfs_port_info->state = IB_LINK_ACTIVE;
320 else if (!strcmp(state, "DOWN"))
321 pfs_port_info->state = IB_LINK_DOWN;
322 else if (!strcmp(state, "INIT"))
323 pfs_port_info->state = IB_LINK_INIT;
324 else if (!strcmp(state, "ARMED"))
325 pfs_port_info->state = IB_LINK_ARMED;
327 pfs_port_info->state = 0;
330 if (!(p_ch = strstr(file_buffer, "LID:"))) {
331 osm_log(p_vend->p_log, OSM_LOG_ERROR,
332 "__parse_port_info_file: ERR 5215: "
333 "Fail to obtain port lid. In info file:(%s).\n",
337 if (sscanf(p_ch, "LID: %x", &lid) != 1) {
338 osm_log(p_vend->p_log, OSM_LOG_ERROR,
339 "__parse_port_info_file: ERR 5216: "
340 "Fail to parse lid from info file:(%s).\n", p_ch);
343 pfs_port_info->lid = lid;
345 if (!(p_ch = strstr(file_buffer, "LMC:"))) {
346 osm_log(p_vend->p_log, OSM_LOG_ERROR,
347 "__parse_port_info_file: ERR 5217: "
348 "Fail to obtain port LMC. In info file:(%s).\n",
352 if (sscanf(p_ch, "LMC: %x", &lmc) != 1) {
353 osm_log(p_vend->p_log, OSM_LOG_ERROR,
354 "__parse_port_info_file: ERR 5218: "
355 "Fail to parse LMC from info file:(%s).\n", p_ch);
358 pfs_port_info->lmc = lmc;
361 if (!(p_ch = strstr(file_buffer, "SM LID:"))) {
362 osm_log(p_vend->p_log, OSM_LOG_ERROR,
363 "__parse_port_info_file: ERR 5219: "
364 "Fail to obtain port SM LID. In info file:(%s).\n",
368 if (sscanf(p_ch, "SM LID: %x", &sm_lid) != 1) {
369 osm_log(p_vend->p_log, OSM_LOG_ERROR,
370 "__parse_port_info_file: ERR 5220: "
371 "Fail to parse SM LID from info file:(%s).\n", p_ch);
374 pfs_port_info->sm_lid = sm_lid;
377 if (!(p_ch = strstr(file_buffer, "SM SL:"))) {
378 osm_log(p_vend->p_log, OSM_LOG_ERROR,
379 "__parse_port_info_file: ERR 5221: "
380 "Fail to obtain port SM SL. In info file:(%s).\n",
384 if (sscanf(p_ch, "SM SL: %x", &sm_sl) != 1) {
385 osm_log(p_vend->p_log, OSM_LOG_ERROR,
386 "__parse_port_info_file: ERR 5222: "
387 "Fail to parse SM SL from info file:(%s).\n", p_ch);
390 pfs_port_info->sm_sl = sm_sl;
391 osm_log(p_vend->p_log, OSM_LOG_DEBUG,
392 "__parse_port_info_file: "
393 "Obtained Port:%d = state:%d, lid:0x%04X, lmc:%d, sm_lid:0x%04X, sm_sl:%d\n",
394 port_num, pfs_port_info->state, pfs_port_info->lid,
395 pfs_port_info->lmc, pfs_port_info->sm_lid,
396 pfs_port_info->sm_sl);
400 OSM_LOG_EXIT(p_vend->p_log);
404 /**********************************************************************
405 * Parse the port guid_tbl file to obtain the port guid.
407 * [ 0] fe80:0000:0000:0000:0002:c900:0120:3472
408 **********************************************************************/
409 static ib_api_status_t
410 __get_port_guid_from_port_gid_tbl(IN osm_vendor_t * const p_vend,
412 IN uint8_t port_num, OUT uint64_t * port_guid)
414 ib_api_status_t status = IB_ERROR;
417 char file_buffer[3200];
422 OSM_LOG_ENTER(p_vend->p_log);
424 osm_log(p_vend->p_log, OSM_LOG_DEBUG,
425 "__get_port_guid_from_port_gid_tbl: "
426 "Parsing Proc File System Port Guid Table CA %d Port %d.\n",
429 /* we use the proc file system so we must be able to open the info file .. */
430 sprintf(file_name, "/proc/infiniband/core/ca%d/port%d/gid_table",
432 info_file = open(file_name, O_RDONLY);
434 osm_log(p_vend->p_log, OSM_LOG_ERROR,
435 "__get_port_guid_from_port_gid_tbl: ERR 5223: "
436 "Fail to open HCA:%d Port:%d gid_table file:(%s).\n",
437 hca_idx, port_num, file_name);
441 /* read in the file */
442 len = read(info_file, file_buffer, 3200);
444 file_buffer[len] = '\0';
448 [ 0] fe80:0000:0000:0000:0002:c900:0120:3472
451 if (!(p_ch = strstr(file_buffer, "[ 0]"))) {
452 osm_log(p_vend->p_log, OSM_LOG_ERROR,
453 "__get_port_guid_from_port_gid_tbl: ERR 5224: "
454 "Fail to obtain first gid index. In gid_table file:(%s).\n",
458 if (sscanf(p_ch + 6, "%x:%x:%x:%x:%x:%x:%x:%x",
459 &g[7], &g[6], &g[5], &g[4], &g[3], &g[2], &g[1], &g[0]) != 8)
461 osm_log(p_vend->p_log, OSM_LOG_ERROR,
462 "__get_port_guid_from_port_gid_tbl: ERR 5225: "
463 "Fail to parse gid from gid_table file:(%s).\n", p_ch);
468 (uint64_t) g[3] << 48 | (uint64_t) g[2] << 32 | (uint64_t) g[1] <<
472 OSM_LOG_EXIT(p_vend->p_log);
476 /**********************************************************************
477 * Initialize an Info Struct for the Given HCA by its index 1..N
478 **********************************************************************/
479 static ib_api_status_t
480 __osm_ca_info_init(IN osm_vendor_t * const p_vend,
481 IN uint32_t const idx, OUT osm_ca_info_t * const p_ca_info)
483 ib_api_status_t status = IB_ERROR;
487 pfs_ca_info_t pfs_ca_info;
489 OSM_LOG_ENTER(p_vend->p_log);
491 /* parse the CA info file */
492 if (__parse_ca_info_file(p_vend, idx, &pfs_ca_info) != IB_SUCCESS)
495 p_ca_info->guid = cl_hton64(pfs_ca_info.guid);
497 /* set size of attributes and allocate them */
498 p_ca_info->attr_size = 1;
499 p_ca_info->p_attr = (ib_ca_attr_t *) malloc(sizeof(ib_ca_attr_t));
501 p_ca_info->p_attr->ca_guid = p_ca_info->guid;
502 p_ca_info->p_attr->num_ports = pfs_ca_info.num_ports;
504 /* now obtain the attributes of the ports */
505 p_ca_info->p_attr->p_port_attr =
506 (ib_port_attr_t *) malloc(pfs_ca_info.num_ports *
507 sizeof(ib_port_attr_t));
509 /* get all the ports info */
510 for (port_num = 1; port_num <= pfs_ca_info.num_ports; port_num++) {
511 pfs_port_info_t pfs_port_info;
512 /* query the port attributes */
513 if (__parse_port_info_file
514 (p_vend, idx, port_num, &pfs_port_info)) {
515 osm_log(p_vend->p_log, OSM_LOG_ERROR,
516 "__osm_ca_info_init: ERR 5226: "
517 "Fail to get HCA:%d Port:%d Attributes.\n", idx,
522 /* HACK: the lids should have been converted to network but the rest of the code
523 is wrong and provdes them as is (host order) - so we stick with it. */
524 p_ca_info->p_attr->p_port_attr[port_num - 1].lid =
526 p_ca_info->p_attr->p_port_attr[port_num - 1].link_state =
528 p_ca_info->p_attr->p_port_attr[port_num - 1].sm_lid =
529 pfs_port_info.sm_lid;
531 /* get the port guid */
532 if (__get_port_guid_from_port_gid_tbl
533 (p_vend, idx, port_num, &port_guid)) {
534 osm_log(p_vend->p_log, OSM_LOG_ERROR,
535 "__osm_ca_info_init: ERR 5227: "
536 "Fail to get HCA:%d Port:%d Guid.\n", idx,
540 p_ca_info->p_attr->p_port_attr[port_num - 1].port_guid =
541 cl_hton64(port_guid);
546 OSM_LOG_EXIT(p_vend->p_log);
550 /**********************************************************************
551 **********************************************************************/
553 osm_ca_info_destroy(IN osm_vendor_t * const p_vend,
554 IN osm_ca_info_t * const p_ca_info, IN uint8_t num_ca)
559 OSM_LOG_ENTER(p_vend->p_log);
561 for (i = 0; i < num_ca; i++) {
562 p_ca = &p_ca_info[i];
564 if (NULL != p_ca->p_attr) {
565 if (0 != p_ca->p_attr->num_ports) {
566 free(p_ca->p_attr->p_port_attr);
575 OSM_LOG_EXIT(p_vend->p_log);
578 /**********************************************************************
579 * Fill in the array of port_attr with all available ports on ALL the
580 * avilable CAs on this machine.
581 **********************************************************************/
583 osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend,
584 IN ib_port_attr_t * const p_attr_array,
585 IN uint32_t * const p_num_ports)
587 ib_api_status_t status = IB_SUCCESS;
590 uint32_t ca_count = 0;
591 uint32_t port_count = 0;
593 uint32_t total_ports = 0;
594 osm_ca_info_t *p_ca_infos = NULL;
595 uint32_t attr_array_sz = *p_num_ports;
597 OSM_LOG_ENTER(p_vend->p_log);
601 /* determine the number of CA's */
602 ca_count = __hca_pfs_get_num_cas();
604 osm_log(p_vend->p_log, OSM_LOG_ERROR,
605 "osm_vendor_get_all_port_attr: ERR 5228: "
606 "Fail to get Any CA Ids.\n");
610 /* Allocate an array big enough to hold the ca info objects */
611 p_ca_infos = malloc(ca_count * sizeof(osm_ca_info_t));
612 if (p_ca_infos == NULL) {
613 osm_log(p_vend->p_log, OSM_LOG_ERROR,
614 "osm_vendor_get_all_port_attr: ERR 5229: "
615 "Unable to allocate CA information array.\n");
619 memset(p_ca_infos, 0, ca_count * sizeof(osm_ca_info_t));
622 * For each CA, retrieve the CA info attributes
624 for (caIdx = 1; caIdx <= ca_count; caIdx++) {
626 __osm_ca_info_init(p_vend, caIdx, &p_ca_infos[caIdx - 1]);
627 if (status != IB_SUCCESS) {
628 osm_log(p_vend->p_log, OSM_LOG_ERROR,
629 "osm_vendor_get_all_port_attr: ERR 5230: "
630 "Unable to initialize CA Info object (%s).\n",
631 ib_get_err_str(status));
634 total_ports += p_ca_infos[caIdx - 1].p_attr->num_ports;
637 *p_num_ports = total_ports;
638 osm_log(p_vend->p_log, OSM_LOG_DEBUG,
639 "osm_vendor_get_all_port_attr: total ports:%u \n", total_ports);
642 * If the user supplied enough storage, return the port guids,
643 * otherwise, return the appropriate error.
645 if (attr_array_sz >= total_ports) {
646 for (caIdx = 1; caIdx <= ca_count; caIdx++) {
649 num_ports = p_ca_infos[caIdx - 1].p_attr->num_ports;
651 for (port_num = 0; port_num < num_ports; port_num++) {
652 p_attr_array[port_count] =
653 *__osm_ca_info_get_port_attr_ptr(&p_ca_infos
661 status = IB_INSUFFICIENT_MEMORY;
669 osm_ca_info_destroy(p_vend, p_ca_infos, ca_count);
672 OSM_LOG_EXIT(p_vend->p_log);
676 /**********************************************************************
677 * Given the vendor obj and a port guid
678 * return the ca id and port number that have that guid
679 **********************************************************************/
682 osm_vendor_get_guid_ca_and_port(IN osm_vendor_t * const p_vend,
683 IN ib_net64_t const guid,
684 OUT uint32_t * p_hca_hndl,
686 OUT uint8_t * p_hca_idx,
687 OUT uint32_t * p_port_num)
690 uint32_t ca_count = 0;
692 ib_api_status_t status = IB_ERROR;
694 OSM_LOG_ENTER(p_vend->p_log);
698 /* determine the number of CA's */
699 ca_count = __hca_pfs_get_num_cas();
701 osm_log(p_vend->p_log, OSM_LOG_ERROR,
702 "osm_vendor_get_guid_ca_and_port: ERR 5231: "
703 "Fail to get Any CA Ids.\n");
708 * For each CA, retrieve the CA info attributes
710 for (caIdx = 1; caIdx <= ca_count; caIdx++) {
711 pfs_ca_info_t pfs_ca_info;
712 if (__parse_ca_info_file(p_vend, caIdx, &pfs_ca_info) ==
714 /* get all the ports info */
715 for (port_num = 1; port_num <= pfs_ca_info.num_ports;
718 if (!__get_port_guid_from_port_gid_tbl
719 (p_vend, caIdx, port_num, &port_guid)) {
720 if (cl_hton64(port_guid) == guid) {
721 osm_log(p_vend->p_log,
723 "osm_vendor_get_guid_ca_and_port: "
724 "Found Matching guid on HCA:%d Port:%d.\n",
728 *p_port_num = port_num;
729 *p_hca_idx = caIdx - 1;
739 osm_log(p_vend->p_log, OSM_LOG_ERROR,
740 "osm_vendor_get_guid_ca_and_port: ERR 5232: "
741 "Fail to find HCA and Port for Port Guid 0x%" PRIx64 "\n",
743 status = IB_INVALID_GUID;
747 OSM_LOG_EXIT(p_vend->p_log);