[infiniband] Disambiguate CM connection rejection reasons
[people/pcmattman/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 ( private_data &&
176              ( rc_xfer = xfer_deliver_raw ( &cmrc->xfer, private_data,
177                                             private_data_len ) ) != 0 ) {
178                 DBGC ( cmrc, "CMRC %p could not deliver private data: %s\n",
179                        cmrc, strerror ( rc_xfer ) );
180                 ib_cmrc_close ( cmrc, rc_xfer );
181                 return;
182         }
183
184         /* If we are disconnected, close the upper connection */
185         if ( rc_cm != 0 ) {
186                 ib_cmrc_close ( cmrc, rc_cm );
187                 return;
188         }
189 }
190
191 /** CMRC connection operations */
192 static struct ib_connection_operations ib_cmrc_conn_op = {
193         .changed = ib_cmrc_changed,
194 };
195
196 /**
197  * Handle CMRC send completion
198  *
199  * @v ibdev             Infiniband device
200  * @v qp                Queue pair
201  * @v iobuf             I/O buffer
202  * @v rc                Completion status code
203  */
204 static void ib_cmrc_complete_send ( struct ib_device *ibdev __unused,
205                                     struct ib_queue_pair *qp,
206                                     struct io_buffer *iobuf, int rc ) {
207         struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
208
209         /* Free the completed I/O buffer */
210         free_iob ( iobuf );
211
212         /* Close the connection on any send errors */
213         if ( rc != 0 ) {
214                 DBGC ( cmrc, "CMRC %p send error: %s\n",
215                        cmrc, strerror ( rc ) );
216                 ib_cmrc_close ( cmrc, rc );
217                 return;
218         }
219 }
220
221 /**
222  * Handle CMRC receive completion
223  *
224  * @v ibdev             Infiniband device
225  * @v qp                Queue pair
226  * @v av                Address vector, or NULL
227  * @v iobuf             I/O buffer
228  * @v rc                Completion status code
229  */
230 static void ib_cmrc_complete_recv ( struct ib_device *ibdev __unused,
231                                     struct ib_queue_pair *qp,
232                                     struct ib_address_vector *av __unused,
233                                     struct io_buffer *iobuf, int rc ) {
234         struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
235
236         /* Close the connection on any receive errors */
237         if ( rc != 0 ) {
238                 DBGC ( cmrc, "CMRC %p receive error: %s\n",
239                        cmrc, strerror ( rc ) );
240                 free_iob ( iobuf );
241                 ib_cmrc_close ( cmrc, rc );
242                 return;
243         }
244
245         DBGC2 ( cmrc, "CMRC %p received:\n", cmrc );
246         DBGC2_HDA ( cmrc, 0, iobuf->data, iob_len ( iobuf ) );
247
248         /* Pass up data */
249         if ( ( rc = xfer_deliver_iob ( &cmrc->xfer, iobuf ) ) != 0 ) {
250                 DBGC ( cmrc, "CMRC %p could not deliver data: %s\n",
251                        cmrc, strerror ( rc ) );
252                 ib_cmrc_close ( cmrc, rc );
253                 return;
254         }
255 }
256
257 /** Infiniband CMRC completion operations */
258 static struct ib_completion_queue_operations ib_cmrc_completion_ops = {
259         .complete_send = ib_cmrc_complete_send,
260         .complete_recv = ib_cmrc_complete_recv,
261 };
262
263 /**
264  * Send data via CMRC
265  *
266  * @v xfer              Data transfer interface
267  * @v iobuf             Datagram I/O buffer
268  * @v meta              Data transfer metadata
269  * @ret rc              Return status code
270  */
271 static int ib_cmrc_xfer_deliver_iob ( struct xfer_interface *xfer,
272                                       struct io_buffer *iobuf,
273                                       struct xfer_metadata *meta __unused ) {
274         struct ib_cmrc_connection *cmrc =
275                 container_of ( xfer, struct ib_cmrc_connection, xfer );
276         int rc;
277
278         /* If no connection has yet been attempted, send this datagram
279          * as the CM REQ private data.  Otherwise, send it via the QP.
280          */
281         if ( ! cmrc->connected ) {
282
283                 /* Abort if we have already sent a CM connection request */
284                 if ( cmrc->conn ) {
285                         DBGC ( cmrc, "CMRC %p attempt to send before "
286                                "connection is complete\n", cmrc );
287                         rc = -EIO;
288                         goto out;
289                 }
290
291                 /* Send via CM connection request */
292                 cmrc->conn = ib_create_conn ( cmrc->ibdev, cmrc->qp,
293                                               &cmrc->dgid, &cmrc->service_id,
294                                               iobuf->data, iob_len ( iobuf ),
295                                               &ib_cmrc_conn_op );
296                 if ( ! cmrc->conn ) {
297                         DBGC ( cmrc, "CMRC %p could not connect\n", cmrc );
298                         rc = -ENOMEM;
299                         goto out;
300                 }
301
302         } else {
303
304                 /* Send via QP */
305                 if ( ( rc = ib_post_send ( cmrc->ibdev, cmrc->qp, NULL,
306                                            iob_disown ( iobuf ) ) ) != 0 ) {
307                         DBGC ( cmrc, "CMRC %p could not send: %s\n",
308                                cmrc, strerror ( rc ) );
309                         goto out;
310                 }
311
312         }
313         return 0;
314
315  out:
316         /* Free the I/O buffer if necessary */
317         free_iob ( iobuf );
318
319         /* Close the connection on any errors */
320         if ( rc != 0 )
321                 ib_cmrc_close ( cmrc, rc );
322
323         return rc;
324 }
325
326 /**
327  * Check CMRC flow control window
328  *
329  * @v xfer              Data transfer interface
330  * @ret len             Length of window
331  */
332 static size_t ib_cmrc_xfer_window ( struct xfer_interface *xfer ) {
333         struct ib_cmrc_connection *cmrc =
334                 container_of ( xfer, struct ib_cmrc_connection, xfer );
335
336         /* We indicate a window only when we are successfully
337          * connected.
338          */
339         return ( cmrc->connected ? IB_MAX_PAYLOAD_SIZE : 0 );
340 }
341
342 /**
343  * Close CMRC data-transfer interface
344  *
345  * @v xfer              Data transfer interface
346  * @v rc                Reason for close
347  */
348 static void ib_cmrc_xfer_close ( struct xfer_interface *xfer, int rc ) {
349         struct ib_cmrc_connection *cmrc =
350                 container_of ( xfer, struct ib_cmrc_connection, xfer );
351
352         DBGC ( cmrc, "CMRC %p closed: %s\n", cmrc, strerror ( rc ) );
353         ib_cmrc_close ( cmrc, rc );
354 }
355
356 /** CMRC data transfer interface operations */
357 static struct xfer_interface_operations ib_cmrc_xfer_operations = {
358         .close          = ib_cmrc_xfer_close,
359         .vredirect      = ignore_xfer_vredirect,
360         .window         = ib_cmrc_xfer_window,
361         .alloc_iob      = default_xfer_alloc_iob,
362         .deliver_iob    = ib_cmrc_xfer_deliver_iob,
363         .deliver_raw    = xfer_deliver_as_iob,
364 };
365
366 /**
367  * Open CMRC connection
368  *
369  * @v xfer              Data transfer interface
370  * @v ibdev             Infiniband device
371  * @v dgid              Destination GID
372  * @v service_id        Service ID
373  * @ret rc              Returns status code
374  */
375 int ib_cmrc_open ( struct xfer_interface *xfer, struct ib_device *ibdev,
376                    struct ib_gid *dgid, struct ib_gid_half *service_id ) {
377         struct ib_cmrc_connection *cmrc;
378         int rc;
379
380         /* Allocate and initialise structure */
381         cmrc = zalloc ( sizeof ( *cmrc ) );
382         if ( ! cmrc ) {
383                 rc = -ENOMEM;
384                 goto err_alloc;
385         }
386         xfer_init ( &cmrc->xfer, &ib_cmrc_xfer_operations, &cmrc->refcnt );
387         cmrc->ibdev = ibdev;
388         memcpy ( &cmrc->dgid, dgid, sizeof ( cmrc->dgid ) );
389         memcpy ( &cmrc->service_id, service_id, sizeof ( cmrc->service_id ) );
390         process_init_stopped ( &cmrc->shutdown, ib_cmrc_shutdown,
391                                &cmrc->refcnt );
392
393         /* Open Infiniband device */
394         if ( ( rc = ib_open ( ibdev ) ) != 0 ) {
395                 DBGC ( cmrc, "CMRC %p could not open device: %s\n",
396                        cmrc, strerror ( rc ) );
397                 goto err_open;
398         }
399
400         /* Create completion queue */
401         cmrc->cq = ib_create_cq ( ibdev, IB_CMRC_NUM_CQES,
402                                   &ib_cmrc_completion_ops );
403         if ( ! cmrc->cq ) {
404                 DBGC ( cmrc, "CMRC %p could not create completion queue\n",
405                        cmrc );
406                 rc = -ENOMEM;
407                 goto err_create_cq;
408         }
409
410         /* Create queue pair */
411         cmrc->qp = ib_create_qp ( ibdev, IB_QPT_RC, IB_CMRC_NUM_SEND_WQES,
412                                   cmrc->cq, IB_CMRC_NUM_RECV_WQES, cmrc->cq );
413         if ( ! cmrc->qp ) {
414                 DBGC ( cmrc, "CMRC %p could not create queue pair\n", cmrc );
415                 rc = -ENOMEM;
416                 goto err_create_qp;
417         }
418         ib_qp_set_ownerdata ( cmrc->qp, cmrc );
419         DBGC ( cmrc, "CMRC %p using QPN %lx\n", cmrc, cmrc->qp->qpn );
420
421         /* Attach to parent interface, transfer reference (implicitly)
422          * to our shutdown process, and return.
423          */
424         xfer_plug_plug ( &cmrc->xfer, xfer );
425         return 0;
426
427         ib_destroy_qp ( ibdev, cmrc->qp );
428  err_create_qp:
429         ib_destroy_cq ( ibdev, cmrc->cq );
430  err_create_cq:
431         ib_close ( ibdev );
432  err_open:
433         ref_put ( &cmrc->refcnt );
434  err_alloc:
435         return rc;
436 }