[infiniband] Update subnet management agent to use a management interface
authorMichael Brown <mcb30@etherboot.org>
Mon, 3 Aug 2009 16:47:55 +0000 (17:47 +0100)
committerMichael Brown <mcb30@etherboot.org>
Sat, 8 Aug 2009 22:55:29 +0000 (23:55 +0100)
src/drivers/infiniband/linda.c
src/include/gpxe/ib_mad.h
src/include/gpxe/ib_packet.h
src/include/gpxe/ib_sma.h [new file with mode: 0644]
src/include/gpxe/infiniband.h
src/net/infiniband.c
src/net/infiniband/ib_gma.c
src/net/infiniband/ib_sma.c [new file with mode: 0644]

index c8e44bf..7893e06 100644 (file)
@@ -1606,15 +1606,15 @@ static int linda_read_eeprom ( struct linda *linda,
 
        /* Read GUID */
        if ( ( rc = i2c->read ( i2c, &linda->eeprom, LINDA_EEPROM_GUID_OFFSET,
-                               guid->bytes, sizeof ( *guid ) ) ) != 0 ) {
+                               guid->u.bytes, sizeof ( *guid ) ) ) != 0 ) {
                DBGC ( linda, "Linda %p could not read GUID: %s\n",
                       linda, strerror ( rc ) );
                return rc;
        }
        DBGC2 ( linda, "Linda %p has GUID %02x:%02x:%02x:%02x:%02x:%02x:"
-               "%02x:%02x\n", linda, guid->bytes[0], guid->bytes[1],
-               guid->bytes[2], guid->bytes[3], guid->bytes[4],
-               guid->bytes[5], guid->bytes[6], guid->bytes[7] );
+               "%02x:%02x\n", linda, guid->u.bytes[0], guid->u.bytes[1],
+               guid->u.bytes[2], guid->u.bytes[3], guid->u.bytes[4],
+               guid->u.bytes[5], guid->u.bytes[6], guid->u.bytes[7] );
 
        /* Read serial number (debug only) */
        if ( DBG_LOG ) {
index cfd8ef9..ac9a1d4 100644 (file)
@@ -30,9 +30,6 @@ struct ib_smp_hdr {
        uint8_t reserved[28];
 } __attribute__ (( packed ));
 
-/** Bits to ignore in the management class for subnet management MADs */
-#define IB_SMP_CLASS_IGNORE                    0x80
-
 /** Subnet management class version */
 #define IB_SMP_CLASS_VERSION                   1
 
index a014352..d468859 100644 (file)
@@ -16,7 +16,11 @@ struct io_buffer;
 
 /** Half of an Infiniband Global Identifier */
 struct ib_gid_half {
-       uint8_t bytes[8];
+       union {
+               uint8_t bytes[8];
+               uint16_t words[4];
+               uint32_t dwords[2];
+       } u;
 };
 
 /** An Infiniband Global Identifier */
diff --git a/src/include/gpxe/ib_sma.h b/src/include/gpxe/ib_sma.h
new file mode 100644 (file)
index 0000000..78fc672
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _GPXE_IB_SMA_H
+#define _GPXE_IB_SMA_H
+
+/** @file
+ *
+ * Infiniband subnet management agent
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct ib_device;
+struct ib_mad_interface;
+
+extern int ib_create_sma ( struct ib_device *ibdev,
+                          struct ib_mad_interface *mi );
+extern void ib_destroy_sma ( struct ib_device *ibdev,
+                            struct ib_mad_interface *mi );
+
+#endif /* _GPXE_IB_SMA_H */
index 2581b17..d300a77 100644 (file)
@@ -45,6 +45,7 @@ struct ib_device;
 struct ib_queue_pair;
 struct ib_address_vector;
 struct ib_completion_queue;
+struct ib_mad_interface;
 struct ib_gma;
 
 /** Infiniband transmission rates */
@@ -413,8 +414,8 @@ struct ib_device {
         */
        uint32_t rdma_key;
 
-       /** Subnet management agent */
-       struct ib_gma *sma;
+       /** Subnet management interface */
+       struct ib_mad_interface *smi;
        /** General management agent */
        struct ib_gma *gma;
 
index 1677081..a0dfc5b 100644 (file)
@@ -33,6 +33,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <gpxe/ipoib.h>
 #include <gpxe/process.h>
 #include <gpxe/infiniband.h>
+#include <gpxe/ib_mi.h>
+#include <gpxe/ib_sma.h>
 #include <gpxe/ib_gma.h>
 
 /** @file
@@ -534,11 +536,18 @@ int ib_open ( struct ib_device *ibdev ) {
                return 0;
        }
 
-       /* Create subnet management agent */
-       ibdev->sma = ib_create_gma ( ibdev, IB_QPT_SMI );
-       if ( ! ibdev->sma ) {
-               DBGC ( ibdev, "IBDEV %p could not create SMA\n", ibdev );
+       /* Create subnet management interface */
+       ibdev->smi = ib_create_mi ( ibdev, IB_QPT_SMI );
+       if ( ! ibdev->smi ) {
+               DBGC ( ibdev, "IBDEV %p could not create SMI\n", ibdev );
                rc = -ENOMEM;
+               goto err_create_smi;
+       }
+
+       /* Create subnet management agent */
+       if ( ( rc = ib_create_sma ( ibdev, ibdev->smi ) ) != 0 ) {
+               DBGC ( ibdev, "IBDEV %p could not create SMA: %s\n",
+                      ibdev, strerror ( rc ) );
                goto err_create_sma;
        }
 
@@ -564,8 +573,10 @@ int ib_open ( struct ib_device *ibdev ) {
  err_open:
        ib_destroy_gma ( ibdev->gma );
  err_create_gma:
-       ib_destroy_gma ( ibdev->sma );
+       ib_destroy_sma ( ibdev, ibdev->smi );
  err_create_sma:
+       ib_destroy_mi ( ibdev, ibdev->smi );
+ err_create_smi:
        assert ( ibdev->open_count == 1 );
        ibdev->open_count = 0;
        return rc;
@@ -584,7 +595,8 @@ void ib_close ( struct ib_device *ibdev ) {
        /* Close device if this was the last remaining requested opening */
        if ( ibdev->open_count == 0 ) {
                ib_destroy_gma ( ibdev->gma );
-               ib_destroy_gma ( ibdev->sma );
+               ib_destroy_sma ( ibdev, ibdev->smi );
+               ib_destroy_mi ( ibdev, ibdev->smi );
                ibdev->op->close ( ibdev );
        }
 }
index 1a87b26..f11a9fa 100644 (file)
@@ -74,303 +74,6 @@ struct ib_mad_request {
 /** TID to use for next MAD request */
 static unsigned int next_request_tid;
 
-/*****************************************************************************
- *
- * Subnet management MAD handlers
- *
- *****************************************************************************
- */
-
-/**
- * Construct directed route response, if necessary
- *
- * @v gma              General management agent
- * @v mad              MAD response without DR fields filled in
- * @ret mad            MAD response with DR fields filled in
- */
-static union ib_mad * ib_sma_dr_response ( struct ib_gma *gma,
-                                          union ib_mad *mad ) {
-       struct ib_mad_hdr *hdr = &mad->hdr;
-       struct ib_mad_smp *smp = &mad->smp;
-       unsigned int hop_pointer;
-       unsigned int hop_count;
-
-       /* Set response fields for directed route SMPs */
-       if ( hdr->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) {
-               hdr->status |= htons ( IB_SMP_STATUS_D_INBOUND );
-               hop_pointer = smp->mad_hdr.class_specific.smp.hop_pointer;
-               hop_count = smp->mad_hdr.class_specific.smp.hop_count;
-               assert ( hop_count == hop_pointer );
-               if ( hop_pointer < ( sizeof ( smp->return_path.hops ) /
-                                    sizeof ( smp->return_path.hops[0] ) ) ) {
-                       smp->return_path.hops[hop_pointer] = gma->ibdev->port;
-               } else {
-                       DBGC ( gma, "GMA %p invalid hop pointer %d\n",
-                              gma, hop_pointer );
-                       return NULL;
-               }
-       }
-
-       return mad;
-}
-
-/**
- * Get node information
- *
- * @v gma              General management agent
- * @v mad              MAD
- * @ret response       MAD response
- */
-static union ib_mad * ib_sma_get_node_info ( struct ib_gma *gma,
-                                            union ib_mad *mad ) {
-       struct ib_device *ibdev = gma->ibdev;
-       struct ib_node_info *node_info = &mad->smp.smp_data.node_info;
-
-       memset ( node_info, 0, sizeof ( *node_info ) );
-       node_info->base_version = IB_MGMT_BASE_VERSION;
-       node_info->class_version = IB_SMP_CLASS_VERSION;
-       node_info->node_type = IB_NODE_TYPE_HCA;
-       node_info->num_ports = ib_get_hca_info ( ibdev, &node_info->sys_guid );
-       memcpy ( &node_info->node_guid, &node_info->sys_guid,
-                sizeof ( node_info->node_guid ) );
-       memcpy ( &node_info->port_guid, &ibdev->gid.u.half[1],
-                sizeof ( node_info->port_guid ) );
-       node_info->partition_cap = htons ( 1 );
-       node_info->local_port_num = ibdev->port;
-
-       mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
-       return ib_sma_dr_response ( gma, mad );
-}
-
-/**
- * Get node description
- *
- * @v gma              General management agent
- * @v mad              MAD
- * @ret response       MAD response
- */
-static union ib_mad * ib_sma_get_node_desc ( struct ib_gma *gma,
-                                            union ib_mad *mad ) {
-       struct ib_device *ibdev = gma->ibdev;
-       struct ib_node_desc *node_desc = &mad->smp.smp_data.node_desc;
-       struct ib_gid_half *guid = &ibdev->gid.u.half[1];
-
-       memset ( node_desc, 0, sizeof ( *node_desc ) );
-       snprintf ( node_desc->node_string, sizeof ( node_desc->node_string ),
-                  "gPXE %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)",
-                  guid->bytes[0], guid->bytes[1], guid->bytes[2],
-                  guid->bytes[3], guid->bytes[4], guid->bytes[5],
-                  guid->bytes[6], guid->bytes[7], ibdev->dev->name );
-
-       mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
-       return ib_sma_dr_response ( gma, mad );
-}
-
-/**
- * Get GUID information
- *
- * @v gma              General management agent
- * @v mad              MAD
- * @ret response       MAD response
- */
-static union ib_mad * ib_sma_get_guid_info ( struct ib_gma *gma,
-                                            union ib_mad *mad ) {
-       struct ib_device *ibdev = gma->ibdev;
-       struct ib_guid_info *guid_info = &mad->smp.smp_data.guid_info;
-
-       memset ( guid_info, 0, sizeof ( *guid_info ) );
-       memcpy ( guid_info->guid[0], &ibdev->gid.u.half[1],
-                sizeof ( guid_info->guid[0] ) );
-
-       mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
-       return ib_sma_dr_response ( gma, mad );
-}
-
-/**
- * Get port information
- *
- * @v gma              General management agent
- * @v mad              MAD
- * @ret response       MAD response
- */
-static union ib_mad * ib_sma_get_port_info ( struct ib_gma *gma,
-                                            union ib_mad *mad ) {
-       struct ib_device *ibdev = gma->ibdev;
-       struct ib_port_info *port_info = &mad->smp.smp_data.port_info;
-
-       memset ( port_info, 0, sizeof ( *port_info ) );
-       memcpy ( port_info->gid_prefix, &ibdev->gid.u.half[0],
-                sizeof ( port_info->gid_prefix ) );
-       port_info->lid = ntohs ( ibdev->lid );
-       port_info->mastersm_lid = ntohs ( ibdev->sm_lid );
-       port_info->local_port_num = ibdev->port;
-       port_info->link_width_enabled = ibdev->link_width_enabled;
-       port_info->link_width_supported = ibdev->link_width_supported;
-       port_info->link_width_active = ibdev->link_width_active;
-       port_info->link_speed_supported__port_state =
-               ( ( ibdev->link_speed_supported << 4 ) | ibdev->port_state );
-       port_info->port_phys_state__link_down_def_state =
-               ( ( IB_PORT_PHYS_STATE_POLLING << 4 ) |
-                 IB_PORT_PHYS_STATE_POLLING );
-       port_info->link_speed_active__link_speed_enabled =
-               ( ( ibdev->link_speed_active << 4 ) |
-                 ibdev->link_speed_enabled );
-       port_info->neighbour_mtu__mastersm_sl =
-               ( ( IB_MTU_2048 << 4 ) | ibdev->sm_sl );
-       port_info->vl_cap__init_type = ( IB_VL_0 << 4 );
-       port_info->init_type_reply__mtu_cap = IB_MTU_2048;
-       port_info->operational_vls__enforcement = ( IB_VL_0 << 4 );
-       port_info->guid_cap = 1;
-
-       mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
-       return ib_sma_dr_response ( gma, mad );
-}
-
-/**
- * Set port information
- *
- * @v gma              General management agent
- * @v mad              MAD
- * @ret response       MAD response
- */
-static union ib_mad * ib_sma_set_port_info ( struct ib_gma *gma,
-                                            union ib_mad *mad ) {
-       struct ib_device *ibdev = gma->ibdev;
-       const struct ib_port_info *port_info = &mad->smp.smp_data.port_info;
-       unsigned int link_width_enabled;
-       unsigned int link_speed_enabled;
-       int rc;
-
-       memcpy ( &ibdev->gid.u.half[0], port_info->gid_prefix,
-                sizeof ( ibdev->gid.u.half[0] ) );
-       ibdev->lid = ntohs ( port_info->lid );
-       ibdev->sm_lid = ntohs ( port_info->mastersm_lid );
-       if ( ( link_width_enabled = port_info->link_width_enabled ) )
-               ibdev->link_width_enabled = link_width_enabled;
-       if ( ( link_speed_enabled =
-              ( port_info->link_speed_active__link_speed_enabled & 0xf ) ) )
-               ibdev->link_speed_enabled = link_speed_enabled;
-       ibdev->sm_sl = ( port_info->neighbour_mtu__mastersm_sl & 0xf );
-       DBGC ( gma, "GMA %p set LID %04x SMLID %04x link width %02x speed "
-              "%02x\n", gma, ibdev->lid, ibdev->sm_lid,
-              ibdev->link_width_enabled, ibdev->link_speed_enabled );
-
-       if ( ( rc = ib_set_port_info ( ibdev, mad ) ) != 0 ) {
-               DBGC ( gma, "GMA %p could not set port information: %s\n",
-                      gma, strerror ( rc ) );
-               mad->hdr.status =
-                       htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
-       }
-
-       return ib_sma_get_port_info ( gma, mad );
-}
-
-/**
- * Get partition key table
- *
- * @v gma              General management agent
- * @v mad              MAD
- * @ret response       MAD response
- */
-static union ib_mad * ib_sma_get_pkey_table ( struct ib_gma *gma,
-                                             union ib_mad *mad ) {
-       struct ib_device *ibdev = gma->ibdev;
-       struct ib_pkey_table *pkey_table = &mad->smp.smp_data.pkey_table;
-
-       mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
-       memset ( pkey_table, 0, sizeof ( *pkey_table ) );
-       pkey_table->pkey[0] = htons ( ibdev->pkey );
-
-       mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
-       return ib_sma_dr_response ( gma, mad );
-}
-
-/**
- * Set partition key table
- *
- * @v gma              General management agent
- * @v mad              MAD
- * @ret response       MAD response
- */
-static union ib_mad * ib_sma_set_pkey_table ( struct ib_gma *gma,
-                                             union ib_mad *mad ) {
-       struct ib_device *ibdev = gma->ibdev;
-       struct ib_pkey_table *pkey_table = &mad->smp.smp_data.pkey_table;
-       int rc;
-
-       ibdev->pkey = ntohs ( pkey_table->pkey[0] );
-       DBGC ( gma, "GMA %p set pkey %04x\n", gma, ibdev->pkey );
-
-       if ( ( rc = ib_set_pkey_table ( ibdev, mad ) ) != 0 ) {
-               DBGC ( gma, "GMA %p could not set pkey table: %s\n",
-                      gma, strerror ( rc ) );
-               mad->hdr.status =
-                       htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
-       }
-
-       return ib_sma_get_pkey_table ( gma, mad );
-}
-
-/** List of attribute handlers */
-struct ib_gma_handler ib_sma_handlers[] __ib_gma_handler = {
-       {
-               .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
-               .mgmt_class_ignore = IB_SMP_CLASS_IGNORE,
-               .class_version = IB_SMP_CLASS_VERSION,
-               .method = IB_MGMT_METHOD_GET,
-               .attr_id = htons ( IB_SMP_ATTR_NODE_INFO ),
-               .handle = ib_sma_get_node_info,
-       },
-       {
-               .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
-               .mgmt_class_ignore = IB_SMP_CLASS_IGNORE,
-               .class_version = IB_SMP_CLASS_VERSION,
-               .method = IB_MGMT_METHOD_GET,
-               .attr_id = htons ( IB_SMP_ATTR_NODE_DESC ),
-               .handle = ib_sma_get_node_desc,
-       },
-       {
-               .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
-               .mgmt_class_ignore = IB_SMP_CLASS_IGNORE,
-               .class_version = IB_SMP_CLASS_VERSION,
-               .method = IB_MGMT_METHOD_GET,
-               .attr_id = htons ( IB_SMP_ATTR_GUID_INFO ),
-               .handle = ib_sma_get_guid_info,
-       },
-       {
-               .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
-               .mgmt_class_ignore = IB_SMP_CLASS_IGNORE,
-               .class_version = IB_SMP_CLASS_VERSION,
-               .method = IB_MGMT_METHOD_GET,
-               .attr_id = htons ( IB_SMP_ATTR_PORT_INFO ),
-               .handle = ib_sma_get_port_info,
-       },
-       {
-               .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
-               .mgmt_class_ignore = IB_SMP_CLASS_IGNORE,
-               .class_version = IB_SMP_CLASS_VERSION,
-               .method = IB_MGMT_METHOD_SET,
-               .attr_id = htons ( IB_SMP_ATTR_PORT_INFO ),
-               .handle = ib_sma_set_port_info,
-       },
-       {
-               .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
-               .mgmt_class_ignore = IB_SMP_CLASS_IGNORE,
-               .class_version = IB_SMP_CLASS_VERSION,
-               .method = IB_MGMT_METHOD_GET,
-               .attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE ),
-               .handle = ib_sma_get_pkey_table,
-       },
-       {
-               .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
-               .mgmt_class_ignore = IB_SMP_CLASS_IGNORE,
-               .class_version = IB_SMP_CLASS_VERSION,
-               .method = IB_MGMT_METHOD_SET,
-               .attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE ),
-               .handle = ib_sma_set_pkey_table,
-       },
-};
-
 /*****************************************************************************
  *
  * General management agent
diff --git a/src/net/infiniband/ib_sma.c b/src/net/infiniband/ib_sma.c
new file mode 100644 (file)
index 0000000..eb4f987
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2009 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 <stdio.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <gpxe/infiniband.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/ib_mi.h>
+#include <gpxe/ib_sma.h>
+
+/**
+ * @file
+ *
+ * Infiniband Subnet Management Agent
+ *
+ */
+
+/**
+ * Node information
+ *
+ * @v ibdev            Infiniband device
+ * @v mi               Management interface
+ * @v mad              Received MAD
+ * @v av               Source address vector
+ */
+static void ib_sma_node_info ( struct ib_device *ibdev,
+                              struct ib_mad_interface *mi,
+                              union ib_mad *mad,
+                              struct ib_address_vector *av ) {
+       struct ib_node_info *node_info = &mad->smp.smp_data.node_info;
+       int rc;
+
+       /* Fill in information */
+       memset ( node_info, 0, sizeof ( *node_info ) );
+       node_info->base_version = IB_MGMT_BASE_VERSION;
+       node_info->class_version = IB_SMP_CLASS_VERSION;
+       node_info->node_type = IB_NODE_TYPE_HCA;
+       node_info->num_ports = ib_get_hca_info ( ibdev, &node_info->sys_guid );
+       memcpy ( &node_info->node_guid, &node_info->sys_guid,
+                sizeof ( node_info->node_guid ) );
+       memcpy ( &node_info->port_guid, &ibdev->gid.u.half[1],
+                sizeof ( node_info->port_guid ) );
+       node_info->partition_cap = htons ( 1 );
+       node_info->local_port_num = ibdev->port;
+
+       /* Send GetResponse */
+       mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
+       if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
+               DBGC ( mi, "SMA %p could not send NodeInfo GetResponse: %s\n",
+                      mi, strerror ( rc ) );
+               return;
+       }
+}
+
+/**
+ * Node description
+ *
+ * @v ibdev            Infiniband device
+ * @v mi               Management interface
+ * @v mad              Received MAD
+ * @v av               Source address vector
+ */
+static void ib_sma_node_desc ( struct ib_device *ibdev,
+                              struct ib_mad_interface *mi,
+                              union ib_mad *mad,
+                              struct ib_address_vector *av ) {
+       struct ib_node_desc *node_desc = &mad->smp.smp_data.node_desc;
+       struct ib_gid_half *guid = &ibdev->gid.u.half[1];
+       int rc;
+
+       /* Fill in information */
+       memset ( node_desc, 0, sizeof ( *node_desc ) );
+       snprintf ( node_desc->node_string, sizeof ( node_desc->node_string ),
+                  "gPXE %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)",
+                  guid->u.bytes[0], guid->u.bytes[1], guid->u.bytes[2],
+                  guid->u.bytes[3], guid->u.bytes[4], guid->u.bytes[5],
+                  guid->u.bytes[6], guid->u.bytes[7], ibdev->dev->name );
+
+       /* Send GetResponse */
+       mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
+       if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
+               DBGC ( mi, "SMA %p could not send NodeDesc GetResponse: %s\n",
+                      mi, strerror ( rc ) );
+               return;
+       }
+}
+
+/**
+ * GUID information
+ *
+ * @v ibdev            Infiniband device
+ * @v mi               Management interface
+ * @v mad              Received MAD
+ * @v av               Source address vector
+ */
+static void ib_sma_guid_info ( struct ib_device *ibdev,
+                              struct ib_mad_interface *mi,
+                              union ib_mad *mad,
+                              struct ib_address_vector *av ) {
+       struct ib_guid_info *guid_info = &mad->smp.smp_data.guid_info;
+       int rc;
+
+       /* Fill in information */
+       memset ( guid_info, 0, sizeof ( *guid_info ) );
+       memcpy ( guid_info->guid[0], &ibdev->gid.u.half[1],
+                sizeof ( guid_info->guid[0] ) );
+
+       /* Send GetResponse */
+       mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
+       if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
+               DBGC ( mi, "SMA %p could not send GuidInfo GetResponse: %s\n",
+                      mi, strerror ( rc ) );
+               return;
+       }
+}
+
+/**
+ * Set port information
+ *
+ * @v ibdev            Infiniband device
+ * @v mi               Management interface
+ * @v mad              Received MAD
+ * @ret rc             Return status code
+ */
+static int ib_sma_set_port_info ( struct ib_device *ibdev,
+                                 struct ib_mad_interface *mi,
+                                 union ib_mad *mad ) {
+       const struct ib_port_info *port_info = &mad->smp.smp_data.port_info;
+       unsigned int link_width_enabled;
+       unsigned int link_speed_enabled;
+       int rc;
+
+       /* Set parameters */
+       memcpy ( &ibdev->gid.u.half[0], port_info->gid_prefix,
+                sizeof ( ibdev->gid.u.half[0] ) );
+       ibdev->lid = ntohs ( port_info->lid );
+       ibdev->sm_lid = ntohs ( port_info->mastersm_lid );
+       if ( ( link_width_enabled = port_info->link_width_enabled ) )
+               ibdev->link_width_enabled = link_width_enabled;
+       if ( ( link_speed_enabled =
+              ( port_info->link_speed_active__link_speed_enabled & 0xf ) ) )
+               ibdev->link_speed_enabled = link_speed_enabled;
+       ibdev->sm_sl = ( port_info->neighbour_mtu__mastersm_sl & 0xf );
+       DBGC ( mi, "SMA %p set LID %04x SMLID %04x link width %02x speed "
+              "%02x\n", mi, ibdev->lid, ibdev->sm_lid,
+              ibdev->link_width_enabled, ibdev->link_speed_enabled );
+
+       /* Update parameters on device */
+       if ( ( rc = ib_set_port_info ( ibdev, mad ) ) != 0 ) {
+               DBGC ( mi, "SMA %p could not set port information: %s\n",
+                      mi, strerror ( rc ) );
+               return rc;
+       }
+
+       return 0;
+}
+
+/**
+ * Port information
+ *
+ * @v ibdev            Infiniband device
+ * @v mi               Management interface
+ * @v mad              Received MAD
+ * @v av               Source address vector
+ */
+static void ib_sma_port_info ( struct ib_device *ibdev,
+                              struct ib_mad_interface *mi,
+                              union ib_mad *mad,
+                              struct ib_address_vector *av ) {
+       struct ib_port_info *port_info = &mad->smp.smp_data.port_info;
+       int rc;
+
+       /* Set parameters if applicable */
+       if ( mad->hdr.method == IB_MGMT_METHOD_SET ) {
+               if ( ( rc = ib_sma_set_port_info ( ibdev, mi, mad ) ) != 0 ) {
+                       mad->hdr.status =
+                             htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
+                       /* Fall through to generate GetResponse */
+               }
+       }
+
+       /* Fill in information */
+       memset ( port_info, 0, sizeof ( *port_info ) );
+       memcpy ( port_info->gid_prefix, &ibdev->gid.u.half[0],
+                sizeof ( port_info->gid_prefix ) );
+       port_info->lid = ntohs ( ibdev->lid );
+       port_info->mastersm_lid = ntohs ( ibdev->sm_lid );
+       port_info->local_port_num = ibdev->port;
+       port_info->link_width_enabled = ibdev->link_width_enabled;
+       port_info->link_width_supported = ibdev->link_width_supported;
+       port_info->link_width_active = ibdev->link_width_active;
+       port_info->link_speed_supported__port_state =
+               ( ( ibdev->link_speed_supported << 4 ) | ibdev->port_state );
+       port_info->port_phys_state__link_down_def_state =
+               ( ( IB_PORT_PHYS_STATE_POLLING << 4 ) |
+                 IB_PORT_PHYS_STATE_POLLING );
+       port_info->link_speed_active__link_speed_enabled =
+               ( ( ibdev->link_speed_active << 4 ) |
+                 ibdev->link_speed_enabled );
+       port_info->neighbour_mtu__mastersm_sl =
+               ( ( IB_MTU_2048 << 4 ) | ibdev->sm_sl );
+       port_info->vl_cap__init_type = ( IB_VL_0 << 4 );
+       port_info->init_type_reply__mtu_cap = IB_MTU_2048;
+       port_info->operational_vls__enforcement = ( IB_VL_0 << 4 );
+       port_info->guid_cap = 1;
+
+       /* Send GetResponse */
+       mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
+       if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
+               DBGC ( mi, "SMA %p could not send PortInfo GetResponse: %s\n",
+                      mi, strerror ( rc ) );
+               return;
+       }
+}
+
+/**
+ * Set partition key table
+ *
+ * @v ibdev            Infiniband device
+ * @v mi               Management interface
+ * @v mad              Received MAD
+ * @ret rc             Return status code
+ */
+static int ib_sma_set_pkey_table ( struct ib_device *ibdev,
+                                  struct ib_mad_interface *mi,
+                                  union ib_mad *mad ) {
+       struct ib_pkey_table *pkey_table = &mad->smp.smp_data.pkey_table;
+       int rc;
+
+       /* Set parameters */
+       ibdev->pkey = ntohs ( pkey_table->pkey[0] );
+       DBGC ( mi, "SMA %p set pkey %04x\n", mi, ibdev->pkey );
+
+       /* Update parameters on device */
+       if ( ( rc = ib_set_pkey_table ( ibdev, mad ) ) != 0 ) {
+               DBGC ( mi, "SMA %p could not set pkey table: %s\n",
+                      mi, strerror ( rc ) );
+               return rc;
+       }
+
+       return 0;
+}
+
+/**
+ * Partition key table
+ *
+ * @v ibdev            Infiniband device
+ * @v mi               Management interface
+ * @v mad              Received MAD
+ * @v av               Source address vector
+ */
+static void ib_sma_pkey_table ( struct ib_device *ibdev,
+                               struct ib_mad_interface *mi,
+                               union ib_mad *mad,
+                               struct ib_address_vector *av ) {
+       struct ib_pkey_table *pkey_table = &mad->smp.smp_data.pkey_table;
+       int rc;
+
+       /* Set parameters, if applicable */
+       if ( mad->hdr.method == IB_MGMT_METHOD_SET ) {
+               if ( ( rc = ib_sma_set_pkey_table ( ibdev, mi, mad ) ) != 0 ) {
+                       mad->hdr.status =
+                             htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
+                       /* Fall through to generate GetResponse */
+               }
+       }
+
+       /* Fill in information */
+       mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
+       memset ( pkey_table, 0, sizeof ( *pkey_table ) );
+       pkey_table->pkey[0] = htons ( ibdev->pkey );
+
+       /* Send GetResponse */
+       mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
+       if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
+               DBGC ( mi, "SMA %p could not send PKeyTable GetResponse: %s\n",
+                      mi, strerror ( rc ) );
+               return;
+       }
+}
+
+/** Subnet management agent */
+struct ib_mad_agent ib_sma_agent[] __ib_mad_agent = {
+       {
+               .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
+               .class_version = IB_SMP_CLASS_VERSION,
+               .attr_id = htons ( IB_SMP_ATTR_NODE_INFO ),
+               .handle = ib_sma_node_info,
+       },
+       {
+               .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
+               .class_version = IB_SMP_CLASS_VERSION,
+               .attr_id = htons ( IB_SMP_ATTR_NODE_DESC ),
+               .handle = ib_sma_node_desc,
+       },
+       {
+               .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
+               .class_version = IB_SMP_CLASS_VERSION,
+               .attr_id = htons ( IB_SMP_ATTR_GUID_INFO ),
+               .handle = ib_sma_guid_info,
+       },
+       {
+               .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
+               .class_version = IB_SMP_CLASS_VERSION,
+               .attr_id = htons ( IB_SMP_ATTR_PORT_INFO ),
+               .handle = ib_sma_port_info,
+       },
+       {
+               .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
+               .class_version = IB_SMP_CLASS_VERSION,
+               .attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE ),
+               .handle = ib_sma_pkey_table,
+       },
+};
+
+/**
+ * Create subnet management agent and interface
+ *
+ * @v ibdev            Infiniband device
+ * @v mi               Management interface
+ * @ret rc             Return status code
+ */
+int ib_create_sma ( struct ib_device *ibdev, struct ib_mad_interface *mi ) {
+
+       /* Nothing to do */
+       DBGC ( ibdev, "IBDEV %p SMA using SMI %p\n", ibdev, mi );
+
+       return 0;
+}
+
+/**
+ * Destroy subnet management agent and interface
+ *
+ * @v ibdev            Infiniband device
+ * @v mi               Management interface
+ */
+void ib_destroy_sma ( struct ib_device *ibdev __unused,
+                     struct ib_mad_interface *mi __unused ) {
+       /* Nothing to do */
+}