[infiniband] Pass GMA as a parameter to GMA MAD handlers
[people/sha0/gpxe.git] / src / net / infiniband / ib_gma.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_gma.h>
31
32 /**
33  * @file
34  *
35  * Infiniband General Management Agent
36  *
37  */
38
39 /** A MAD request */
40 struct ib_mad_request {
41         /** Associated GMA */
42         struct ib_gma *gma;
43         /** List of outstanding MAD requests */
44         struct list_head list;
45         /** Retry timer */
46         struct retry_timer timer;
47         /** Destination address */
48         struct ib_address_vector av;
49         /** MAD request */
50         union ib_mad mad;
51 };
52
53 /** GMA number of send WQEs
54  *
55  * This is a policy decision.
56  */
57 #define IB_GMA_NUM_SEND_WQES 4
58
59 /** GMA number of receive WQEs
60  *
61  * This is a policy decision.
62  */
63 #define IB_GMA_NUM_RECV_WQES 2
64
65 /** GMA number of completion queue entries
66  *
67  * This is a policy decision
68  */
69 #define IB_GMA_NUM_CQES 8
70
71 /** GMA TID magic signature */
72 #define IB_GMA_TID_MAGIC ( ( 'g' << 24 ) | ( 'P' << 16 ) | ( 'X' << 8 ) | 'E' )
73
74 /** TID to use for next MAD request */
75 static unsigned int next_request_tid;
76
77 /**
78  * Call attribute handler
79  *
80  * @v gma               General management agent
81  * @v mad               MAD
82  * @ret rc              Return status code
83  */
84 static int ib_handle_mad ( struct ib_gma *gma, union ib_mad *mad ) {
85         struct ib_mad_hdr *hdr = &mad->hdr;
86         struct ib_gma_handler *handler;
87
88         for_each_table_entry ( handler, IB_GMA_HANDLERS ) {
89                 if ( ( handler->mgmt_class == hdr->mgmt_class ) &&
90                      ( handler->class_version == hdr->class_version ) &&
91                      ( handler->method == hdr->method ) &&
92                      ( handler->attr_id == hdr->attr_id ) ) {
93                         hdr->method = handler->resp_method;
94                         return handler->handle ( gma, mad );
95                 }
96         }
97
98         hdr->method = IB_MGMT_METHOD_TRAP;
99         hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
100         return -ENOTSUP;
101 }
102
103 /**
104  * Complete GMA receive
105  *
106  *
107  * @v ibdev             Infiniband device
108  * @v qp                Queue pair
109  * @v av                Address vector
110  * @v iobuf             I/O buffer
111  * @v rc                Completion status code
112  */
113 static void ib_gma_complete_recv ( struct ib_device *ibdev,
114                                    struct ib_queue_pair *qp,
115                                    struct ib_address_vector *av,
116                                    struct io_buffer *iobuf, int rc ) {
117         struct ib_gma *gma = ib_qp_get_ownerdata ( qp );
118         struct ib_mad_request *request;
119         union ib_mad *mad;
120         struct ib_mad_hdr *hdr;
121         unsigned int hop_pointer;
122         unsigned int hop_count;
123
124         /* Ignore errors */
125         if ( rc != 0 ) {
126                 DBGC ( gma, "GMA %p RX error: %s\n", gma, strerror ( rc ) );
127                 goto out;
128         }
129
130         /* Sanity checks */
131         if ( iob_len ( iobuf ) != sizeof ( *mad ) ) {
132                 DBGC ( gma, "GMA %p RX bad size (%zd bytes)\n",
133                        gma, iob_len ( iobuf ) );
134                 DBGC_HDA ( gma, 0, iobuf->data, iob_len ( iobuf ) );
135                 goto out;
136         }
137         mad = iobuf->data;
138         hdr = &mad->hdr;
139         if ( hdr->base_version != IB_MGMT_BASE_VERSION ) {
140                 DBGC ( gma, "GMA %p unsupported base version %x\n",
141                        gma, hdr->base_version );
142                 DBGC_HDA ( gma, 0, mad, sizeof ( *mad ) );
143                 goto out;
144         }
145         DBGC ( gma, "GMA %p RX TID %08x%08x (%02x,%02x,%02x,%04x) status "
146                "%04x\n", gma, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
147                hdr->mgmt_class, hdr->class_version, hdr->method,
148                ntohs ( hdr->attr_id ), ntohs ( hdr->status ) );
149         DBGC2_HDA ( gma, 0, mad, sizeof ( *mad ) );
150
151         /* Dequeue request if applicable */
152         list_for_each_entry ( request, &gma->requests, list ) {
153                 if ( memcmp ( &request->mad.hdr.tid, &hdr->tid,
154                               sizeof ( request->mad.hdr.tid ) ) == 0 ) {
155                         stop_timer ( &request->timer );
156                         list_del ( &request->list );
157                         free ( request );
158                         break;
159                 }
160         }
161
162         /* Handle MAD, if possible */
163         if ( ( rc = ib_handle_mad ( gma, mad ) ) != 0 ) {
164                 DBGC ( gma, "GMA %p could not handle TID %08x%08x: %s\n",
165                        gma, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
166                        strerror ( rc ) );
167                 /* Do not abort; we may want to send an error response */
168         }
169
170         /* Finish processing if we have no response to send */
171         if ( ! hdr->method )
172                 goto out;
173
174         DBGC ( gma, "GMA %p TX TID %08x%08x (%02x,%02x,%02x,%04x)\n", gma,
175                ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ), hdr->mgmt_class,
176                hdr->class_version, hdr->method, ntohs ( hdr->attr_id ) );
177         DBGC2_HDA ( gma, 0, mad, sizeof ( *mad ) );
178
179         /* Set response fields for directed route SMPs */
180         if ( hdr->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) {
181                 struct ib_mad_smp *smp = &mad->smp;
182
183                 hdr->status |= htons ( IB_SMP_STATUS_D_INBOUND );
184                 hop_pointer = smp->mad_hdr.class_specific.smp.hop_pointer;
185                 hop_count = smp->mad_hdr.class_specific.smp.hop_count;
186                 assert ( hop_count == hop_pointer );
187                 if ( hop_pointer < ( sizeof ( smp->return_path.hops ) /
188                                      sizeof ( smp->return_path.hops[0] ) ) ) {
189                         smp->return_path.hops[hop_pointer] = ibdev->port;
190                 } else {
191                         DBGC ( gma, "GMA %p invalid hop pointer %d\n",
192                                gma, hop_pointer );
193                         goto out;
194                 }
195         }
196
197         /* Send MAD response, if applicable */
198         if ( ( rc = ib_post_send ( ibdev, qp, av,
199                                    iob_disown ( iobuf ) ) ) != 0 ) {
200                 DBGC ( gma, "GMA %p could not send MAD response: %s\n",
201                        gma, strerror ( rc ) );
202                 goto out;
203         }
204
205  out:
206         free_iob ( iobuf );
207 }
208
209 /**
210  * Complete GMA send
211  *
212  *
213  * @v ibdev             Infiniband device
214  * @v qp                Queue pair
215  * @v iobuf             I/O buffer
216  * @v rc                Completion status code
217  */
218 static void ib_gma_complete_send ( struct ib_device *ibdev __unused,
219                                    struct ib_queue_pair *qp,
220                                    struct io_buffer *iobuf, int rc ) {
221         struct ib_gma *gma = ib_qp_get_ownerdata ( qp );
222
223         if ( rc != 0 ) {
224                 DBGC ( gma, "GMA %p send completion error: %s\n",
225                        gma, strerror ( rc ) );
226         }
227         free_iob ( iobuf );
228 }
229
230 /** GMA completion operations */
231 static struct ib_completion_queue_operations ib_gma_completion_ops = {
232         .complete_send = ib_gma_complete_send,
233         .complete_recv = ib_gma_complete_recv,
234 };
235
236 /**
237  * Transmit MAD request
238  *
239  * @v gma               General management agent
240  * @v request           MAD request
241  * @ret rc              Return status code
242  */
243 static int ib_gma_send ( struct ib_gma *gma, struct ib_mad_request *request ) {
244         struct io_buffer *iobuf;
245         int rc;
246
247         DBGC ( gma, "GMA %p TX TID %08x%08x (%02x,%02x,%02x,%04x)\n",
248                gma, ntohl ( request->mad.hdr.tid[0] ),
249                ntohl ( request->mad.hdr.tid[1] ), request->mad.hdr.mgmt_class,
250                request->mad.hdr.class_version, request->mad.hdr.method,
251                ntohs ( request->mad.hdr.attr_id ) );
252         DBGC2_HDA ( gma, 0, &request->mad, sizeof ( request->mad ) );
253
254         /* Construct I/O buffer */
255         iobuf = alloc_iob ( sizeof ( request->mad ) );
256         if ( ! iobuf ) {
257                 DBGC ( gma, "GMA %p could not allocate buffer for TID "
258                        "%08x%08x\n", gma, ntohl ( request->mad.hdr.tid[0] ),
259                        ntohl ( request->mad.hdr.tid[1] ) );
260                 return -ENOMEM;
261         }
262         memcpy ( iob_put ( iobuf, sizeof ( request->mad ) ), &request->mad,
263                  sizeof ( request->mad ) );
264
265         /* Send I/O buffer */
266         if ( ( rc = ib_post_send ( gma->ibdev, gma->qp, &request->av,
267                                    iobuf ) ) != 0 ) {
268                 DBGC ( gma, "GMA %p could not send TID %08x%08x: %s\n",
269                        gma,  ntohl ( request->mad.hdr.tid[0] ),
270                        ntohl ( request->mad.hdr.tid[1] ), strerror ( rc ) );
271                 free_iob ( iobuf );
272                 return rc;
273         }
274
275         return 0;
276 }
277
278 /**
279  * Handle MAD request timer expiry
280  *
281  * @v timer             Retry timer
282  * @v expired           Failure indicator
283  */
284 static void ib_gma_timer_expired ( struct retry_timer *timer, int expired ) {
285         struct ib_mad_request *request =
286                 container_of ( timer, struct ib_mad_request, timer );
287         struct ib_gma *gma = request->gma;
288
289         /* Abandon TID if we have tried too many times */
290         if ( expired ) {
291                 DBGC ( gma, "GMA %p abandoning TID %08x%08x\n",
292                        gma, ntohl ( request->mad.hdr.tid[0] ),
293                        ntohl ( request->mad.hdr.tid[1] ) );
294                 list_del ( &request->list );
295                 free ( request );
296                 return;
297         }
298
299         /* Restart retransmission timer */
300         start_timer ( timer );
301
302         /* Resend request */
303         ib_gma_send ( gma, request );
304 }
305
306 /**
307  * Issue MAD request
308  *
309  * @v gma               General management agent
310  * @v mad               MAD request
311  * @v av                Destination address, or NULL for SM
312  * @v retry             Request should be retried until a response arrives
313  * @ret rc              Return status code
314  */
315 int ib_gma_request ( struct ib_gma *gma, union ib_mad *mad,
316                      struct ib_address_vector *av, int retry ) {
317         struct ib_device *ibdev = gma->ibdev;
318         struct ib_mad_request *request;
319
320         /* Allocate and initialise structure */
321         request = zalloc ( sizeof ( *request ) );
322         if ( ! request ) {
323                 DBGC ( gma, "GMA %p could not allocate MAD request\n", gma );
324                 return -ENOMEM;
325         }
326         request->gma = gma;
327         request->timer.expired = ib_gma_timer_expired;
328
329         /* Determine address vector */
330         if ( av ) {
331                 memcpy ( &request->av, av, sizeof ( request->av ) );
332         } else {
333                 request->av.lid = ibdev->sm_lid;
334                 request->av.sl = ibdev->sm_sl;
335                 request->av.qpn = IB_QPN_GMA;
336                 request->av.qkey = IB_QKEY_GMA;
337         }
338
339         /* Copy MAD body */
340         memcpy ( &request->mad, mad, sizeof ( request->mad ) );
341
342         /* Allocate TID */
343         request->mad.hdr.tid[0] = htonl ( IB_GMA_TID_MAGIC );
344         request->mad.hdr.tid[1] = htonl ( ++next_request_tid );
345
346         /* Send initial request.  Ignore errors; the retry timer will
347          * take care of those we care about.
348          */
349         ib_gma_send ( gma, request );
350
351         /* Add to list and start timer if applicable */
352         if ( retry ) {
353                 list_add ( &request->list, &gma->requests );
354                 start_timer ( &request->timer );
355         } else {
356                 free ( request );
357         }
358
359         return 0;
360 }
361
362 /**
363  * Create GMA
364  *
365  * @v gma               General management agent
366  * @v ibdev             Infiniband device
367  * @v qkey              Queue key
368  * @ret rc              Return status code
369  */
370 int ib_create_gma ( struct ib_gma *gma, struct ib_device *ibdev,
371                     unsigned long qkey ) {
372         int rc;
373
374         /* Initialise fields */
375         memset ( gma, 0, sizeof ( *gma ) );
376         gma->ibdev = ibdev;
377         INIT_LIST_HEAD ( &gma->requests );
378
379         /* Create completion queue */
380         gma->cq = ib_create_cq ( ibdev, IB_GMA_NUM_CQES,
381                                  &ib_gma_completion_ops );
382         if ( ! gma->cq ) {
383                 DBGC ( gma, "GMA %p could not allocate completion queue\n",
384                        gma );
385                 rc = -ENOMEM;
386                 goto err_create_cq;
387         }
388
389         /* Create queue pair */
390         gma->qp = ib_create_qp ( ibdev, IB_GMA_NUM_SEND_WQES, gma->cq,
391                                  IB_GMA_NUM_RECV_WQES, gma->cq, qkey );
392         if ( ! gma->qp ) {
393                 DBGC ( gma, "GMA %p could not allocate queue pair\n", gma );
394                 rc = -ENOMEM;
395                 goto err_create_qp;
396         }
397         ib_qp_set_ownerdata ( gma->qp, gma );
398
399         DBGC ( gma, "GMA %p running on QPN %#lx\n", gma, gma->qp->qpn );
400
401         /* Fill receive ring */
402         ib_refill_recv ( ibdev, gma->qp );
403         return 0;
404
405         ib_destroy_qp ( ibdev, gma->qp );
406  err_create_qp:
407         ib_destroy_cq ( ibdev, gma->cq );
408  err_create_cq:
409         return rc;
410 }
411
412 /**
413  * Destroy GMA
414  *
415  * @v gma               General management agent
416  */
417 void ib_destroy_gma ( struct ib_gma *gma ) {
418         struct ib_device *ibdev = gma->ibdev;
419         struct ib_mad_request *request;
420         struct ib_mad_request *tmp;
421
422         /* Flush any outstanding requests */
423         list_for_each_entry_safe ( request, tmp, &gma->requests, list ) {
424                 stop_timer ( &request->timer );
425                 list_del ( &request->list );
426                 free ( request );
427         }
428
429         ib_destroy_qp ( ibdev, gma->qp );
430         ib_destroy_cq ( ibdev, gma->cq );
431 }