[infiniband] Centralise assumption of 2048-byte payloads
[people/lynusvaz/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/iobuf.h>
30 #include <gpxe/process.h>
31 #include <gpxe/ib_sma.h>
32
33 /**
34  * @file
35  *
36  * Infiniband Subnet Management Agent
37  *
38  */
39
40 /**
41  * Get node information
42  *
43  * @v sma               Subnet management agent
44  * @v get               Attribute to get
45  */
46 static void ib_sma_get_node_info ( struct ib_sma *sma,
47                                    union ib_smp_data *get ) {
48         struct ib_device *ibdev = sma->ibdev;
49         struct ib_node_info *node_info = &get->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
64 /**
65  * Get node description
66  *
67  * @v sma               Subnet management agent
68  * @v get               Attribute to get
69  */
70 static void ib_sma_get_node_desc ( struct ib_sma *sma,
71                                    union ib_smp_data *get ) {
72         struct ib_device *ibdev = sma->ibdev;
73         struct ib_node_desc *node_desc = &get->node_desc;
74         struct ib_gid_half *guid = &ibdev->gid.u.half[1];
75
76         memset ( node_desc, 0, sizeof ( *node_desc ) );
77         snprintf ( node_desc->node_string, sizeof ( node_desc->node_string ),
78                    "gPXE %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)",
79                    guid->bytes[0], guid->bytes[1], guid->bytes[2],
80                    guid->bytes[3], guid->bytes[4], guid->bytes[5],
81                    guid->bytes[6], guid->bytes[7], ibdev->dev->name );
82 }
83
84 /**
85  * Get GUID information
86  *
87  * @v sma               Subnet management agent
88  * @v get               Attribute to get
89  */
90 static void ib_sma_get_guid_info ( struct ib_sma *sma,
91                                    union ib_smp_data *get ) {
92         struct ib_device *ibdev = sma->ibdev;
93         struct ib_guid_info *guid_info = &get->guid_info;
94
95         memset ( guid_info, 0, sizeof ( *guid_info ) );
96         memcpy ( guid_info->guid[0], &ibdev->gid.u.half[1],
97                  sizeof ( guid_info->guid[0] ) );
98 }
99
100 /**
101  * Get port information
102  *
103  * @v sma               Subnet management agent
104  * @v get               Attribute to get
105  */
106 static void ib_sma_get_port_info ( struct ib_sma *sma,
107                                    union ib_smp_data *get ) {
108         struct ib_device *ibdev = sma->ibdev;
109         struct ib_port_info *port_info = &get->port_info;
110
111         memset ( port_info, 0, sizeof ( *port_info ) );
112         memcpy ( port_info->gid_prefix, &ibdev->gid.u.half[0],
113                  sizeof ( port_info->gid_prefix ) );
114         port_info->lid = ntohs ( ibdev->lid );
115         port_info->mastersm_lid = ntohs ( ibdev->sm_lid );
116         port_info->local_port_num = ibdev->port;
117         port_info->link_width_enabled = ibdev->link_width;
118         port_info->link_width_supported = ibdev->link_width;
119         port_info->link_width_active = ibdev->link_width;
120         port_info->link_speed_supported__port_state =
121                 ( ( ibdev->link_speed << 4 ) | ibdev->port_state );
122         port_info->port_phys_state__link_down_def_state =
123                 ( ( IB_PORT_PHYS_STATE_POLLING << 4 ) |
124                   IB_PORT_PHYS_STATE_POLLING );
125         port_info->link_speed_active__link_speed_enabled =
126                 ( ( ibdev->link_speed << 4 ) | ibdev->link_speed );
127         port_info->neighbour_mtu__mastersm_sl =
128                 ( ( IB_MTU_2048 << 4 ) | ibdev->sm_sl );
129         port_info->vl_cap__init_type = ( IB_VL_0 << 4 );
130         port_info->init_type_reply__mtu_cap = IB_MTU_2048;
131         port_info->operational_vls__enforcement = ( IB_VL_0 << 4 );
132         port_info->guid_cap = 1;
133 }
134
135 /**
136  * Set port information
137  *
138  * @v sma               Subnet management agent
139  * @v set               Attribute to set
140  * @ret rc              Return status code
141  */
142 static int ib_sma_set_port_info ( struct ib_sma *sma,
143                                   const union ib_smp_data *set ) {
144         struct ib_device *ibdev = sma->ibdev;
145         const struct ib_port_info *port_info = &set->port_info;
146
147         memcpy ( &ibdev->gid.u.half[0], port_info->gid_prefix,
148                  sizeof ( ibdev->gid.u.half[0] ) );
149         ibdev->lid = ntohs ( port_info->lid );
150         ibdev->sm_lid = ntohs ( port_info->mastersm_lid );
151         ibdev->sm_sl = ( port_info->neighbour_mtu__mastersm_sl & 0xf );
152
153         if ( ! sma->op->set_port_info ) {
154                 /* Not an error; we just ignore all other settings */
155                 return 0;
156         }
157
158         return sma->op->set_port_info ( ibdev, port_info );
159 }
160
161 /**
162  * Get partition key table
163  *
164  * @v sma               Subnet management agent
165  * @v get               Attribute to get
166  */
167 static void ib_sma_get_pkey_table ( struct ib_sma *sma,
168                                     union ib_smp_data *get ) {
169         struct ib_device *ibdev = sma->ibdev;
170         struct ib_pkey_table *pkey_table = &get->pkey_table;
171
172         memset ( pkey_table, 0, sizeof ( *pkey_table ) );
173         pkey_table->pkey[0] = htons ( ibdev->pkey );
174 }
175
176 /**
177  * Set partition key table
178  *
179  * @v sma               Subnet management agent
180  * @v set               Attribute to set
181  */
182 static int ib_sma_set_pkey_table ( struct ib_sma *sma,
183                                    const union ib_smp_data *get ) {
184         struct ib_device *ibdev = sma->ibdev;
185         const struct ib_pkey_table *pkey_table = &get->pkey_table;
186
187         ibdev->pkey = ntohs ( pkey_table->pkey[0] );
188         return 0;
189 }
190
191 /** An attribute handler */
192 struct ib_sma_handler {
193         /** Attribute (in network byte order) */
194         uint16_t attr_id;
195         /** Get attribute
196          *
197          * @v sma       Subnet management agent
198          * @v get       Attribute to get
199          * @ret rc      Return status code
200          */
201         void ( * get ) ( struct ib_sma *sma, union ib_smp_data *get );
202         /** Set attribute
203          *
204          * @v sma       Subnet management agent
205          * @v set       Attribute to set
206          * @ret rc      Return status code
207          */
208         int ( * set ) ( struct ib_sma *sma, const union ib_smp_data *set );
209 };
210
211 /** List of attribute handlers */
212 static struct ib_sma_handler ib_sma_handlers[] = {
213         { htons ( IB_SMP_ATTR_NODE_DESC ),
214           ib_sma_get_node_desc, NULL },
215         { htons ( IB_SMP_ATTR_NODE_INFO ),
216           ib_sma_get_node_info, NULL },
217         { htons ( IB_SMP_ATTR_GUID_INFO ),
218           ib_sma_get_guid_info, NULL },
219         { htons ( IB_SMP_ATTR_PORT_INFO ),
220           ib_sma_get_port_info, ib_sma_set_port_info },
221         { htons ( IB_SMP_ATTR_PKEY_TABLE ),
222           ib_sma_get_pkey_table, ib_sma_set_pkey_table },
223 };
224
225 /**
226  * Identify attribute handler
227  *
228  * @v attr_id           Attribute ID (in network byte order)
229  * @ret handler         Attribute handler (or NULL)
230  */
231 static struct ib_sma_handler * ib_sma_handler ( uint16_t attr_id ) {
232         struct ib_sma_handler *handler;
233         unsigned int i;
234
235         for ( i = 0 ; i < ( sizeof ( ib_sma_handlers ) /
236                             sizeof ( ib_sma_handlers[0] ) ) ; i++ ) {
237                 handler = &ib_sma_handlers[i];
238                 if ( handler->attr_id == attr_id )
239                         return handler;
240         }
241
242         return NULL;
243 }
244
245 /**
246  * Respond to management datagram
247  *
248  * @v sma               Subnet management agent
249  * @v mad               Management datagram
250  * @ret rc              Return status code
251  */
252 static int ib_sma_mad ( struct ib_sma *sma, union ib_mad *mad ) {
253         struct ib_device *ibdev = sma->ibdev;
254         struct ib_mad_hdr *hdr = &mad->hdr;
255         struct ib_mad_smp *smp = &mad->smp;
256         struct ib_sma_handler *handler = NULL;
257         unsigned int hop_pointer;
258         unsigned int hop_count;
259         int rc;
260
261         DBGC ( sma, "SMA %p received SMP with bv=%02x mc=%02x cv=%02x "
262                "meth=%02x attr=%04x mod=%08x\n", sma, hdr->base_version,
263                hdr->mgmt_class, hdr->class_version, hdr->method,
264                ntohs ( hdr->attr_id ), ntohl ( hdr->attr_mod ) );
265         DBGC2_HDA ( sma, 0, mad, sizeof ( *mad ) );
266
267         /* Sanity checks */
268         if ( hdr->base_version != IB_MGMT_BASE_VERSION ) {
269                 DBGC ( sma, "SMA %p unsupported base version %x\n",
270                        sma, hdr->base_version );
271                 return -ENOTSUP;
272         }
273         if ( ( hdr->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) &&
274              ( hdr->mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED ) ) {
275                 DBGC ( sma, "SMA %p unsupported management class %x\n",
276                        sma, hdr->mgmt_class );
277                 return -ENOTSUP;
278         }
279         if ( hdr->class_version != IB_SMP_CLASS_VERSION ) {
280                 DBGC ( sma, "SMA %p unsupported class version %x\n",
281                        sma, hdr->class_version );
282                 return -ENOTSUP;
283         }
284         if ( ( hdr->method != IB_MGMT_METHOD_GET ) &&
285              ( hdr->method != IB_MGMT_METHOD_SET ) ) {
286                 DBGC ( sma, "SMA %p unsupported method %x\n",
287                        sma, hdr->method );
288                 return -ENOTSUP;
289         }
290
291         /* Identify handler */
292         if ( ! ( handler = ib_sma_handler ( hdr->attr_id ) ) ) {
293                 DBGC ( sma, "SMA %p unsupported attribute %x\n",
294                        sma, ntohs ( hdr->attr_id ) );
295                 hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
296                 goto respond_without_data;
297         }
298
299         /* Set attribute (if applicable) */
300         if ( hdr->method != IB_MGMT_METHOD_SET ) {
301                 hdr->status = htons ( IB_MGMT_STATUS_OK );
302                 goto respond;
303         }
304         if ( ! handler->set ) {
305                 DBGC ( sma, "SMA %p attribute %x is unsettable\n",
306                        sma, ntohs ( hdr->attr_id ) );
307                 hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
308                 goto respond;
309         }
310         if ( ( rc = handler->set ( sma, &smp->smp_data ) ) != 0 ) {
311                 DBGC ( sma, "SMA %p could not set attribute %x: %s\n",
312                        sma, ntohs ( hdr->attr_id ), strerror ( rc ) );
313                 hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
314                 goto respond;
315         }
316
317         hdr->status = htons ( IB_MGMT_STATUS_OK );
318
319  respond:
320         /* Get attribute */
321         handler->get ( sma, &smp->smp_data );
322
323  respond_without_data:
324
325         /* Set method to "Get Response" */
326         hdr->method = IB_MGMT_METHOD_GET_RESP;
327
328         /* Set response fields for directed route SMPs */
329         if ( hdr->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) {
330                 hdr->status |= htons ( IB_SMP_STATUS_D_INBOUND );
331                 hop_pointer = smp->mad_hdr.class_specific.smp.hop_pointer;
332                 hop_count = smp->mad_hdr.class_specific.smp.hop_count;
333                 assert ( hop_count == hop_pointer );
334                 if ( hop_pointer < ( sizeof ( smp->return_path.hops ) /
335                                      sizeof ( smp->return_path.hops[0] ) ) ) {
336                         smp->return_path.hops[hop_pointer] = ibdev->port;
337                 } else {
338                         DBGC ( sma, "SMA %p invalid hop pointer %d\n",
339                                sma, hop_pointer );
340                         return -EINVAL;
341                 }
342         }
343
344         DBGC ( sma, "SMA %p responding with status=%04x\n",
345                sma, ntohs ( hdr->status ) );
346         DBGC2_HDA ( sma, 0, mad, sizeof ( *mad ) );
347
348         return 0;
349 }
350
351 /**
352  * Refill SMA receive ring
353  *
354  * @v sma               Subnet management agent
355  */
356 static void ib_sma_refill_recv ( struct ib_sma *sma ) {
357         struct ib_device *ibdev = sma->ibdev;
358         struct io_buffer *iobuf;
359         int rc;
360
361         while ( sma->qp->recv.fill < IB_SMA_NUM_RECV_WQES ) {
362
363                 /* Allocate I/O buffer */
364                 iobuf = alloc_iob ( IB_MAX_PAYLOAD_SIZE );
365                 if ( ! iobuf ) {
366                         /* Non-fatal; we will refill on next attempt */
367                         return;
368                 }
369
370                 /* Post I/O buffer */
371                 if ( ( rc = ib_post_recv ( ibdev, sma->qp, iobuf ) ) != 0 ) {
372                         DBGC ( sma, "SMA %p could not refill: %s\n",
373                                sma, strerror ( rc ) );
374                         free_iob ( iobuf );
375                         /* Give up */
376                         return;
377                 }
378         }
379 }
380
381 /**
382  * Complete SMA send
383  *
384  *
385  * @v ibdev             Infiniband device
386  * @v qp                Queue pair
387  * @v iobuf             I/O buffer
388  * @v rc                Completion status code
389  */
390 static void ib_sma_complete_send ( struct ib_device *ibdev __unused,
391                                    struct ib_queue_pair *qp,
392                                    struct io_buffer *iobuf, int rc ) {
393         struct ib_sma *sma = ib_qp_get_ownerdata ( qp );
394
395         if ( rc != 0 ) {
396                 DBGC ( sma, "SMA %p send completion error: %s\n",
397                        sma, strerror ( rc ) );
398         }
399         free_iob ( iobuf );
400 }
401
402 /**
403  * Complete SMA receive
404  *
405  *
406  * @v ibdev             Infiniband device
407  * @v qp                Queue pair
408  * @v av                Address vector
409  * @v iobuf             I/O buffer
410  * @v rc                Completion status code
411  */
412 static void ib_sma_complete_recv ( struct ib_device *ibdev,
413                                    struct ib_queue_pair *qp,
414                                    struct ib_address_vector *av,
415                                    struct io_buffer *iobuf, int rc ) {
416         struct ib_sma *sma = ib_qp_get_ownerdata ( qp );
417         union ib_mad *mad;
418
419         /* Ignore errors */
420         if ( rc != 0 ) {
421                 DBGC ( sma, "SMA %p RX error: %s\n", sma, strerror ( rc ) );
422                 goto err;
423         }
424
425         /* Sanity check */
426         if ( iob_len ( iobuf ) != sizeof ( *mad ) ) {
427                 DBGC ( sma, "SMA %p RX bad size (%zd bytes)\n",
428                        sma, iob_len ( iobuf ) );
429                 goto err;
430         }
431         mad = iobuf->data;
432
433         /* Construct MAD response */
434         if ( ( rc = ib_sma_mad ( sma, mad ) ) != 0 ) {
435                 DBGC ( sma, "SMA %p could not construct MAD response: %s\n",
436                        sma, strerror ( rc ) );
437                 goto err;
438         }
439
440         /* Send MAD response */
441         if ( ( rc = ib_post_send ( ibdev, qp, av, iobuf ) ) != 0 ) {
442                 DBGC ( sma, "SMA %p could not send MAD response: %s\n",
443                        sma, strerror ( rc ) );
444                 goto err;
445         }
446
447         return;
448
449  err:
450         free_iob ( iobuf );
451 }
452
453 /** SMA completion operations */
454 static struct ib_completion_queue_operations ib_sma_completion_ops = {
455         .complete_send = ib_sma_complete_send,
456         .complete_recv = ib_sma_complete_recv,
457 };
458
459 /**
460  * Poll SMA
461  *
462  * @v process           Process
463  */
464 static void ib_sma_step ( struct process *process ) {
465         struct ib_sma *sma =
466                 container_of ( process, struct ib_sma, poll );
467         struct ib_device *ibdev = sma->ibdev;
468
469         /* Poll the kernel completion queue */
470         ib_poll_cq ( ibdev, sma->cq );
471
472         /* Refill the receive ring */
473         ib_sma_refill_recv ( sma );
474 }
475
476 /**
477  * Create SMA
478  *
479  * @v sma               Subnet management agent
480  * @v ibdev             Infiniband device
481  * @v op                Subnet management operations
482  * @ret rc              Return status code
483  */
484 int ib_create_sma ( struct ib_sma *sma, struct ib_device *ibdev,
485                     struct ib_sma_operations *op ) {
486         int rc;
487
488         /* Initialise fields */
489         memset ( sma, 0, sizeof ( *sma ) );
490         sma->ibdev = ibdev;
491         sma->op = op;
492         process_init ( &sma->poll, ib_sma_step, &ibdev->refcnt );
493
494         /* Create completion queue */
495         sma->cq = ib_create_cq ( ibdev, IB_SMA_NUM_CQES,
496                                  &ib_sma_completion_ops );
497         if ( ! sma->cq ) {
498                 rc = -ENOMEM;
499                 goto err_create_cq;
500         }
501
502         /* Create queue pair */
503         sma->qp = ib_create_qp ( ibdev, IB_SMA_NUM_SEND_WQES, sma->cq,
504                                  IB_SMA_NUM_RECV_WQES, sma->cq, 0 );
505         if ( ! sma->qp ) {
506                 rc = -ENOMEM;
507                 goto err_create_qp;
508         }
509         ib_qp_set_ownerdata ( sma->qp, sma );
510
511         /* If we don't get QP0, we can't function */
512         if ( sma->qp->qpn != IB_QPN_SMP ) {
513                 DBGC ( sma, "SMA %p on QPN %lx, needs to be on QPN 0\n",
514                        sma, sma->qp->qpn );
515                 rc = -ENOTSUP;
516                 goto err_not_qp0;
517         }
518
519         /* Fill receive ring */
520         ib_sma_refill_recv ( sma );
521         return 0;
522
523  err_not_qp0:
524         ib_destroy_qp ( ibdev, sma->qp );
525  err_create_qp:
526         ib_destroy_cq ( ibdev, sma->cq );
527  err_create_cq:
528         process_del ( &sma->poll );
529         return rc;
530 }
531
532 /**
533  * Destroy SMA
534  *
535  * @v sma               Subnet management agent
536  */
537 void ib_destroy_sma ( struct ib_sma *sma ) {
538         struct ib_device *ibdev = sma->ibdev;
539
540         ib_destroy_qp ( ibdev, sma->qp );
541         ib_destroy_cq ( ibdev, sma->cq );
542         process_del ( &sma->poll );
543 }