[infiniband] Use "%#lx" as format specifier for queue pair numbers
[ipxe.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 <ipxe/iobuf.h>
37 #include <ipxe/xfer.h>
38 #include <ipxe/process.h>
39 #include <ipxe/infiniband.h>
40 #include <ipxe/ib_cm.h>
41 #include <ipxe/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 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 union ib_gid dgid;
84 /** Service ID */
85 union ib_guid 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 cmrc Communication-Managed Reliable Connection
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 ib_cmrc_connection *cmrc ) {
111
112 DBGC ( cmrc, "CMRC %p shutting down\n", cmrc );
113
114 /* Shut down Infiniband interface */
115 ib_destroy_conn ( cmrc->ibdev, cmrc->qp, cmrc->conn );
116 ib_destroy_qp ( cmrc->ibdev, cmrc->qp );
117 ib_destroy_cq ( cmrc->ibdev, cmrc->cq );
118 ib_close ( cmrc->ibdev );
119
120 /* Cancel any pending shutdown */
121 process_del ( &cmrc->shutdown );
122
123 /* Drop the remaining reference */
124 ref_put ( &cmrc->refcnt );
125 }
126
127 /**
128 * Close CMRC connection
129 *
130 * @v cmrc Communication-Managed Reliable Connection
131 * @v rc Reason for close
132 */
133 static void ib_cmrc_close ( struct ib_cmrc_connection *cmrc, int rc ) {
134
135 /* Close data transfer interface */
136 intf_shutdown ( &cmrc->xfer, rc );
137
138 /* Schedule shutdown process */
139 process_add ( &cmrc->shutdown );
140 }
141
142 /**
143 * Handle change of CMRC connection status
144 *
145 * @v ibdev Infiniband device
146 * @v qp Queue pair
147 * @v conn Connection
148 * @v rc_cm Connection status code
149 * @v private_data Private data, if available
150 * @v private_data_len Length of private data
151 */
152 static void ib_cmrc_changed ( struct ib_device *ibdev __unused,
153 struct ib_queue_pair *qp,
154 struct ib_connection *conn __unused, int rc_cm,
155 void *private_data, size_t private_data_len ) {
156 struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
157 int rc_xfer;
158
159 /* Record connection status */
160 if ( rc_cm == 0 ) {
161 DBGC ( cmrc, "CMRC %p connected\n", cmrc );
162 cmrc->connected = 1;
163 } else {
164 DBGC ( cmrc, "CMRC %p disconnected: %s\n",
165 cmrc, strerror ( rc_cm ) );
166 cmrc->connected = 0;
167 }
168
169 /* Pass up any private data */
170 DBGC2 ( cmrc, "CMRC %p received private data:\n", cmrc );
171 DBGC2_HDA ( cmrc, 0, private_data, private_data_len );
172 if ( private_data &&
173 ( rc_xfer = xfer_deliver_raw ( &cmrc->xfer, private_data,
174 private_data_len ) ) != 0 ) {
175 DBGC ( cmrc, "CMRC %p could not deliver private data: %s\n",
176 cmrc, strerror ( rc_xfer ) );
177 ib_cmrc_close ( cmrc, rc_xfer );
178 return;
179 }
180
181 /* Notify upper connection of window change */
182 xfer_window_changed ( &cmrc->xfer );
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 dest Destination address vector, or NULL
227 * @v source Source address vector, or NULL
228 * @v iobuf I/O buffer
229 * @v rc Completion status code
230 */
231 static void ib_cmrc_complete_recv ( struct ib_device *ibdev __unused,
232 struct ib_queue_pair *qp,
233 struct ib_address_vector *dest __unused,
234 struct ib_address_vector *source __unused,
235 struct io_buffer *iobuf, int rc ) {
236 struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
237
238 /* Close the connection on any receive errors */
239 if ( rc != 0 ) {
240 DBGC ( cmrc, "CMRC %p receive error: %s\n",
241 cmrc, strerror ( rc ) );
242 free_iob ( iobuf );
243 ib_cmrc_close ( cmrc, rc );
244 return;
245 }
246
247 DBGC2 ( cmrc, "CMRC %p received:\n", cmrc );
248 DBGC2_HDA ( cmrc, 0, iobuf->data, iob_len ( iobuf ) );
249
250 /* Pass up data */
251 if ( ( rc = xfer_deliver_iob ( &cmrc->xfer, iobuf ) ) != 0 ) {
252 DBGC ( cmrc, "CMRC %p could not deliver data: %s\n",
253 cmrc, strerror ( rc ) );
254 ib_cmrc_close ( cmrc, rc );
255 return;
256 }
257 }
258
259 /** Infiniband CMRC completion operations */
260 static struct ib_completion_queue_operations ib_cmrc_completion_ops = {
261 .complete_send = ib_cmrc_complete_send,
262 .complete_recv = ib_cmrc_complete_recv,
263 };
264
265 /** Infiniband CMRC queue pair operations */
266 static struct ib_queue_pair_operations ib_cmrc_queue_pair_ops = {
267 .alloc_iob = alloc_iob,
268 };
269
270 /**
271 * Send data via CMRC
272 *
273 * @v cmrc CMRC connection
274 * @v iobuf Datagram I/O buffer
275 * @v meta Data transfer metadata
276 * @ret rc Return status code
277 */
278 static int ib_cmrc_xfer_deliver ( struct ib_cmrc_connection *cmrc,
279 struct io_buffer *iobuf,
280 struct xfer_metadata *meta __unused ) {
281 int rc;
282
283 /* If no connection has yet been attempted, send this datagram
284 * as the CM REQ private data. Otherwise, send it via the QP.
285 */
286 if ( ! cmrc->connected ) {
287
288 /* Abort if we have already sent a CM connection request */
289 if ( cmrc->conn ) {
290 DBGC ( cmrc, "CMRC %p attempt to send before "
291 "connection is complete\n", cmrc );
292 rc = -EIO;
293 goto out;
294 }
295
296 /* Send via CM connection request */
297 cmrc->conn = ib_create_conn ( cmrc->ibdev, cmrc->qp,
298 &cmrc->dgid, &cmrc->service_id,
299 iobuf->data, iob_len ( iobuf ),
300 &ib_cmrc_conn_op );
301 if ( ! cmrc->conn ) {
302 DBGC ( cmrc, "CMRC %p could not connect\n", cmrc );
303 rc = -ENOMEM;
304 goto out;
305 }
306
307 } else {
308
309 /* Send via QP */
310 if ( ( rc = ib_post_send ( cmrc->ibdev, cmrc->qp, NULL,
311 iob_disown ( iobuf ) ) ) != 0 ) {
312 DBGC ( cmrc, "CMRC %p could not send: %s\n",
313 cmrc, strerror ( rc ) );
314 goto out;
315 }
316
317 }
318 return 0;
319
320 out:
321 /* Free the I/O buffer if necessary */
322 free_iob ( iobuf );
323
324 /* Close the connection on any errors */
325 if ( rc != 0 )
326 ib_cmrc_close ( cmrc, rc );
327
328 return rc;
329 }
330
331 /**
332 * Check CMRC flow control window
333 *
334 * @v cmrc CMRC connection
335 * @ret len Length of window
336 */
337 static size_t ib_cmrc_xfer_window ( struct ib_cmrc_connection *cmrc ) {
338
339 /* We indicate a window only when we are successfully
340 * connected.
341 */
342 return ( cmrc->connected ? IB_MAX_PAYLOAD_SIZE : 0 );
343 }
344
345 /**
346 * Identify device underlying CMRC connection
347 *
348 * @v cmrc CMRC connection
349 * @ret device Underlying device
350 */
351 static struct device *
352 ib_cmrc_identify_device ( struct ib_cmrc_connection *cmrc ) {
353 return cmrc->ibdev->dev;
354 }
355
356 /** CMRC data transfer interface operations */
357 static struct interface_operation ib_cmrc_xfer_operations[] = {
358 INTF_OP ( xfer_deliver, struct ib_cmrc_connection *,
359 ib_cmrc_xfer_deliver ),
360 INTF_OP ( xfer_window, struct ib_cmrc_connection *,
361 ib_cmrc_xfer_window ),
362 INTF_OP ( intf_close, struct ib_cmrc_connection *, ib_cmrc_close ),
363 INTF_OP ( identify_device, struct ib_cmrc_connection *,
364 ib_cmrc_identify_device ),
365 };
366
367 /** CMRC data transfer interface descriptor */
368 static struct interface_descriptor ib_cmrc_xfer_desc =
369 INTF_DESC ( struct ib_cmrc_connection, xfer, ib_cmrc_xfer_operations );
370
371 /** CMRC shutdown process descriptor */
372 static struct process_descriptor ib_cmrc_shutdown_desc =
373 PROC_DESC_ONCE ( struct ib_cmrc_connection, shutdown,
374 ib_cmrc_shutdown );
375
376 /**
377 * Open CMRC connection
378 *
379 * @v xfer Data transfer interface
380 * @v ibdev Infiniband device
381 * @v dgid Destination GID
382 * @v service_id Service ID
383 * @ret rc Returns status code
384 */
385 int ib_cmrc_open ( struct interface *xfer, struct ib_device *ibdev,
386 union ib_gid *dgid, union ib_guid *service_id ) {
387 struct ib_cmrc_connection *cmrc;
388 int rc;
389
390 /* Allocate and initialise structure */
391 cmrc = zalloc ( sizeof ( *cmrc ) );
392 if ( ! cmrc ) {
393 rc = -ENOMEM;
394 goto err_alloc;
395 }
396 ref_init ( &cmrc->refcnt, NULL );
397 intf_init ( &cmrc->xfer, &ib_cmrc_xfer_desc, &cmrc->refcnt );
398 cmrc->ibdev = ibdev;
399 memcpy ( &cmrc->dgid, dgid, sizeof ( cmrc->dgid ) );
400 memcpy ( &cmrc->service_id, service_id, sizeof ( cmrc->service_id ) );
401 process_init_stopped ( &cmrc->shutdown, &ib_cmrc_shutdown_desc,
402 &cmrc->refcnt );
403
404 /* Open Infiniband device */
405 if ( ( rc = ib_open ( ibdev ) ) != 0 ) {
406 DBGC ( cmrc, "CMRC %p could not open device: %s\n",
407 cmrc, strerror ( rc ) );
408 goto err_open;
409 }
410
411 /* Create completion queue */
412 cmrc->cq = ib_create_cq ( ibdev, IB_CMRC_NUM_CQES,
413 &ib_cmrc_completion_ops );
414 if ( ! cmrc->cq ) {
415 DBGC ( cmrc, "CMRC %p could not create completion queue\n",
416 cmrc );
417 rc = -ENOMEM;
418 goto err_create_cq;
419 }
420
421 /* Create queue pair */
422 cmrc->qp = ib_create_qp ( ibdev, IB_QPT_RC, IB_CMRC_NUM_SEND_WQES,
423 cmrc->cq, IB_CMRC_NUM_RECV_WQES, cmrc->cq,
424 &ib_cmrc_queue_pair_ops );
425 if ( ! cmrc->qp ) {
426 DBGC ( cmrc, "CMRC %p could not create queue pair\n", cmrc );
427 rc = -ENOMEM;
428 goto err_create_qp;
429 }
430 ib_qp_set_ownerdata ( cmrc->qp, cmrc );
431 DBGC ( cmrc, "CMRC %p using QPN %#lx\n", cmrc, cmrc->qp->qpn );
432
433 /* Attach to parent interface, transfer reference (implicitly)
434 * to our shutdown process, and return.
435 */
436 intf_plug_plug ( &cmrc->xfer, xfer );
437 return 0;
438
439 ib_destroy_qp ( ibdev, cmrc->qp );
440 err_create_qp:
441 ib_destroy_cq ( ibdev, cmrc->cq );
442 err_create_cq:
443 ib_close ( ibdev );
444 err_open:
445 ref_put ( &cmrc->refcnt );
446 err_alloc:
447 return rc;
448 }