iPXE
ib_sma.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stdint.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <errno.h>
00030 #include <stdio.h>
00031 #include <unistd.h>
00032 #include <byteswap.h>
00033 #include <ipxe/settings.h>
00034 #include <ipxe/infiniband.h>
00035 #include <ipxe/iobuf.h>
00036 #include <ipxe/ib_mi.h>
00037 #include <ipxe/ib_sma.h>
00038 
00039 /**
00040  * @file
00041  *
00042  * Infiniband Subnet Management Agent
00043  *
00044  */
00045 
00046 /**
00047  * Node information
00048  *
00049  * @v ibdev             Infiniband device
00050  * @v mi                Management interface
00051  * @v mad               Received MAD
00052  * @v av                Source address vector
00053  */
00054 static void ib_sma_node_info ( struct ib_device *ibdev,
00055                                struct ib_mad_interface *mi,
00056                                union ib_mad *mad,
00057                                struct ib_address_vector *av ) {
00058         struct ib_node_info *node_info = &mad->smp.smp_data.node_info;
00059         int rc;
00060 
00061         /* Fill in information */
00062         memset ( node_info, 0, sizeof ( *node_info ) );
00063         node_info->base_version = IB_MGMT_BASE_VERSION;
00064         node_info->class_version = IB_SMP_CLASS_VERSION;
00065         node_info->node_type = IB_NODE_TYPE_HCA;
00066         node_info->num_ports = ib_count_ports ( ibdev );
00067         memcpy ( &node_info->sys_guid, &ibdev->node_guid,
00068                  sizeof ( node_info->sys_guid ) );
00069         memcpy ( &node_info->node_guid, &ibdev->node_guid,
00070                  sizeof ( node_info->node_guid ) );
00071         memcpy ( &node_info->port_guid, &ibdev->gid.s.guid,
00072                  sizeof ( node_info->port_guid ) );
00073         node_info->partition_cap = htons ( 1 );
00074         node_info->local_port_num = ibdev->port;
00075 
00076         /* Send GetResponse */
00077         mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
00078         if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
00079                 DBGC ( mi, "SMA %p could not send NodeInfo GetResponse: %s\n",
00080                        mi, strerror ( rc ) );
00081                 return;
00082         }
00083 }
00084 
00085 /**
00086  * Node description
00087  *
00088  * @v ibdev             Infiniband device
00089  * @v mi                Management interface
00090  * @v mad               Received MAD
00091  * @v av                Source address vector
00092  */
00093 static void ib_sma_node_desc ( struct ib_device *ibdev,
00094                                struct ib_mad_interface *mi,
00095                                union ib_mad *mad,
00096                                struct ib_address_vector *av ) {
00097         struct ib_node_desc *node_desc = &mad->smp.smp_data.node_desc;
00098         union ib_guid *guid = &ibdev->node_guid;
00099         char hostname[ sizeof ( node_desc->node_string ) ];
00100         int hostname_len;
00101         int rc;
00102 
00103         /* Fill in information */
00104         memset ( node_desc, 0, sizeof ( *node_desc ) );
00105         hostname_len = fetch_string_setting ( NULL, &hostname_setting,
00106                                               hostname, sizeof ( hostname ) );
00107         snprintf ( node_desc->node_string, sizeof ( node_desc->node_string ),
00108                    "iPXE %s%s%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)",
00109                    hostname, ( ( hostname_len >= 0 ) ? " " : "" ),
00110                    guid->bytes[0], guid->bytes[1], guid->bytes[2],
00111                    guid->bytes[3], guid->bytes[4], guid->bytes[5],
00112                    guid->bytes[6], guid->bytes[7], ibdev->dev->name );
00113 
00114         /* Send GetResponse */
00115         mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
00116         if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
00117                 DBGC ( mi, "SMA %p could not send NodeDesc GetResponse: %s\n",
00118                        mi, strerror ( rc ) );
00119                 return;
00120         }
00121 }
00122 
00123 /**
00124  * GUID information
00125  *
00126  * @v ibdev             Infiniband device
00127  * @v mi                Management interface
00128  * @v mad               Received MAD
00129  * @v av                Source address vector
00130  */
00131 static void ib_sma_guid_info ( struct ib_device *ibdev,
00132                                struct ib_mad_interface *mi,
00133                                union ib_mad *mad,
00134                                struct ib_address_vector *av ) {
00135         struct ib_guid_info *guid_info = &mad->smp.smp_data.guid_info;
00136         int rc;
00137 
00138         /* Fill in information */
00139         memset ( guid_info, 0, sizeof ( *guid_info ) );
00140         memcpy ( guid_info->guid[0], &ibdev->gid.s.guid,
00141                  sizeof ( guid_info->guid[0] ) );
00142 
00143         /* Send GetResponse */
00144         mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
00145         if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
00146                 DBGC ( mi, "SMA %p could not send GuidInfo GetResponse: %s\n",
00147                        mi, strerror ( rc ) );
00148                 return;
00149         }
00150 }
00151 
00152 /**
00153  * Set port information
00154  *
00155  * @v ibdev             Infiniband device
00156  * @v mi                Management interface
00157  * @v mad               Received MAD
00158  * @ret rc              Return status code
00159  */
00160 static int ib_sma_set_port_info ( struct ib_device *ibdev,
00161                                   struct ib_mad_interface *mi,
00162                                   union ib_mad *mad ) {
00163         const struct ib_port_info *port_info = &mad->smp.smp_data.port_info;
00164         unsigned int link_width_enabled;
00165         unsigned int link_speed_enabled;
00166         int rc;
00167 
00168         /* Set parameters */
00169         memcpy ( &ibdev->gid.s.prefix, port_info->gid_prefix,
00170                  sizeof ( ibdev->gid.s.prefix ) );
00171         ibdev->lid = ntohs ( port_info->lid );
00172         ibdev->sm_lid = ntohs ( port_info->mastersm_lid );
00173         if ( ( link_width_enabled = port_info->link_width_enabled ) )
00174                 ibdev->link_width_enabled = link_width_enabled;
00175         if ( ( link_speed_enabled =
00176                ( port_info->link_speed_active__link_speed_enabled & 0xf ) ) )
00177                 ibdev->link_speed_enabled = link_speed_enabled;
00178         ibdev->sm_sl = ( port_info->neighbour_mtu__mastersm_sl & 0xf );
00179         DBGC ( mi, "SMA %p set LID %d SMLID %d link width %d speed %d\n",
00180                mi, ibdev->lid, ibdev->sm_lid, ibdev->link_width_enabled,
00181                ibdev->link_speed_enabled );
00182 
00183         /* Update parameters on device */
00184         if ( ( rc = ib_set_port_info ( ibdev, mad ) ) != 0 ) {
00185                 DBGC ( mi, "SMA %p could not set port information: %s\n",
00186                        mi, strerror ( rc ) );
00187                 return rc;
00188         }
00189 
00190         return 0;
00191 }
00192 
00193 /**
00194  * Port information
00195  *
00196  * @v ibdev             Infiniband device
00197  * @v mi                Management interface
00198  * @v mad               Received MAD
00199  * @v av                Source address vector
00200  */
00201 static void ib_sma_port_info ( struct ib_device *ibdev,
00202                                struct ib_mad_interface *mi,
00203                                union ib_mad *mad,
00204                                struct ib_address_vector *av ) {
00205         struct ib_port_info *port_info = &mad->smp.smp_data.port_info;
00206         int rc;
00207 
00208         /* Set parameters if applicable */
00209         if ( mad->hdr.method == IB_MGMT_METHOD_SET ) {
00210                 if ( ( rc = ib_sma_set_port_info ( ibdev, mi, mad ) ) != 0 ) {
00211                         mad->hdr.status =
00212                               htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
00213                         /* Fall through to generate GetResponse */
00214                 }
00215         }
00216 
00217         /* Fill in information */
00218         memset ( port_info, 0, sizeof ( *port_info ) );
00219         memcpy ( port_info->gid_prefix, &ibdev->gid.s.prefix,
00220                  sizeof ( port_info->gid_prefix ) );
00221         port_info->lid = ntohs ( ibdev->lid );
00222         port_info->mastersm_lid = ntohs ( ibdev->sm_lid );
00223         port_info->local_port_num = ibdev->port;
00224         port_info->link_width_enabled = ibdev->link_width_enabled;
00225         port_info->link_width_supported = ibdev->link_width_supported;
00226         port_info->link_width_active = ibdev->link_width_active;
00227         port_info->link_speed_supported__port_state =
00228                 ( ( ibdev->link_speed_supported << 4 ) | ibdev->port_state );
00229         port_info->port_phys_state__link_down_def_state =
00230                 ( ( IB_PORT_PHYS_STATE_POLLING << 4 ) |
00231                   IB_PORT_PHYS_STATE_POLLING );
00232         port_info->link_speed_active__link_speed_enabled =
00233                 ( ( ibdev->link_speed_active << 4 ) |
00234                   ibdev->link_speed_enabled );
00235         port_info->neighbour_mtu__mastersm_sl =
00236                 ( ( IB_MTU_2048 << 4 ) | ibdev->sm_sl );
00237         port_info->vl_cap__init_type = ( IB_VL_0 << 4 );
00238         port_info->init_type_reply__mtu_cap = IB_MTU_2048;
00239         port_info->operational_vls__enforcement = ( IB_VL_0 << 4 );
00240         port_info->guid_cap = 1;
00241 
00242         /* Send GetResponse */
00243         mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
00244         if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
00245                 DBGC ( mi, "SMA %p could not send PortInfo GetResponse: %s\n",
00246                        mi, strerror ( rc ) );
00247                 return;
00248         }
00249 }
00250 
00251 /**
00252  * Set partition key table
00253  *
00254  * @v ibdev             Infiniband device
00255  * @v mi                Management interface
00256  * @v mad               Received MAD
00257  * @ret rc              Return status code
00258  */
00259 static int ib_sma_set_pkey_table ( struct ib_device *ibdev,
00260                                    struct ib_mad_interface *mi,
00261                                    union ib_mad *mad ) {
00262         struct ib_pkey_table *pkey_table = &mad->smp.smp_data.pkey_table;
00263         int rc;
00264 
00265         /* Set parameters */
00266         ibdev->pkey = ntohs ( pkey_table->pkey[0] );
00267         DBGC ( mi, "SMA %p set pkey %04x\n", mi, ibdev->pkey );
00268 
00269         /* Update parameters on device */
00270         if ( ( rc = ib_set_pkey_table ( ibdev, mad ) ) != 0 ) {
00271                 DBGC ( mi, "SMA %p could not set pkey table: %s\n",
00272                        mi, strerror ( rc ) );
00273                 return rc;
00274         }
00275 
00276         return 0;
00277 }
00278 
00279 /**
00280  * Partition key table
00281  *
00282  * @v ibdev             Infiniband device
00283  * @v mi                Management interface
00284  * @v mad               Received MAD
00285  * @v av                Source address vector
00286  */
00287 static void ib_sma_pkey_table ( struct ib_device *ibdev,
00288                                 struct ib_mad_interface *mi,
00289                                 union ib_mad *mad,
00290                                 struct ib_address_vector *av ) {
00291         struct ib_pkey_table *pkey_table = &mad->smp.smp_data.pkey_table;
00292         int rc;
00293 
00294         /* Set parameters, if applicable */
00295         if ( mad->hdr.method == IB_MGMT_METHOD_SET ) {
00296                 if ( ( rc = ib_sma_set_pkey_table ( ibdev, mi, mad ) ) != 0 ) {
00297                         mad->hdr.status =
00298                               htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
00299                         /* Fall through to generate GetResponse */
00300                 }
00301         }
00302 
00303         /* Fill in information */
00304         mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
00305         memset ( pkey_table, 0, sizeof ( *pkey_table ) );
00306         pkey_table->pkey[0] = htons ( ibdev->pkey );
00307 
00308         /* Send GetResponse */
00309         mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
00310         if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
00311                 DBGC ( mi, "SMA %p could not send PKeyTable GetResponse: %s\n",
00312                        mi, strerror ( rc ) );
00313                 return;
00314         }
00315 }
00316 
00317 /** Subnet management agent */
00318 struct ib_mad_agent ib_sma_agent[] __ib_mad_agent = {
00319         {
00320                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
00321                 .class_version = IB_SMP_CLASS_VERSION,
00322                 .attr_id = htons ( IB_SMP_ATTR_NODE_INFO ),
00323                 .handle = ib_sma_node_info,
00324         },
00325         {
00326                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
00327                 .class_version = IB_SMP_CLASS_VERSION,
00328                 .attr_id = htons ( IB_SMP_ATTR_NODE_DESC ),
00329                 .handle = ib_sma_node_desc,
00330         },
00331         {
00332                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
00333                 .class_version = IB_SMP_CLASS_VERSION,
00334                 .attr_id = htons ( IB_SMP_ATTR_GUID_INFO ),
00335                 .handle = ib_sma_guid_info,
00336         },
00337         {
00338                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
00339                 .class_version = IB_SMP_CLASS_VERSION,
00340                 .attr_id = htons ( IB_SMP_ATTR_PORT_INFO ),
00341                 .handle = ib_sma_port_info,
00342         },
00343         {
00344                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
00345                 .class_version = IB_SMP_CLASS_VERSION,
00346                 .attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE ),
00347                 .handle = ib_sma_pkey_table,
00348         },
00349 };
00350 
00351 /**
00352  * Create subnet management agent and interface
00353  *
00354  * @v ibdev             Infiniband device
00355  * @v mi                Management interface
00356  * @ret rc              Return status code
00357  */
00358 int ib_create_sma ( struct ib_device *ibdev, struct ib_mad_interface *mi ) {
00359 
00360         /* Nothing to do */
00361         DBGC ( ibdev, "IBDEV %s SMA using SMI %p\n", ibdev->name, mi );
00362 
00363         return 0;
00364 }
00365 
00366 /**
00367  * Destroy subnet management agent and interface
00368  *
00369  * @v ibdev             Infiniband device
00370  * @v mi                Management interface
00371  */
00372 void ib_destroy_sma ( struct ib_device *ibdev __unused,
00373                       struct ib_mad_interface *mi __unused ) {
00374         /* Nothing to do */
00375 }