2 * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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
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.
31 FILE_LICENCE ( BSD2 );
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>
46 * Infiniband Communication-managed Reliable Connections
50 /** CMRC number of send WQEs
52 * This is a policy decision.
54 #define IB_CMRC_NUM_SEND_WQES 4
56 /** CMRC number of receive WQEs
58 * This is a policy decision.
60 #define IB_CMRC_NUM_RECV_WQES 2
62 /** CMRC number of completion queue entries
64 * This is a policy decision
66 #define IB_CMRC_NUM_CQES 8
68 /** An Infiniband Communication-Managed Reliable Connection */
69 struct ib_cmrc_connection {
70 /** Reference count */
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;
79 struct ib_queue_pair *qp;
81 struct ib_connection *conn;
82 /** Destination GID */
85 union ib_guid service_id;
86 /** QP is connected */
88 /** Shutdown process */
89 struct process shutdown;
93 * Shut down CMRC connection gracefully
95 * @v cmrc Communication-Managed Reliable Connection
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).
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.
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.
110 static void ib_cmrc_shutdown ( struct ib_cmrc_connection *cmrc ) {
112 DBGC ( cmrc, "CMRC %p shutting down\n", cmrc );
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 );
120 /* Drop the remaining reference */
121 ref_put ( &cmrc->refcnt );
125 * Close CMRC connection
127 * @v cmrc Communication-Managed Reliable Connection
128 * @v rc Reason for close
130 static void ib_cmrc_close ( struct ib_cmrc_connection *cmrc, int rc ) {
132 /* Close data transfer interface */
133 intf_shutdown ( &cmrc->xfer, rc );
135 /* Schedule shutdown process */
136 process_add ( &cmrc->shutdown );
140 * Handle change of CMRC connection status
142 * @v ibdev Infiniband device
145 * @v rc_cm Connection status code
146 * @v private_data Private data, if available
147 * @v private_data_len Length of private data
149 static void ib_cmrc_changed ( struct ib_device *ibdev __unused,
150 struct ib_queue_pair *qp,
151 struct ib_connection *conn __unused, int rc_cm,
152 void *private_data, size_t private_data_len ) {
153 struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
156 /* Record connection status */
158 DBGC ( cmrc, "CMRC %p connected\n", cmrc );
161 DBGC ( cmrc, "CMRC %p disconnected: %s\n",
162 cmrc, strerror ( rc_cm ) );
166 /* Pass up any private data */
167 DBGC2 ( cmrc, "CMRC %p received private data:\n", cmrc );
168 DBGC2_HDA ( cmrc, 0, private_data, private_data_len );
170 ( rc_xfer = xfer_deliver_raw ( &cmrc->xfer, private_data,
171 private_data_len ) ) != 0 ) {
172 DBGC ( cmrc, "CMRC %p could not deliver private data: %s\n",
173 cmrc, strerror ( rc_xfer ) );
174 ib_cmrc_close ( cmrc, rc_xfer );
178 /* Notify upper connection of window change */
179 xfer_window_changed ( &cmrc->xfer );
181 /* If we are disconnected, close the upper connection */
183 ib_cmrc_close ( cmrc, rc_cm );
188 /** CMRC connection operations */
189 static struct ib_connection_operations ib_cmrc_conn_op = {
190 .changed = ib_cmrc_changed,
194 * Handle CMRC send completion
196 * @v ibdev Infiniband device
198 * @v iobuf I/O buffer
199 * @v rc Completion status code
201 static void ib_cmrc_complete_send ( struct ib_device *ibdev __unused,
202 struct ib_queue_pair *qp,
203 struct io_buffer *iobuf, int rc ) {
204 struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
206 /* Free the completed I/O buffer */
209 /* Close the connection on any send errors */
211 DBGC ( cmrc, "CMRC %p send error: %s\n",
212 cmrc, strerror ( rc ) );
213 ib_cmrc_close ( cmrc, rc );
219 * Handle CMRC receive completion
221 * @v ibdev Infiniband device
223 * @v dest Destination address vector, or NULL
224 * @v source Source address vector, or NULL
225 * @v iobuf I/O buffer
226 * @v rc Completion status code
228 static void ib_cmrc_complete_recv ( struct ib_device *ibdev __unused,
229 struct ib_queue_pair *qp,
230 struct ib_address_vector *dest __unused,
231 struct ib_address_vector *source __unused,
232 struct io_buffer *iobuf, int rc ) {
233 struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
235 /* Close the connection on any receive errors */
237 DBGC ( cmrc, "CMRC %p receive error: %s\n",
238 cmrc, strerror ( rc ) );
240 ib_cmrc_close ( cmrc, rc );
244 DBGC2 ( cmrc, "CMRC %p received:\n", cmrc );
245 DBGC2_HDA ( cmrc, 0, iobuf->data, iob_len ( iobuf ) );
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 );
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,
262 /** Infiniband CMRC queue pair operations */
263 static struct ib_queue_pair_operations ib_cmrc_queue_pair_ops = {
264 .alloc_iob = alloc_iob,
270 * @v cmrc CMRC connection
271 * @v iobuf Datagram I/O buffer
272 * @v meta Data transfer metadata
273 * @ret rc Return status code
275 static int ib_cmrc_xfer_deliver ( struct ib_cmrc_connection *cmrc,
276 struct io_buffer *iobuf,
277 struct xfer_metadata *meta __unused ) {
280 /* If no connection has yet been attempted, send this datagram
281 * as the CM REQ private data. Otherwise, send it via the QP.
283 if ( ! cmrc->connected ) {
285 /* Abort if we have already sent a CM connection request */
287 DBGC ( cmrc, "CMRC %p attempt to send before "
288 "connection is complete\n", cmrc );
293 /* Send via CM connection request */
294 cmrc->conn = ib_create_conn ( cmrc->ibdev, cmrc->qp,
295 &cmrc->dgid, &cmrc->service_id,
296 iobuf->data, iob_len ( iobuf ),
298 if ( ! cmrc->conn ) {
299 DBGC ( cmrc, "CMRC %p could not connect\n", cmrc );
307 if ( ( rc = ib_post_send ( cmrc->ibdev, cmrc->qp, NULL,
308 iob_disown ( iobuf ) ) ) != 0 ) {
309 DBGC ( cmrc, "CMRC %p could not send: %s\n",
310 cmrc, strerror ( rc ) );
318 /* Free the I/O buffer if necessary */
321 /* Close the connection on any errors */
323 ib_cmrc_close ( cmrc, rc );
329 * Check CMRC flow control window
331 * @v cmrc CMRC connection
332 * @ret len Length of window
334 static size_t ib_cmrc_xfer_window ( struct ib_cmrc_connection *cmrc ) {
336 /* We indicate a window only when we are successfully
339 return ( cmrc->connected ? IB_MAX_PAYLOAD_SIZE : 0 );
343 * Identify device underlying CMRC connection
345 * @v cmrc CMRC connection
346 * @ret device Underlying device
348 static struct device *
349 ib_cmrc_identify_device ( struct ib_cmrc_connection *cmrc ) {
350 return cmrc->ibdev->dev;
353 /** CMRC data transfer interface operations */
354 static struct interface_operation ib_cmrc_xfer_operations[] = {
355 INTF_OP ( xfer_deliver, struct ib_cmrc_connection *,
356 ib_cmrc_xfer_deliver ),
357 INTF_OP ( xfer_window, struct ib_cmrc_connection *,
358 ib_cmrc_xfer_window ),
359 INTF_OP ( intf_close, struct ib_cmrc_connection *, ib_cmrc_close ),
360 INTF_OP ( identify_device, struct ib_cmrc_connection *,
361 ib_cmrc_identify_device ),
364 /** CMRC data transfer interface descriptor */
365 static struct interface_descriptor ib_cmrc_xfer_desc =
366 INTF_DESC ( struct ib_cmrc_connection, xfer, ib_cmrc_xfer_operations );
368 /** CMRC shutdown process descriptor */
369 static struct process_descriptor ib_cmrc_shutdown_desc =
370 PROC_DESC_ONCE ( struct ib_cmrc_connection, shutdown,
374 * Open CMRC connection
376 * @v xfer Data transfer interface
377 * @v ibdev Infiniband device
378 * @v dgid Destination GID
379 * @v service_id Service ID
380 * @ret rc Returns status code
382 int ib_cmrc_open ( struct interface *xfer, struct ib_device *ibdev,
383 union ib_gid *dgid, union ib_guid *service_id ) {
384 struct ib_cmrc_connection *cmrc;
387 /* Allocate and initialise structure */
388 cmrc = zalloc ( sizeof ( *cmrc ) );
393 ref_init ( &cmrc->refcnt, NULL );
394 intf_init ( &cmrc->xfer, &ib_cmrc_xfer_desc, &cmrc->refcnt );
396 memcpy ( &cmrc->dgid, dgid, sizeof ( cmrc->dgid ) );
397 memcpy ( &cmrc->service_id, service_id, sizeof ( cmrc->service_id ) );
398 process_init_stopped ( &cmrc->shutdown, &ib_cmrc_shutdown_desc,
401 /* Open Infiniband device */
402 if ( ( rc = ib_open ( ibdev ) ) != 0 ) {
403 DBGC ( cmrc, "CMRC %p could not open device: %s\n",
404 cmrc, strerror ( rc ) );
408 /* Create completion queue */
409 cmrc->cq = ib_create_cq ( ibdev, IB_CMRC_NUM_CQES,
410 &ib_cmrc_completion_ops );
412 DBGC ( cmrc, "CMRC %p could not create completion queue\n",
418 /* Create queue pair */
419 cmrc->qp = ib_create_qp ( ibdev, IB_QPT_RC, IB_CMRC_NUM_SEND_WQES,
420 cmrc->cq, IB_CMRC_NUM_RECV_WQES, cmrc->cq,
421 &ib_cmrc_queue_pair_ops );
423 DBGC ( cmrc, "CMRC %p could not create queue pair\n", cmrc );
427 ib_qp_set_ownerdata ( cmrc->qp, cmrc );
428 DBGC ( cmrc, "CMRC %p using QPN %lx\n", cmrc, cmrc->qp->qpn );
430 /* Attach to parent interface, transfer reference (implicitly)
431 * to our shutdown process, and return.
433 intf_plug_plug ( &cmrc->xfer, xfer );
436 ib_destroy_qp ( ibdev, cmrc->qp );
438 ib_destroy_cq ( ibdev, cmrc->cq );
442 ref_put ( &cmrc->refcnt );