1 /* 2 * Copyright (C) 2008 Michael Brown <mbrown (at) fensystems.co.uk>. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of the 7 * License, or any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 */ 18 19 FILE_LICENCE ( GPL2_OR_LATER ); 20 21 #include <stdint.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <errno.h> 25 #include <unistd.h> 26 #include <byteswap.h> 27 #include <gpxe/infiniband.h> 28 #include <gpxe/ib_smc.h> 29 30 /** 31 * @file 32 * 33 * Infiniband Subnet Management Client 34 * 35 */ 36 37 /** 38 * Get port information 39 * 40 * @v ibdev Infiniband device 41 * @v local_mad Method for issuing local MADs 42 * @v mad Management datagram to fill in 43 * @ret rc Return status code 44 */ 45 static int ib_smc_get_port_info ( struct ib_device *ibdev, 46 ib_local_mad_t local_mad, 47 union ib_mad *mad ) { 48 int rc; 49 50 /* Construct MAD */ 51 memset ( mad, 0, sizeof ( *mad ) ); 52 mad->hdr.base_version = IB_MGMT_BASE_VERSION; 53 mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; 54 mad->hdr.class_version = 1; 55 mad->hdr.method = IB_MGMT_METHOD_GET; 56 mad->hdr.attr_id = htons ( IB_SMP_ATTR_PORT_INFO ); 57 mad->hdr.attr_mod = htonl ( ibdev->port ); 58 59 if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) { 60 DBGC ( ibdev, "IBDEV %p could not get port info: %s\n", 61 ibdev, strerror ( rc ) ); 62 return rc; 63 } 64 return 0; 65 } 66 67 /** 68 * Get GUID information 69 * 70 * @v ibdev Infiniband device 71 * @v local_mad Method for issuing local MADs 72 * @v mad Management datagram to fill in 73 * @ret rc Return status code 74 */ 75 static int ib_smc_get_guid_info ( struct ib_device *ibdev, 76 ib_local_mad_t local_mad, 77 union ib_mad *mad ) { 78 int rc; 79 80 /* Construct MAD */ 81 memset ( mad, 0, sizeof ( *mad ) ); 82 mad->hdr.base_version = IB_MGMT_BASE_VERSION; 83 mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; 84 mad->hdr.class_version = 1; 85 mad->hdr.method = IB_MGMT_METHOD_GET; 86 mad->hdr.attr_id = htons ( IB_SMP_ATTR_GUID_INFO ); 87 88 if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) { 89 DBGC ( ibdev, "IBDEV %p could not get GUID info: %s\n", 90 ibdev, strerror ( rc ) ); 91 return rc; 92 } 93 return 0; 94 } 95 96 /** 97 * Get partition key table 98 * 99 * @v ibdev Infiniband device 100 * @v local_mad Method for issuing local MADs 101 * @v mad Management datagram to fill in 102 * @ret rc Return status code 103 */ 104 static int ib_smc_get_pkey_table ( struct ib_device *ibdev, 105 ib_local_mad_t local_mad, 106 union ib_mad *mad ) { 107 int rc; 108 109 /* Construct MAD */ 110 memset ( mad, 0, sizeof ( *mad ) ); 111 mad->hdr.base_version = IB_MGMT_BASE_VERSION; 112 mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; 113 mad->hdr.class_version = 1; 114 mad->hdr.method = IB_MGMT_METHOD_GET; 115 mad->hdr.attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE ); 116 117 if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) { 118 DBGC ( ibdev, "IBDEV %p could not get pkey table: %s\n", 119 ibdev, strerror ( rc ) ); 120 return rc; 121 } 122 return 0; 123 } 124 125 /** 126 * Get MAD parameters 127 * 128 * @v ibdev Infiniband device 129 * @v local_mad Method for issuing local MADs 130 * @ret rc Return status code 131 */ 132 int ib_smc_update ( struct ib_device *ibdev, ib_local_mad_t local_mad ) { 133 union ib_mad mad; 134 struct ib_port_info *port_info = &mad.smp.smp_data.port_info; 135 struct ib_guid_info *guid_info = &mad.smp.smp_data.guid_info; 136 struct ib_pkey_table *pkey_table = &mad.smp.smp_data.pkey_table; 137 int rc; 138 139 /* Port info gives us the link state, the first half of the 140 * port GID and the SM LID. 141 */ 142 if ( ( rc = ib_smc_get_port_info ( ibdev, local_mad, &mad ) ) != 0 ) 143 return rc; 144 memcpy ( &ibdev->gid.u.half[0], port_info->gid_prefix, 145 sizeof ( ibdev->gid.u.half[0] ) ); 146 ibdev->lid = ntohs ( port_info->lid ); 147 ibdev->sm_lid = ntohs ( port_info->mastersm_lid ); 148 ibdev->link_width_enabled = port_info->link_width_enabled; 149 ibdev->link_width_supported = port_info->link_width_supported; 150 ibdev->link_width_active = port_info->link_width_active; 151 ibdev->link_speed_supported = 152 ( port_info->link_speed_supported__port_state >> 4 ); 153 ibdev->port_state = 154 ( port_info->link_speed_supported__port_state & 0xf ); 155 ibdev->link_speed_active = 156 ( port_info->link_speed_active__link_speed_enabled >> 4 ); 157 ibdev->link_speed_enabled = 158 ( port_info->link_speed_active__link_speed_enabled & 0xf ); 159 ibdev->sm_sl = ( port_info->neighbour_mtu__mastersm_sl & 0xf ); 160 161 /* GUID info gives us the second half of the port GID */ 162 if ( ( rc = ib_smc_get_guid_info ( ibdev, local_mad, &mad ) ) != 0 ) 163 return rc; 164 memcpy ( &ibdev->gid.u.half[1], guid_info->guid[0], 165 sizeof ( ibdev->gid.u.half[1] ) ); 166 167 /* Get partition key */ 168 if ( ( rc = ib_smc_get_pkey_table ( ibdev, local_mad, &mad ) ) != 0 ) 169 return rc; 170 ibdev->pkey = ntohs ( pkey_table->pkey[0] ); 171 172 DBGC ( ibdev, "IBDEV %p port GID is %08x:%08x:%08x:%08x\n", ibdev, 173 htonl ( ibdev->gid.u.dwords[0] ), 174 htonl ( ibdev->gid.u.dwords[1] ), 175 htonl ( ibdev->gid.u.dwords[2] ), 176 htonl ( ibdev->gid.u.dwords[3] ) ); 177 178 return 0; 179 } 180