[infiniband] Update subnet management agent to use a management interface
[people/peper/gpxe.git] / src / net / infiniband / ib_sma.c
1 /*
2  * Copyright (C) 2009 Michael Brown <mbrown@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 <stdio.h>
26 #include <unistd.h>
27 #include <byteswap.h>
28 #include <gpxe/infiniband.h>
29 #include <gpxe/iobuf.h>
30 #include <gpxe/ib_mi.h>
31 #include <gpxe/ib_sma.h>
32
33 /**
34  * @file
35  *
36  * Infiniband Subnet Management Agent
37  *
38  */
39
40 /**
41  * Node information
42  *
43  * @v ibdev             Infiniband device
44  * @v mi                Management interface
45  * @v mad               Received MAD
46  * @v av                Source address vector
47  */
48 static void ib_sma_node_info ( struct ib_device *ibdev,
49                                struct ib_mad_interface *mi,
50                                union ib_mad *mad,
51                                struct ib_address_vector *av ) {
52         struct ib_node_info *node_info = &mad->smp.smp_data.node_info;
53         int rc;
54
55         /* Fill in information */
56         memset ( node_info, 0, sizeof ( *node_info ) );
57         node_info->base_version = IB_MGMT_BASE_VERSION;
58         node_info->class_version = IB_SMP_CLASS_VERSION;
59         node_info->node_type = IB_NODE_TYPE_HCA;
60         node_info->num_ports = ib_get_hca_info ( ibdev, &node_info->sys_guid );
61         memcpy ( &node_info->node_guid, &node_info->sys_guid,
62                  sizeof ( node_info->node_guid ) );
63         memcpy ( &node_info->port_guid, &ibdev->gid.u.half[1],
64                  sizeof ( node_info->port_guid ) );
65         node_info->partition_cap = htons ( 1 );
66         node_info->local_port_num = ibdev->port;
67
68         /* Send GetResponse */
69         mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
70         if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
71                 DBGC ( mi, "SMA %p could not send NodeInfo GetResponse: %s\n",
72                        mi, strerror ( rc ) );
73                 return;
74         }
75 }
76
77 /**
78  * Node description
79  *
80  * @v ibdev             Infiniband device
81  * @v mi                Management interface
82  * @v mad               Received MAD
83  * @v av                Source address vector
84  */
85 static void ib_sma_node_desc ( struct ib_device *ibdev,
86                                struct ib_mad_interface *mi,
87                                union ib_mad *mad,
88                                struct ib_address_vector *av ) {
89         struct ib_node_desc *node_desc = &mad->smp.smp_data.node_desc;
90         struct ib_gid_half *guid = &ibdev->gid.u.half[1];
91         int rc;
92
93         /* Fill in information */
94         memset ( node_desc, 0, sizeof ( *node_desc ) );
95         snprintf ( node_desc->node_string, sizeof ( node_desc->node_string ),
96                    "gPXE %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)",
97                    guid->u.bytes[0], guid->u.bytes[1], guid->u.bytes[2],
98                    guid->u.bytes[3], guid->u.bytes[4], guid->u.bytes[5],
99                    guid->u.bytes[6], guid->u.bytes[7], ibdev->dev->name );
100
101         /* Send GetResponse */
102         mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
103         if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
104                 DBGC ( mi, "SMA %p could not send NodeDesc GetResponse: %s\n",
105                        mi, strerror ( rc ) );
106                 return;
107         }
108 }
109
110 /**
111  * GUID information
112  *
113  * @v ibdev             Infiniband device
114  * @v mi                Management interface
115  * @v mad               Received MAD
116  * @v av                Source address vector
117  */
118 static void ib_sma_guid_info ( struct ib_device *ibdev,
119                                struct ib_mad_interface *mi,
120                                union ib_mad *mad,
121                                struct ib_address_vector *av ) {
122         struct ib_guid_info *guid_info = &mad->smp.smp_data.guid_info;
123         int rc;
124
125         /* Fill in information */
126         memset ( guid_info, 0, sizeof ( *guid_info ) );
127         memcpy ( guid_info->guid[0], &ibdev->gid.u.half[1],
128                  sizeof ( guid_info->guid[0] ) );
129
130         /* Send GetResponse */
131         mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
132         if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
133                 DBGC ( mi, "SMA %p could not send GuidInfo GetResponse: %s\n",
134                        mi, strerror ( rc ) );
135                 return;
136         }
137 }
138
139 /**
140  * Set port information
141  *
142  * @v ibdev             Infiniband device
143  * @v mi                Management interface
144  * @v mad               Received MAD
145  * @ret rc              Return status code
146  */
147 static int ib_sma_set_port_info ( struct ib_device *ibdev,
148                                   struct ib_mad_interface *mi,
149                                   union ib_mad *mad ) {
150         const struct ib_port_info *port_info = &mad->smp.smp_data.port_info;
151         unsigned int link_width_enabled;
152         unsigned int link_speed_enabled;
153         int rc;
154
155         /* Set parameters */
156         memcpy ( &ibdev->gid.u.half[0], port_info->gid_prefix,
157                  sizeof ( ibdev->gid.u.half[0] ) );
158         ibdev->lid = ntohs ( port_info->lid );
159         ibdev->sm_lid = ntohs ( port_info->mastersm_lid );
160         if ( ( link_width_enabled = port_info->link_width_enabled ) )
161                 ibdev->link_width_enabled = link_width_enabled;
162         if ( ( link_speed_enabled =
163                ( port_info->link_speed_active__link_speed_enabled & 0xf ) ) )
164                 ibdev->link_speed_enabled = link_speed_enabled;
165         ibdev->sm_sl = ( port_info->neighbour_mtu__mastersm_sl & 0xf );
166         DBGC ( mi, "SMA %p set LID %04x SMLID %04x link width %02x speed "
167                "%02x\n", mi, ibdev->lid, ibdev->sm_lid,
168                ibdev->link_width_enabled, ibdev->link_speed_enabled );
169
170         /* Update parameters on device */
171         if ( ( rc = ib_set_port_info ( ibdev, mad ) ) != 0 ) {
172                 DBGC ( mi, "SMA %p could not set port information: %s\n",
173                        mi, strerror ( rc ) );
174                 return rc;
175         }
176
177         return 0;
178 }
179
180 /**
181  * Port information
182  *
183  * @v ibdev             Infiniband device
184  * @v mi                Management interface
185  * @v mad               Received MAD
186  * @v av                Source address vector
187  */
188 static void ib_sma_port_info ( struct ib_device *ibdev,
189                                struct ib_mad_interface *mi,
190                                union ib_mad *mad,
191                                struct ib_address_vector *av ) {
192         struct ib_port_info *port_info = &mad->smp.smp_data.port_info;
193         int rc;
194
195         /* Set parameters if applicable */
196         if ( mad->hdr.method == IB_MGMT_METHOD_SET ) {
197                 if ( ( rc = ib_sma_set_port_info ( ibdev, mi, mad ) ) != 0 ) {
198                         mad->hdr.status =
199                               htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
200                         /* Fall through to generate GetResponse */
201                 }
202         }
203
204         /* Fill in information */
205         memset ( port_info, 0, sizeof ( *port_info ) );
206         memcpy ( port_info->gid_prefix, &ibdev->gid.u.half[0],
207                  sizeof ( port_info->gid_prefix ) );
208         port_info->lid = ntohs ( ibdev->lid );
209         port_info->mastersm_lid = ntohs ( ibdev->sm_lid );
210         port_info->local_port_num = ibdev->port;
211         port_info->link_width_enabled = ibdev->link_width_enabled;
212         port_info->link_width_supported = ibdev->link_width_supported;
213         port_info->link_width_active = ibdev->link_width_active;
214         port_info->link_speed_supported__port_state =
215                 ( ( ibdev->link_speed_supported << 4 ) | ibdev->port_state );
216         port_info->port_phys_state__link_down_def_state =
217                 ( ( IB_PORT_PHYS_STATE_POLLING << 4 ) |
218                   IB_PORT_PHYS_STATE_POLLING );
219         port_info->link_speed_active__link_speed_enabled =
220                 ( ( ibdev->link_speed_active << 4 ) |
221                   ibdev->link_speed_enabled );
222         port_info->neighbour_mtu__mastersm_sl =
223                 ( ( IB_MTU_2048 << 4 ) | ibdev->sm_sl );
224         port_info->vl_cap__init_type = ( IB_VL_0 << 4 );
225         port_info->init_type_reply__mtu_cap = IB_MTU_2048;
226         port_info->operational_vls__enforcement = ( IB_VL_0 << 4 );
227         port_info->guid_cap = 1;
228
229         /* Send GetResponse */
230         mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
231         if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
232                 DBGC ( mi, "SMA %p could not send PortInfo GetResponse: %s\n",
233                        mi, strerror ( rc ) );
234                 return;
235         }
236 }
237
238 /**
239  * Set partition key table
240  *
241  * @v ibdev             Infiniband device
242  * @v mi                Management interface
243  * @v mad               Received MAD
244  * @ret rc              Return status code
245  */
246 static int ib_sma_set_pkey_table ( struct ib_device *ibdev,
247                                    struct ib_mad_interface *mi,
248                                    union ib_mad *mad ) {
249         struct ib_pkey_table *pkey_table = &mad->smp.smp_data.pkey_table;
250         int rc;
251
252         /* Set parameters */
253         ibdev->pkey = ntohs ( pkey_table->pkey[0] );
254         DBGC ( mi, "SMA %p set pkey %04x\n", mi, ibdev->pkey );
255
256         /* Update parameters on device */
257         if ( ( rc = ib_set_pkey_table ( ibdev, mad ) ) != 0 ) {
258                 DBGC ( mi, "SMA %p could not set pkey table: %s\n",
259                        mi, strerror ( rc ) );
260                 return rc;
261         }
262
263         return 0;
264 }
265
266 /**
267  * Partition key table
268  *
269  * @v ibdev             Infiniband device
270  * @v mi                Management interface
271  * @v mad               Received MAD
272  * @v av                Source address vector
273  */
274 static void ib_sma_pkey_table ( struct ib_device *ibdev,
275                                 struct ib_mad_interface *mi,
276                                 union ib_mad *mad,
277                                 struct ib_address_vector *av ) {
278         struct ib_pkey_table *pkey_table = &mad->smp.smp_data.pkey_table;
279         int rc;
280
281         /* Set parameters, if applicable */
282         if ( mad->hdr.method == IB_MGMT_METHOD_SET ) {
283                 if ( ( rc = ib_sma_set_pkey_table ( ibdev, mi, mad ) ) != 0 ) {
284                         mad->hdr.status =
285                               htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
286                         /* Fall through to generate GetResponse */
287                 }
288         }
289
290         /* Fill in information */
291         mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
292         memset ( pkey_table, 0, sizeof ( *pkey_table ) );
293         pkey_table->pkey[0] = htons ( ibdev->pkey );
294
295         /* Send GetResponse */
296         mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
297         if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
298                 DBGC ( mi, "SMA %p could not send PKeyTable GetResponse: %s\n",
299                        mi, strerror ( rc ) );
300                 return;
301         }
302 }
303
304 /** Subnet management agent */
305 struct ib_mad_agent ib_sma_agent[] __ib_mad_agent = {
306         {
307                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
308                 .class_version = IB_SMP_CLASS_VERSION,
309                 .attr_id = htons ( IB_SMP_ATTR_NODE_INFO ),
310                 .handle = ib_sma_node_info,
311         },
312         {
313                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
314                 .class_version = IB_SMP_CLASS_VERSION,
315                 .attr_id = htons ( IB_SMP_ATTR_NODE_DESC ),
316                 .handle = ib_sma_node_desc,
317         },
318         {
319                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
320                 .class_version = IB_SMP_CLASS_VERSION,
321                 .attr_id = htons ( IB_SMP_ATTR_GUID_INFO ),
322                 .handle = ib_sma_guid_info,
323         },
324         {
325                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
326                 .class_version = IB_SMP_CLASS_VERSION,
327                 .attr_id = htons ( IB_SMP_ATTR_PORT_INFO ),
328                 .handle = ib_sma_port_info,
329         },
330         {
331                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
332                 .class_version = IB_SMP_CLASS_VERSION,
333                 .attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE ),
334                 .handle = ib_sma_pkey_table,
335         },
336 };
337
338 /**
339  * Create subnet management agent and interface
340  *
341  * @v ibdev             Infiniband device
342  * @v mi                Management interface
343  * @ret rc              Return status code
344  */
345 int ib_create_sma ( struct ib_device *ibdev, struct ib_mad_interface *mi ) {
346
347         /* Nothing to do */
348         DBGC ( ibdev, "IBDEV %p SMA using SMI %p\n", ibdev, mi );
349
350         return 0;
351 }
352
353 /**
354  * Destroy subnet management agent and interface
355  *
356  * @v ibdev             Infiniband device
357  * @v mi                Management interface
358  */
359 void ib_destroy_sma ( struct ib_device *ibdev __unused,
360                       struct ib_mad_interface *mi __unused ) {
361         /* Nothing to do */
362 }