• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
ib_cmrc_shutdown(struct process * process)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  */
ib_cmrc_close(struct ib_cmrc_connection * cmrc,int rc)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  */
ib_cmrc_changed(struct ib_device * ibdev __unused,struct ib_queue_pair * qp,struct ib_connection * conn __unused,int rc_cm,void * private_data,size_t private_data_len)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  */
ib_cmrc_complete_send(struct ib_device * ibdev __unused,struct ib_queue_pair * qp,struct io_buffer * iobuf,int rc)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  */
ib_cmrc_complete_recv(struct ib_device * ibdev __unused,struct ib_queue_pair * qp,struct ib_address_vector * av __unused,struct io_buffer * iobuf,int rc)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  */
ib_cmrc_xfer_deliver_iob(struct xfer_interface * xfer,struct io_buffer * iobuf,struct xfer_metadata * meta __unused)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  */
ib_cmrc_xfer_window(struct xfer_interface * xfer)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  */
ib_cmrc_xfer_close(struct xfer_interface * xfer,int rc)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  */
ib_cmrc_open(struct xfer_interface * xfer,struct ib_device * ibdev,struct ib_gid * dgid,struct ib_gid_half * service_id)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 }
437