[infiniband] Use connection's local ID as debug message identifier
[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 DBGC ( cmrc, "CMRC %p using CM %08x\n",
307 cmrc, cmrc->conn->local_id );
308
309 } else {
310
311 /* Send via QP */
312 if ( ( rc = ib_post_send ( cmrc->ibdev, cmrc->qp, NULL,
313 iob_disown ( iobuf ) ) ) != 0 ) {
314 DBGC ( cmrc, "CMRC %p could not send: %s\n",
315 cmrc, strerror ( rc ) );
316 goto out;
317 }
318
319 }
320 return 0;
321
322 out:
323 /* Free the I/O buffer if necessary */
324 free_iob ( iobuf );
325
326 /* Close the connection on any errors */
327 if ( rc != 0 )
328 ib_cmrc_close ( cmrc, rc );
329
330 return rc;
331 }
332
333 /**
334 * Check CMRC flow control window
335 *
336 * @v cmrc CMRC connection
337 * @ret len Length of window
338 */
339 static size_t ib_cmrc_xfer_window ( struct ib_cmrc_connection *cmrc ) {
340
341 /* We indicate a window only when we are successfully
342 * connected.
343 */
344 return ( cmrc->connected ? IB_MAX_PAYLOAD_SIZE : 0 );
345 }
346
347 /**
348 * Identify device underlying CMRC connection
349 *
350 * @v cmrc CMRC connection
351 * @ret device Underlying device
352 */
353 static struct device *
354 ib_cmrc_identify_device ( struct ib_cmrc_connection *cmrc ) {
355 return cmrc->ibdev->dev;
356 }
357
358 /** CMRC data transfer interface operations */
359 static struct interface_operation ib_cmrc_xfer_operations[] = {
360 INTF_OP ( xfer_deliver, struct ib_cmrc_connection *,
361 ib_cmrc_xfer_deliver ),
362 INTF_OP ( xfer_window, struct ib_cmrc_connection *,
363 ib_cmrc_xfer_window ),
364 INTF_OP ( intf_close, struct ib_cmrc_connection *, ib_cmrc_close ),
365 INTF_OP ( identify_device, struct ib_cmrc_connection *,
366 ib_cmrc_identify_device ),
367 };
368
369 /** CMRC data transfer interface descriptor */
370 static struct interface_descriptor ib_cmrc_xfer_desc =
371 INTF_DESC ( struct ib_cmrc_connection, xfer, ib_cmrc_xfer_operations );
372
373 /** CMRC shutdown process descriptor */
374 static struct process_descriptor ib_cmrc_shutdown_desc =
375 PROC_DESC_ONCE ( struct ib_cmrc_connection, shutdown,
376 ib_cmrc_shutdown );
377
378 /**
379 * Open CMRC connection
380 *
381 * @v xfer Data transfer interface
382 * @v ibdev Infiniband device
383 * @v dgid Destination GID
384 * @v service_id Service ID
385 * @ret rc Returns status code
386 */
387 int ib_cmrc_open ( struct interface *xfer, struct ib_device *ibdev,
388 union ib_gid *dgid, union ib_guid *service_id ) {
389 struct ib_cmrc_connection *cmrc;
390 int rc;
391
392 /* Allocate and initialise structure */
393 cmrc = zalloc ( sizeof ( *cmrc ) );
394 if ( ! cmrc ) {
395 rc = -ENOMEM;
396 goto err_alloc;
397 }
398 ref_init ( &cmrc->refcnt, NULL );
399 intf_init ( &cmrc->xfer, &ib_cmrc_xfer_desc, &cmrc->refcnt );
400 cmrc->ibdev = ibdev;
401 memcpy ( &cmrc->dgid, dgid, sizeof ( cmrc->dgid ) );
402 memcpy ( &cmrc->service_id, service_id, sizeof ( cmrc->service_id ) );
403 process_init_stopped ( &cmrc->shutdown, &ib_cmrc_shutdown_desc,
404 &cmrc->refcnt );
405
406 /* Open Infiniband device */
407 if ( ( rc = ib_open ( ibdev ) ) != 0 ) {
408 DBGC ( cmrc, "CMRC %p could not open device: %s\n",
409 cmrc, strerror ( rc ) );
410 goto err_open;
411 }
412
413 /* Create completion queue */
414 cmrc->cq = ib_create_cq ( ibdev, IB_CMRC_NUM_CQES,
415 &ib_cmrc_completion_ops );
416 if ( ! cmrc->cq ) {
417 DBGC ( cmrc, "CMRC %p could not create completion queue\n",
418 cmrc );
419 rc = -ENOMEM;
420 goto err_create_cq;
421 }
422
423 /* Create queue pair */
424 cmrc->qp = ib_create_qp ( ibdev, IB_QPT_RC, IB_CMRC_NUM_SEND_WQES,
425 cmrc->cq, IB_CMRC_NUM_RECV_WQES, cmrc->cq,
426 &ib_cmrc_queue_pair_ops );
427 if ( ! cmrc->qp ) {
428 DBGC ( cmrc, "CMRC %p could not create queue pair\n", cmrc );
429 rc = -ENOMEM;
430 goto err_create_qp;
431 }
432 ib_qp_set_ownerdata ( cmrc->qp, cmrc );
433 DBGC ( cmrc, "CMRC %p using QPN %#lx\n", cmrc, cmrc->qp->qpn );
434
435 /* Attach to parent interface, transfer reference (implicitly)
436 * to our shutdown process, and return.
437 */
438 intf_plug_plug ( &cmrc->xfer, xfer );
439 return 0;
440
441 ib_destroy_qp ( ibdev, cmrc->qp );
442 err_create_qp:
443 ib_destroy_cq ( ibdev, cmrc->cq );
444 err_create_cq:
445 ib_close ( ibdev );
446 err_open:
447 ref_put ( &cmrc->refcnt );
448 err_alloc:
449 return rc;
450 }