| /* |
| * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation; either version 2 of the |
| * License, or any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| */ |
| |
| FILE_LICENCE ( GPL2_OR_LATER ); |
| |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <byteswap.h> |
| #include <gpxe/infiniband.h> |
| #include <gpxe/ib_smc.h> |
| |
| /** |
| * @file |
| * |
| * Infiniband Subnet Management Client |
| * |
| */ |
| |
| /** |
| * Get port information |
| * |
| * @v ibdev Infiniband device |
| * @v local_mad Method for issuing local MADs |
| * @v mad Management datagram to fill in |
| * @ret rc Return status code |
| */ |
| static int ib_smc_get_port_info ( struct ib_device *ibdev, |
| ib_local_mad_t local_mad, |
| union ib_mad *mad ) { |
| int rc; |
| |
| /* Construct MAD */ |
| memset ( mad, 0, sizeof ( *mad ) ); |
| mad->hdr.base_version = IB_MGMT_BASE_VERSION; |
| mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; |
| mad->hdr.class_version = 1; |
| mad->hdr.method = IB_MGMT_METHOD_GET; |
| mad->hdr.attr_id = htons ( IB_SMP_ATTR_PORT_INFO ); |
| mad->hdr.attr_mod = htonl ( ibdev->port ); |
| |
| if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) { |
| DBGC ( ibdev, "IBDEV %p could not get port info: %s\n", |
| ibdev, strerror ( rc ) ); |
| return rc; |
| } |
| return 0; |
| } |
| |
| /** |
| * Get GUID information |
| * |
| * @v ibdev Infiniband device |
| * @v local_mad Method for issuing local MADs |
| * @v mad Management datagram to fill in |
| * @ret rc Return status code |
| */ |
| static int ib_smc_get_guid_info ( struct ib_device *ibdev, |
| ib_local_mad_t local_mad, |
| union ib_mad *mad ) { |
| int rc; |
| |
| /* Construct MAD */ |
| memset ( mad, 0, sizeof ( *mad ) ); |
| mad->hdr.base_version = IB_MGMT_BASE_VERSION; |
| mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; |
| mad->hdr.class_version = 1; |
| mad->hdr.method = IB_MGMT_METHOD_GET; |
| mad->hdr.attr_id = htons ( IB_SMP_ATTR_GUID_INFO ); |
| |
| if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) { |
| DBGC ( ibdev, "IBDEV %p could not get GUID info: %s\n", |
| ibdev, strerror ( rc ) ); |
| return rc; |
| } |
| return 0; |
| } |
| |
| /** |
| * Get partition key table |
| * |
| * @v ibdev Infiniband device |
| * @v local_mad Method for issuing local MADs |
| * @v mad Management datagram to fill in |
| * @ret rc Return status code |
| */ |
| static int ib_smc_get_pkey_table ( struct ib_device *ibdev, |
| ib_local_mad_t local_mad, |
| union ib_mad *mad ) { |
| int rc; |
| |
| /* Construct MAD */ |
| memset ( mad, 0, sizeof ( *mad ) ); |
| mad->hdr.base_version = IB_MGMT_BASE_VERSION; |
| mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; |
| mad->hdr.class_version = 1; |
| mad->hdr.method = IB_MGMT_METHOD_GET; |
| mad->hdr.attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE ); |
| |
| if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) { |
| DBGC ( ibdev, "IBDEV %p could not get pkey table: %s\n", |
| ibdev, strerror ( rc ) ); |
| return rc; |
| } |
| return 0; |
| } |
| |
| /** |
| * Get MAD parameters |
| * |
| * @v ibdev Infiniband device |
| * @v local_mad Method for issuing local MADs |
| * @ret rc Return status code |
| */ |
| int ib_smc_update ( struct ib_device *ibdev, ib_local_mad_t local_mad ) { |
| union ib_mad mad; |
| union ib_smp_data *smp = &mad.smp.smp_data; |
| int rc; |
| |
| /* Port info gives us the link state, the first half of the |
| * port GID and the SM LID. |
| */ |
| if ( ( rc = ib_smc_get_port_info ( ibdev, local_mad, &mad ) ) != 0 ) |
| return rc; |
| ibdev->port_state = |
| ( smp->port_info.link_speed_supported__port_state & 0x0f ); |
| memcpy ( &ibdev->gid.u.half[0], smp->port_info.gid_prefix, |
| sizeof ( ibdev->gid.u.half[0] ) ); |
| ibdev->lid = ntohs ( smp->port_info.lid ); |
| ibdev->sm_lid = ntohs ( smp->port_info.mastersm_lid ); |
| ibdev->sm_sl = ( smp->port_info.neighbour_mtu__mastersm_sl & 0xf ); |
| |
| /* GUID info gives us the second half of the port GID */ |
| if ( ( rc = ib_smc_get_guid_info ( ibdev, local_mad, &mad ) ) != 0 ) |
| return rc; |
| memcpy ( &ibdev->gid.u.half[1], smp->guid_info.guid[0], |
| sizeof ( ibdev->gid.u.half[1] ) ); |
| |
| /* Get partition key */ |
| if ( ( rc = ib_smc_get_pkey_table ( ibdev, local_mad, &mad ) ) != 0 ) |
| return rc; |
| ibdev->pkey = ntohs ( smp->pkey_table.pkey[0] ); |
| |
| DBGC ( ibdev, "IBDEV %p port GID is %08x:%08x:%08x:%08x\n", ibdev, |
| htonl ( ibdev->gid.u.dwords[0] ), |
| htonl ( ibdev->gid.u.dwords[1] ), |
| htonl ( ibdev->gid.u.dwords[2] ), |
| htonl ( ibdev->gid.u.dwords[3] ) ); |
| |
| return 0; |
| } |