[infiniband] Add notion of a queue pair type
[people/sha0/gpxe.git] / src / net / infiniband / ib_sma.c
1 /*
2  * Copyright (C) 2008 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/ib_gma.h>
30 #include <gpxe/ib_sma.h>
31
32 /**
33  * @file
34  *
35  * Infiniband Subnet Management Agent
36  *
37  */
38
39 /**
40  * Get node information
41  *
42  * @v gma               General management agent
43  * @v mad               MAD
44  * @ret rc              Return status code
45  */
46 static int ib_sma_get_node_info ( struct ib_gma *gma,
47                                   union ib_mad *mad ) {
48         struct ib_device *ibdev = gma->ibdev;
49         struct ib_node_info *node_info = &mad->smp.smp_data.node_info;
50
51         memset ( node_info, 0, sizeof ( *node_info ) );
52         node_info->base_version = IB_MGMT_BASE_VERSION;
53         node_info->class_version = IB_SMP_CLASS_VERSION;
54         node_info->node_type = IB_NODE_TYPE_HCA;
55         node_info->num_ports = ib_get_hca_info ( ibdev, &node_info->sys_guid );
56         memcpy ( &node_info->node_guid, &node_info->sys_guid,
57                  sizeof ( node_info->node_guid ) );
58         memcpy ( &node_info->port_guid, &ibdev->gid.u.half[1],
59                  sizeof ( node_info->port_guid ) );
60         node_info->partition_cap = htons ( 1 );
61         node_info->local_port_num = ibdev->port;
62
63         return 0;
64 }
65
66 /**
67  * Get node description
68  *
69  * @v gma               General management agent
70  * @v mad               MAD
71  * @ret rc              Return status code
72  */
73 static int ib_sma_get_node_desc ( struct ib_gma *gma,
74                                   union ib_mad *mad ) {
75         struct ib_device *ibdev = gma->ibdev;
76         struct ib_node_desc *node_desc = &mad->smp.smp_data.node_desc;
77         struct ib_gid_half *guid = &ibdev->gid.u.half[1];
78
79         memset ( node_desc, 0, sizeof ( *node_desc ) );
80         snprintf ( node_desc->node_string, sizeof ( node_desc->node_string ),
81                    "gPXE %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)",
82                    guid->bytes[0], guid->bytes[1], guid->bytes[2],
83                    guid->bytes[3], guid->bytes[4], guid->bytes[5],
84                    guid->bytes[6], guid->bytes[7], ibdev->dev->name );
85
86         return 0;
87 }
88
89 /**
90  * Get GUID information
91  *
92  * @v gma               General management agent
93  * @v mad               MAD
94  * @ret rc              Return status code
95  */
96 static int ib_sma_get_guid_info ( struct ib_gma *gma,
97                                   union ib_mad *mad ) {
98         struct ib_device *ibdev = gma->ibdev;
99         struct ib_guid_info *guid_info = &mad->smp.smp_data.guid_info;
100
101         memset ( guid_info, 0, sizeof ( *guid_info ) );
102         memcpy ( guid_info->guid[0], &ibdev->gid.u.half[1],
103                  sizeof ( guid_info->guid[0] ) );
104
105         return 0;
106 }
107
108 /**
109  * Get port information
110  *
111  * @v gma               General management agent
112  * @v mad               MAD
113  * @ret rc              Return status code
114  */
115 static int ib_sma_get_port_info ( struct ib_gma *gma,
116                                   union ib_mad *mad ) {
117         struct ib_device *ibdev = gma->ibdev;
118         struct ib_port_info *port_info = &mad->smp.smp_data.port_info;
119
120         memset ( port_info, 0, sizeof ( *port_info ) );
121         memcpy ( port_info->gid_prefix, &ibdev->gid.u.half[0],
122                  sizeof ( port_info->gid_prefix ) );
123         port_info->lid = ntohs ( ibdev->lid );
124         port_info->mastersm_lid = ntohs ( ibdev->sm_lid );
125         port_info->local_port_num = ibdev->port;
126         port_info->link_width_enabled = ibdev->link_width;
127         port_info->link_width_supported = ibdev->link_width;
128         port_info->link_width_active = ibdev->link_width;
129         port_info->link_speed_supported__port_state =
130                 ( ( ibdev->link_speed << 4 ) | ibdev->port_state );
131         port_info->port_phys_state__link_down_def_state =
132                 ( ( IB_PORT_PHYS_STATE_POLLING << 4 ) |
133                   IB_PORT_PHYS_STATE_POLLING );
134         port_info->link_speed_active__link_speed_enabled =
135                 ( ( ibdev->link_speed << 4 ) | ibdev->link_speed );
136         port_info->neighbour_mtu__mastersm_sl =
137                 ( ( IB_MTU_2048 << 4 ) | ibdev->sm_sl );
138         port_info->vl_cap__init_type = ( IB_VL_0 << 4 );
139         port_info->init_type_reply__mtu_cap = IB_MTU_2048;
140         port_info->operational_vls__enforcement = ( IB_VL_0 << 4 );
141         port_info->guid_cap = 1;
142
143         return 0;
144 }
145
146 /**
147  * Set port information
148  *
149  * @v gma               General management agent
150  * @v mad               MAD
151  * @ret rc              Return status code
152  */
153 static int ib_sma_set_port_info ( struct ib_gma *gma,
154                                   union ib_mad *mad ) {
155         struct ib_device *ibdev = gma->ibdev;
156         const struct ib_port_info *port_info = &mad->smp.smp_data.port_info;
157         int rc;
158
159         memcpy ( &ibdev->gid.u.half[0], port_info->gid_prefix,
160                  sizeof ( ibdev->gid.u.half[0] ) );
161         ibdev->lid = ntohs ( port_info->lid );
162         ibdev->sm_lid = ntohs ( port_info->mastersm_lid );
163         ibdev->sm_sl = ( port_info->neighbour_mtu__mastersm_sl & 0xf );
164
165         if ( ( rc = ib_set_port_info ( ibdev, port_info ) ) != 0 ) {
166                 DBGC ( ibdev, "IBDEV %p could not set port information: %s\n",
167                        ibdev, strerror ( rc ) );
168                 mad->hdr.status =
169                         htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
170         }
171
172         return ib_sma_get_port_info ( gma, mad );
173 }
174
175 /**
176  * Get partition key table
177  *
178  * @v gma               General management agent
179  * @v mad               MAD
180  * @ret rc              Return status code
181  */
182 static int ib_sma_get_pkey_table ( struct ib_gma *gma,
183                                    union ib_mad *mad ) {
184         struct ib_device *ibdev = gma->ibdev;
185         struct ib_pkey_table *pkey_table = &mad->smp.smp_data.pkey_table;
186
187         memset ( pkey_table, 0, sizeof ( *pkey_table ) );
188         pkey_table->pkey[0] = htons ( ibdev->pkey );
189
190         return 0;
191 }
192
193 /**
194  * Set partition key table
195  *
196  * @v gma               General management agent
197  * @v mad               MAD
198  * @ret rc              Return status code
199  */
200 static int ib_sma_set_pkey_table ( struct ib_gma *gma,
201                                    union ib_mad *mad ) {
202         struct ib_device *ibdev = gma->ibdev;
203         struct ib_pkey_table *pkey_table = &mad->smp.smp_data.pkey_table;
204
205         ibdev->pkey = ntohs ( pkey_table->pkey[0] );
206
207         return ib_sma_get_pkey_table ( gma, mad );
208 }
209
210 /** List of attribute handlers */
211 struct ib_gma_handler ib_sma_handlers[] __ib_gma_handler = {
212         {
213                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
214                 .mgmt_class_ignore = IB_SMP_CLASS_IGNORE,
215                 .class_version = IB_SMP_CLASS_VERSION,
216                 .method = IB_MGMT_METHOD_GET,
217                 .resp_method = IB_MGMT_METHOD_GET_RESP,
218                 .attr_id = htons ( IB_SMP_ATTR_NODE_INFO ),
219                 .handle = ib_sma_get_node_info,
220         },
221         {
222                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
223                 .mgmt_class_ignore = IB_SMP_CLASS_IGNORE,
224                 .class_version = IB_SMP_CLASS_VERSION,
225                 .method = IB_MGMT_METHOD_GET,
226                 .resp_method = IB_MGMT_METHOD_GET_RESP,
227                 .attr_id = htons ( IB_SMP_ATTR_NODE_DESC ),
228                 .handle = ib_sma_get_node_desc,
229         },
230         {
231                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
232                 .mgmt_class_ignore = IB_SMP_CLASS_IGNORE,
233                 .class_version = IB_SMP_CLASS_VERSION,
234                 .method = IB_MGMT_METHOD_GET,
235                 .resp_method = IB_MGMT_METHOD_GET_RESP,
236                 .attr_id = htons ( IB_SMP_ATTR_GUID_INFO ),
237                 .handle = ib_sma_get_guid_info,
238         },
239         {
240                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
241                 .mgmt_class_ignore = IB_SMP_CLASS_IGNORE,
242                 .class_version = IB_SMP_CLASS_VERSION,
243                 .method = IB_MGMT_METHOD_GET,
244                 .resp_method = IB_MGMT_METHOD_GET_RESP,
245                 .attr_id = htons ( IB_SMP_ATTR_PORT_INFO ),
246                 .handle = ib_sma_get_port_info,
247         },
248         {
249                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
250                 .mgmt_class_ignore = IB_SMP_CLASS_IGNORE,
251                 .class_version = IB_SMP_CLASS_VERSION,
252                 .method = IB_MGMT_METHOD_SET,
253                 .resp_method = IB_MGMT_METHOD_GET_RESP,
254                 .attr_id = htons ( IB_SMP_ATTR_PORT_INFO ),
255                 .handle = ib_sma_set_port_info,
256         },
257         {
258                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
259                 .mgmt_class_ignore = IB_SMP_CLASS_IGNORE,
260                 .class_version = IB_SMP_CLASS_VERSION,
261                 .method = IB_MGMT_METHOD_GET,
262                 .resp_method = IB_MGMT_METHOD_GET_RESP,
263                 .attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE ),
264                 .handle = ib_sma_get_pkey_table,
265         },
266         {
267                 .mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
268                 .mgmt_class_ignore = IB_SMP_CLASS_IGNORE,
269                 .class_version = IB_SMP_CLASS_VERSION,
270                 .method = IB_MGMT_METHOD_SET,
271                 .resp_method = IB_MGMT_METHOD_GET_RESP,
272                 .attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE ),
273                 .handle = ib_sma_set_pkey_table,
274         },
275 };
276
277 /**
278  * Create SMA
279  *
280  * @v sma               Subnet management agent
281  * @v ibdev             Infiniband device
282  * @v op                Subnet management operations
283  * @ret rc              Return status code
284  */
285 int ib_create_sma ( struct ib_sma *sma, struct ib_device *ibdev ) {
286         int rc;
287
288         /* Initialise GMA */
289         if ( ( rc = ib_create_gma ( &sma->gma, ibdev, IB_QPT_SMA ) ) != 0 ) {
290                 DBGC ( sma, "SMA %p could not create GMA: %s\n",
291                        sma, strerror ( rc ) );
292                 goto err_create_gma;
293         }
294
295         /* If we don't get QP0, we can't function */
296         if ( sma->gma.qp->qpn != IB_QPN_SMA ) {
297                 DBGC ( sma, "SMA %p on QPN %lx, needs to be on QPN 0\n",
298                        sma, sma->gma.qp->qpn );
299                 rc = -ENOTSUP;
300                 goto err_not_qp0;
301         }
302
303         return 0;
304
305  err_not_qp0:
306         ib_destroy_gma ( &sma->gma );
307  err_create_gma:
308         return rc;
309 }
310
311 /**
312  * Destroy SMA
313  *
314  * @v sma               Subnet management agent
315  */
316 void ib_destroy_sma ( struct ib_sma *sma ) {
317
318         ib_destroy_gma ( &sma->gma );
319 }