Browse Source

[infiniband] Add a "communication-managed reliable connection" protocol

SRP over Infiniband uses a protocol whereby data is sent via a
combination of the CM private data fields and the RC queue pair
itself.  This seems sufficiently generic that it's worth having
available as a separate protocol.
tags/v0.9.8
Michael Brown 14 years ago
parent
commit
4be11f523c
3 changed files with 456 additions and 0 deletions
  1. 1
    0
      src/include/gpxe/errfile.h
  2. 20
    0
      src/include/gpxe/ib_cmrc.h
  3. 435
    0
      src/net/infiniband/ib_cmrc.c

+ 1
- 0
src/include/gpxe/errfile.h View File

@@ -153,6 +153,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
153 153
 #define ERRFILE_ib_cm			( ERRFILE_NET | 0x001e0000 )
154 154
 #define ERRFILE_net80211		( ERRFILE_NET | 0x001f0000 )
155 155
 #define ERRFILE_ib_mi			( ERRFILE_NET | 0x00200000 )
156
+#define ERRFILE_ib_cmrc			( ERRFILE_NET | 0x00210000 )
156 157
 
157 158
 #define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
158 159
 #define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )

+ 20
- 0
src/include/gpxe/ib_cmrc.h View File

@@ -0,0 +1,20 @@
1
+#ifndef _GPXE_IB_CMRC_H
2
+#define _GPXE_IB_CMRC_H
3
+
4
+/** @file
5
+ *
6
+ * Infiniband Communication-managed Reliable Connections
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( BSD2 );
11
+
12
+#include <gpxe/infiniband.h>
13
+#include <gpxe/xfer.h>
14
+
15
+extern int ib_cmrc_open ( struct xfer_interface *xfer,
16
+			  struct ib_device *ibdev,
17
+			  struct ib_gid *dgid,
18
+			  struct ib_gid_half *service_id );
19
+
20
+#endif /* _GPXE_IB_CMRC_H */

+ 435
- 0
src/net/infiniband/ib_cmrc.c View File

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

Loading…
Cancel
Save