[infiniband] Add a "communication-managed reliable connection" protocol
[people/lynusvaz/gpxe.git] / src / net / infiniband / ib_cmrc.c
1 /*
2  * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *   Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  *   Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in
14  *   the documentation and/or other materials provided with the
15  *   distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 FILE_LICENCE ( BSD2 );
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <gpxe/iobuf.h>
37 #include <gpxe/xfer.h>
38 #include <gpxe/process.h>
39 #include <gpxe/infiniband.h>
40 #include <gpxe/ib_cm.h>
41 #include <gpxe/ib_cmrc.h>
42
43 /**
44  * @file
45  *
46  * Infiniband Communication-managed Reliable Connections
47  *
48  */
49
50 /** CMRC number of send WQEs
51  *
52  * This is a policy decision.
53  */
54 #define IB_CMRC_NUM_SEND_WQES 4
55
56 /** CMRC number of receive WQEs
57  *
58  * This is a policy decision.
59  */
60 #define IB_CMRC_NUM_RECV_WQES 2
61
62 /** CMRC number of completion queue entries
63  *
64  * This is a policy decision
65  */
66 #define IB_CMRC_NUM_CQES 8
67
68 /** An Infiniband Communication-Managed Reliable Connection */
69 struct ib_cmrc_connection {
70         /** Reference count */
71         struct refcnt refcnt;
72         /** Data transfer interface */
73         struct xfer_interface xfer;
74         /** Infiniband device */
75         struct ib_device *ibdev;
76         /** Completion queue */
77         struct ib_completion_queue *cq;
78         /** Queue pair */
79         struct ib_queue_pair *qp;
80         /** Connection */
81         struct ib_connection *conn;
82         /** Destination GID */
83         struct ib_gid dgid;
84         /** Service ID */
85         struct ib_gid_half service_id;
86         /** QP is connected */
87         int connected;
88         /** Shutdown process */
89         struct process shutdown;
90 };
91
92 /**
93  * Shut down CMRC connection gracefully
94  *
95  * @v process           Process
96  *
97  * The Infiniband data structures are not reference-counted or
98  * guarded.  It is therefore unsafe to shut them down while we may be
99  * in the middle of a callback from the Infiniband stack (e.g. in a
100  * receive completion handler).
101  *
102  * This shutdown process will run some time after the call to
103  * ib_cmrc_close(), after control has returned out of the Infiniband
104  * core, and will shut down the Infiniband interfaces cleanly.
105  *
106  * The shutdown process holds an implicit reference on the CMRC
107  * connection, ensuring that the structure is not freed before the
108  * shutdown process has run.
109  */
110 static void ib_cmrc_shutdown ( struct process *process ) {
111         struct ib_cmrc_connection *cmrc =
112                 container_of ( process, struct ib_cmrc_connection, shutdown );
113
114         DBGC ( cmrc, "CMRC %p shutting down\n", cmrc );
115
116         /* Shut down Infiniband interface */
117         ib_destroy_conn ( cmrc->ibdev, cmrc->qp, cmrc->conn );
118         ib_destroy_qp ( cmrc->ibdev, cmrc->qp );
119         ib_destroy_cq ( cmrc->ibdev, cmrc->cq );
120         ib_close ( cmrc->ibdev );
121
122         /* Remove process from run queue */
123         process_del ( &cmrc->shutdown );
124
125         /* Drop the remaining reference */
126         ref_put ( &cmrc->refcnt );
127 }
128
129 /**
130  * Close CMRC connection
131  *
132  * @v cmrc              Communication-Managed Reliable Connection
133  * @v rc                Reason for close
134  */
135 static void ib_cmrc_close ( struct ib_cmrc_connection *cmrc, int rc ) {
136
137         /* Close data transfer interface */
138         xfer_nullify ( &cmrc->xfer );
139         xfer_close ( &cmrc->xfer, rc );
140
141         /* Schedule shutdown process */
142         process_add ( &cmrc->shutdown );
143 }
144
145 /**
146  * Handle change of CMRC connection status
147  *
148  * @v ibdev             Infiniband device
149  * @v qp                Queue pair
150  * @v conn              Connection
151  * @v rc_cm             Connection status code
152  * @v private_data      Private data, if available
153  * @v private_data_len  Length of private data
154  */
155 static void ib_cmrc_changed ( struct ib_device *ibdev __unused,
156                               struct ib_queue_pair *qp,
157                               struct ib_connection *conn __unused, int rc_cm,
158                               void *private_data, size_t private_data_len ) {
159         struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
160         int rc_xfer;
161
162         /* Record connection status */
163         if ( rc_cm == 0 ) {
164                 DBGC ( cmrc, "CMRC %p connected\n", cmrc );
165                 cmrc->connected = 1;
166         } else {
167                 DBGC ( cmrc, "CMRC %p disconnected: %s\n",
168                        cmrc, strerror ( rc_cm ) );
169                 cmrc->connected = 0;
170         }
171
172         /* Pass up any private data */
173         DBGC2 ( cmrc, "CMRC %p received private data:\n", cmrc );
174         DBGC2_HDA ( cmrc, 0, private_data, private_data_len );
175         if ( ( rc_xfer = xfer_deliver_raw ( &cmrc->xfer, private_data,
176                                             private_data_len ) ) != 0 ) {
177                 DBGC ( cmrc, "CMRC %p could not deliver private data: %s\n",
178                        cmrc, strerror ( rc_xfer ) );
179                 ib_cmrc_close ( cmrc, rc_xfer );
180                 return;
181         }
182
183         /* If we are disconnected, close the upper connection */
184         if ( rc_cm != 0 ) {
185                 ib_cmrc_close ( cmrc, rc_cm );
186                 return;
187         }
188 }
189
190 /** CMRC connection operations */
191 static struct ib_connection_operations ib_cmrc_conn_op = {
192         .changed = ib_cmrc_changed,
193 };
194
195 /**
196  * Handle CMRC send completion
197  *
198  * @v ibdev             Infiniband device
199  * @v qp                Queue pair
200  * @v iobuf             I/O buffer
201  * @v rc                Completion status code
202  */
203 static void ib_cmrc_complete_send ( struct ib_device *ibdev __unused,
204                                     struct ib_queue_pair *qp,
205                                     struct io_buffer *iobuf, int rc ) {
206         struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
207
208         /* Free the completed I/O buffer */
209         free_iob ( iobuf );
210
211         /* Close the connection on any send errors */
212         if ( rc != 0 ) {
213                 DBGC ( cmrc, "CMRC %p send error: %s\n",
214                        cmrc, strerror ( rc ) );
215                 ib_cmrc_close ( cmrc, rc );
216                 return;
217         }
218 }
219
220 /**
221  * Handle CMRC receive completion
222  *
223  * @v ibdev             Infiniband device
224  * @v qp                Queue pair
225  * @v av                Address vector, or NULL
226  * @v iobuf             I/O buffer
227  * @v rc                Completion status code
228  */
229 static void ib_cmrc_complete_recv ( struct ib_device *ibdev __unused,
230                                     struct ib_queue_pair *qp,
231                                     struct ib_address_vector *av __unused,
232                                     struct io_buffer *iobuf, int rc ) {
233         struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
234
235         /* Close the connection on any receive errors */
236         if ( rc != 0 ) {
237                 DBGC ( cmrc, "CMRC %p receive error: %s\n",
238                        cmrc, strerror ( rc ) );
239                 free_iob ( iobuf );
240                 ib_cmrc_close ( cmrc, rc );
241                 return;
242         }
243
244         DBGC2 ( cmrc, "CMRC %p received:\n", cmrc );
245         DBGC2_HDA ( cmrc, 0, iobuf->data, iob_len ( iobuf ) );
246
247         /* Pass up data */
248         if ( ( rc = xfer_deliver_iob ( &cmrc->xfer, iobuf ) ) != 0 ) {
249                 DBGC ( cmrc, "CMRC %p could not deliver data: %s\n",
250                        cmrc, strerror ( rc ) );
251                 ib_cmrc_close ( cmrc, rc );
252                 return;
253         }
254 }
255
256 /** Infiniband CMRC completion operations */
257 static struct ib_completion_queue_operations ib_cmrc_completion_ops = {
258         .complete_send = ib_cmrc_complete_send,
259         .complete_recv = ib_cmrc_complete_recv,
260 };
261
262 /**
263  * Send data via CMRC
264  *
265  * @v xfer              Data transfer interface
266  * @v iobuf             Datagram I/O buffer
267  * @v meta              Data transfer metadata
268  * @ret rc              Return status code
269  */
270 static int ib_cmrc_xfer_deliver_iob ( struct xfer_interface *xfer,
271                                       struct io_buffer *iobuf,
272                                       struct xfer_metadata *meta __unused ) {
273         struct ib_cmrc_connection *cmrc =
274                 container_of ( xfer, struct ib_cmrc_connection, xfer );
275         int rc;
276
277         /* If no connection has yet been attempted, send this datagram
278          * as the CM REQ private data.  Otherwise, send it via the QP.
279          */
280         if ( ! cmrc->connected ) {
281
282                 /* Abort if we have already sent a CM connection request */
283                 if ( cmrc->conn ) {
284                         DBGC ( cmrc, "CMRC %p attempt to send before "
285                                "connection is complete\n", cmrc );
286                         rc = -EIO;
287                         goto out;
288                 }
289
290                 /* Send via CM connection request */
291                 cmrc->conn = ib_create_conn ( cmrc->ibdev, cmrc->qp,
292                                               &cmrc->dgid, &cmrc->service_id,
293                                               iobuf->data, iob_len ( iobuf ),
294                                               &ib_cmrc_conn_op );
295                 if ( ! cmrc->conn ) {
296                         DBGC ( cmrc, "CMRC %p could not connect\n", cmrc );
297                         rc = -ENOMEM;
298                         goto out;
299                 }
300
301         } else {
302
303                 /* Send via QP */
304                 if ( ( rc = ib_post_send ( cmrc->ibdev, cmrc->qp, NULL,
305                                            iob_disown ( iobuf ) ) ) != 0 ) {
306                         DBGC ( cmrc, "CMRC %p could not send: %s\n",
307                                cmrc, strerror ( rc ) );
308                         goto out;
309                 }
310
311         }
312         return 0;
313
314  out:
315         /* Free the I/O buffer if necessary */
316         free_iob ( iobuf );
317
318         /* Close the connection on any errors */
319         if ( rc != 0 )
320                 ib_cmrc_close ( cmrc, rc );
321
322         return rc;
323 }
324
325 /**
326  * Check CMRC flow control window
327  *
328  * @v xfer              Data transfer interface
329  * @ret len             Length of window
330  */
331 static size_t ib_cmrc_xfer_window ( struct xfer_interface *xfer ) {
332         struct ib_cmrc_connection *cmrc =
333                 container_of ( xfer, struct ib_cmrc_connection, xfer );
334
335         /* We indicate a window only when we are successfully
336          * connected.
337          */
338         return ( cmrc->connected ? IB_MAX_PAYLOAD_SIZE : 0 );
339 }
340
341 /**
342  * Close CMRC data-transfer interface
343  *
344  * @v xfer              Data transfer interface
345  * @v rc                Reason for close
346  */
347 static void ib_cmrc_xfer_close ( struct xfer_interface *xfer, int rc ) {
348         struct ib_cmrc_connection *cmrc =
349                 container_of ( xfer, struct ib_cmrc_connection, xfer );
350
351         DBGC ( cmrc, "CMRC %p closed: %s\n", cmrc, strerror ( rc ) );
352         ib_cmrc_close ( cmrc, rc );
353 }
354
355 /** CMRC data transfer interface operations */
356 static struct xfer_interface_operations ib_cmrc_xfer_operations = {
357         .close          = ib_cmrc_xfer_close,
358         .vredirect      = ignore_xfer_vredirect,
359         .window         = ib_cmrc_xfer_window,
360         .alloc_iob      = default_xfer_alloc_iob,
361         .deliver_iob    = ib_cmrc_xfer_deliver_iob,
362         .deliver_raw    = xfer_deliver_as_iob,
363 };
364
365 /**
366  * Open CMRC connection
367  *
368  * @v xfer              Data transfer interface
369  * @v ibdev             Infiniband device
370  * @v dgid              Destination GID
371  * @v service_id        Service ID
372  * @ret rc              Returns status code
373  */
374 int ib_cmrc_open ( struct xfer_interface *xfer, struct ib_device *ibdev,
375                    struct ib_gid *dgid, struct ib_gid_half *service_id ) {
376         struct ib_cmrc_connection *cmrc;
377         int rc;
378
379         /* Allocate and initialise structure */
380         cmrc = zalloc ( sizeof ( *cmrc ) );
381         if ( ! cmrc ) {
382                 rc = -ENOMEM;
383                 goto err_alloc;
384         }
385         xfer_init ( &cmrc->xfer, &ib_cmrc_xfer_operations, &cmrc->refcnt );
386         cmrc->ibdev = ibdev;
387         memcpy ( &cmrc->dgid, dgid, sizeof ( cmrc->dgid ) );
388         memcpy ( &cmrc->service_id, service_id, sizeof ( cmrc->service_id ) );
389         process_init_stopped ( &cmrc->shutdown, ib_cmrc_shutdown,
390                                &cmrc->refcnt );
391
392         /* Open Infiniband device */
393         if ( ( rc = ib_open ( ibdev ) ) != 0 ) {
394                 DBGC ( cmrc, "CMRC %p could not open device: %s\n",
395                        cmrc, strerror ( rc ) );
396                 goto err_open;
397         }
398
399         /* Create completion queue */
400         cmrc->cq = ib_create_cq ( ibdev, IB_CMRC_NUM_CQES,
401                                   &ib_cmrc_completion_ops );
402         if ( ! cmrc->cq ) {
403                 DBGC ( cmrc, "CMRC %p could not create completion queue\n",
404                        cmrc );
405                 rc = -ENOMEM;
406                 goto err_create_cq;
407         }
408
409         /* Create queue pair */
410         cmrc->qp = ib_create_qp ( ibdev, IB_QPT_RC, IB_CMRC_NUM_SEND_WQES,
411                                   cmrc->cq, IB_CMRC_NUM_RECV_WQES, cmrc->cq );
412         if ( ! cmrc->qp ) {
413                 DBGC ( cmrc, "CMRC %p could not create queue pair\n", cmrc );
414                 rc = -ENOMEM;
415                 goto err_create_qp;
416         }
417         ib_qp_set_ownerdata ( cmrc->qp, cmrc );
418         DBGC ( cmrc, "CMRC %p using QPN %lx\n", cmrc, cmrc->qp->qpn );
419
420         /* Attach to parent interface, transfer reference (implicitly)
421          * to our shutdown process, and return.
422          */
423         xfer_plug_plug ( &cmrc->xfer, xfer );
424         return 0;
425
426         ib_destroy_qp ( ibdev, cmrc->qp );
427  err_create_qp:
428         ib_destroy_cq ( ibdev, cmrc->cq );
429  err_create_cq:
430         ib_close ( ibdev );
431  err_open:
432         ref_put ( &cmrc->refcnt );
433  err_alloc:
434         return rc;
435 }