Procházet zdrojové kódy

[infiniband] Add the concept of a management interface

A management interface is the component through which both local and
remote management agents are accessed.

This new implementation of a management interface allows for the user
to react to timed-out transactions, and also allows for cancellation
of in-progress transactions.
tags/v0.9.8
Michael Brown před 15 roky
rodič
revize
0e07516f62

+ 1
- 0
src/include/gpxe/errfile.h Zobrazit soubor

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

+ 3
- 1
src/include/gpxe/ib_mad.h Zobrazit soubor

@@ -491,7 +491,9 @@ struct ib_mad_hdr {
491 491
 #define IB_MGMT_CLASS_CM			0x07
492 492
 #define IB_MGMT_CLASS_SNMP			0x08
493 493
 #define IB_MGMT_CLASS_VENDOR_RANGE2_START	0x30
494
-#define IB_MGMT_CLASS_VENDOR_RANGE2_END		0x4F
494
+#define IB_MGMT_CLASS_VENDOR_RANGE2_END		0x4f
495
+
496
+#define IB_MGMT_CLASS_MASK			0x7f
495 497
 
496 498
 /* Management methods */
497 499
 #define IB_MGMT_METHOD_GET			0x01

+ 135
- 0
src/include/gpxe/ib_mi.h Zobrazit soubor

@@ -0,0 +1,135 @@
1
+#ifndef _GPXE_IB_MI_H
2
+#define _GPXE_IB_MI_H
3
+
4
+/** @file
5
+ *
6
+ * Infiniband management interfaces
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+#include <gpxe/list.h>
13
+#include <gpxe/retry.h>
14
+#include <gpxe/tables.h>
15
+#include <gpxe/infiniband.h>
16
+
17
+struct ib_mad_interface;
18
+struct ib_mad_transaction;
19
+
20
+/** An Infiniband management agent */
21
+struct ib_mad_agent {
22
+	/** Management class */
23
+	uint8_t mgmt_class;
24
+	/** Class version */
25
+	uint8_t class_version;
26
+	/** Attribute (in network byte order) */
27
+	uint16_t attr_id;
28
+	/** Handle MAD
29
+	 *
30
+	 * @v ibdev		Infiniband device
31
+	 * @v mi		Management interface
32
+	 * @v mad		Received MAD
33
+	 * @v av		Source address vector
34
+	 * @ret rc		Return status code
35
+	 */
36
+	void ( * handle ) ( struct ib_device *ibdev,
37
+			    struct ib_mad_interface *mi,
38
+			    union ib_mad *mad,
39
+			    struct ib_address_vector *av );
40
+};
41
+
42
+/** Infiniband management agents */
43
+#define IB_MAD_AGENTS __table ( struct ib_mad_agent, "ib_mad_agents" )
44
+
45
+/** Declare an Infiniband management agent */
46
+#define __ib_mad_agent __table_entry ( IB_MAD_AGENTS, 01 )
47
+
48
+/** Infiniband management transaction operations */
49
+struct ib_mad_transaction_operations {
50
+	/** Handle transaction completion
51
+	 *
52
+	 * @v ibdev		Infiniband device
53
+	 * @v mi		Management interface
54
+	 * @v madx		Management transaction
55
+	 * @v rc		Status code
56
+	 * @v mad		Received MAD (or NULL on error)
57
+	 * @v av		Source address vector (or NULL on error)
58
+	 *
59
+	 * The completion handler should in most cases call
60
+	 * ib_destroy_madx() to free up the completed transaction.
61
+	 */
62
+	void ( * complete ) ( struct ib_device *ibdev,
63
+			      struct ib_mad_interface *mi,
64
+			      struct ib_mad_transaction *madx,
65
+			      int rc, union ib_mad *mad,
66
+			      struct ib_address_vector *av );
67
+};
68
+
69
+/** An Infiniband management transaction */
70
+struct ib_mad_transaction {
71
+	/** Associated management interface */
72
+	struct ib_mad_interface *mi;
73
+	/** List of transactions */
74
+	struct list_head list;
75
+	/** Retry timer */
76
+	struct retry_timer timer;
77
+	/** Destination address vector */
78
+	struct ib_address_vector av;
79
+	/** MAD being sent */
80
+	union ib_mad mad;
81
+	/** Transaction operations */
82
+	struct ib_mad_transaction_operations *op;
83
+	/** Owner private data */
84
+	void *owner_priv;
85
+};
86
+
87
+/** An Infiniband management interface */
88
+struct ib_mad_interface {
89
+	/** Infiniband device */
90
+	struct ib_device *ibdev;
91
+	/** Completion queue */
92
+	struct ib_completion_queue *cq;
93
+	/** Queue pair */
94
+	struct ib_queue_pair *qp;
95
+	/** List of management transactions */
96
+	struct list_head madx;
97
+};
98
+
99
+/**
100
+ * Set Infiniband management transaction owner-private data
101
+ *
102
+ * @v madx		Management transaction
103
+ * @v priv		Private data
104
+ */
105
+static inline __always_inline void
106
+ib_madx_set_ownerdata ( struct ib_mad_transaction *madx, void *priv ) {
107
+	madx->owner_priv = priv;
108
+}
109
+
110
+/**
111
+ * Get Infiniband management transaction owner-private data
112
+ *
113
+ * @v madx		Management transaction
114
+ * @ret priv		Private data
115
+ */
116
+static inline __always_inline void *
117
+ib_madx_get_ownerdata ( struct ib_mad_transaction *madx ) {
118
+	return madx->owner_priv;
119
+}
120
+
121
+extern int ib_mi_send ( struct ib_device *ibdev, struct ib_mad_interface *mi,
122
+			union ib_mad *mad, struct ib_address_vector *av );
123
+extern struct ib_mad_transaction *
124
+ib_create_madx ( struct ib_device *ibdev, struct ib_mad_interface *mi,
125
+		 union ib_mad *mad, struct ib_address_vector *av,
126
+		 struct ib_mad_transaction_operations *op );
127
+extern void ib_destroy_madx ( struct ib_device *ibdev,
128
+			      struct ib_mad_interface *mi,
129
+			      struct ib_mad_transaction *madx );
130
+extern struct ib_mad_interface * ib_create_mi ( struct ib_device *ibdev,
131
+						enum ib_queue_pair_type type );
132
+extern void ib_destroy_mi ( struct ib_device *ibdev,
133
+			    struct ib_mad_interface *mi );
134
+
135
+#endif /* _GPXE_IB_MI_H */

+ 410
- 0
src/net/infiniband/ib_mi.c Zobrazit soubor

@@ -0,0 +1,410 @@
1
+/*
2
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+FILE_LICENCE ( GPL2_OR_LATER );
20
+
21
+#include <stdint.h>
22
+#include <stdlib.h>
23
+#include <string.h>
24
+#include <errno.h>
25
+#include <stdio.h>
26
+#include <unistd.h>
27
+#include <byteswap.h>
28
+#include <gpxe/infiniband.h>
29
+#include <gpxe/iobuf.h>
30
+#include <gpxe/ib_mi.h>
31
+
32
+/**
33
+ * @file
34
+ *
35
+ * Infiniband management interfaces
36
+ *
37
+ */
38
+
39
+/** Management interface number of send WQEs
40
+ *
41
+ * This is a policy decision.
42
+ */
43
+#define IB_MI_NUM_SEND_WQES 4
44
+
45
+/** Management interface number of receive WQEs
46
+ *
47
+ * This is a policy decision.
48
+ */
49
+#define IB_MI_NUM_RECV_WQES 2
50
+
51
+/** Management interface number of completion queue entries
52
+ *
53
+ * This is a policy decision
54
+ */
55
+#define IB_MI_NUM_CQES 8
56
+
57
+/** TID magic signature */
58
+#define IB_MI_TID_MAGIC ( ( 'g' << 24 ) | ( 'P' << 16 ) | ( 'X' << 8 ) | 'E' )
59
+
60
+/** TID to use for next MAD */
61
+static unsigned int next_tid;
62
+
63
+/**
64
+ * Handle received MAD
65
+ *
66
+ * @v ibdev		Infiniband device
67
+ * @v mi		Management interface
68
+ * @v mad		Received MAD
69
+ * @v av		Source address vector
70
+ * @ret rc		Return status code
71
+ */
72
+static int ib_mi_handle ( struct ib_device *ibdev,
73
+			  struct ib_mad_interface *mi,
74
+			  union ib_mad *mad,
75
+			  struct ib_address_vector *av ) {
76
+	struct ib_mad_hdr *hdr = &mad->hdr;
77
+	struct ib_mad_transaction *madx;
78
+	struct ib_mad_agent *agent;
79
+	int rc;
80
+
81
+	/* Look for a matching transaction by TID */
82
+	list_for_each_entry ( madx, &mi->madx, list ) {
83
+		if ( memcmp ( &hdr->tid, &madx->mad.hdr.tid,
84
+			      sizeof ( hdr->tid ) ) != 0 )
85
+			continue;
86
+		/* Get transaction result status */
87
+		rc = ( ( hdr->status == htons ( IB_MGMT_STATUS_OK ) ) ?
88
+		       0 : -EIO );
89
+		/* Found a matching transaction */
90
+		madx->op->complete ( ibdev, mi, madx, rc, mad, av );
91
+		return 0;
92
+	}
93
+
94
+	/* If there is no matching transaction, look for a listening agent */
95
+	for_each_table_entry ( agent, IB_MAD_AGENTS ) {
96
+		if ( ( ( agent->mgmt_class & IB_MGMT_CLASS_MASK ) !=
97
+		       ( hdr->mgmt_class & IB_MGMT_CLASS_MASK ) ) ||
98
+		     ( agent->class_version != hdr->class_version ) ||
99
+		     ( agent->attr_id != hdr->attr_id ) )
100
+			continue;
101
+		/* Found a matching agent */
102
+		agent->handle ( ibdev, mi, mad, av );
103
+		return 0;
104
+	}
105
+
106
+	/* Otherwise, ignore it */
107
+	DBGC ( mi, "MI %p RX TID %08x%08x ignored\n",
108
+	       mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ) );
109
+	return -ENOTSUP;
110
+}
111
+
112
+/**
113
+ * Complete receive via management interface
114
+ *
115
+ *
116
+ * @v ibdev		Infiniband device
117
+ * @v qp		Queue pair
118
+ * @v av		Address vector
119
+ * @v iobuf		I/O buffer
120
+ * @v rc		Completion status code
121
+ */
122
+static void ib_mi_complete_recv ( struct ib_device *ibdev,
123
+				  struct ib_queue_pair *qp,
124
+				  struct ib_address_vector *av,
125
+				  struct io_buffer *iobuf, int rc ) {
126
+	struct ib_mad_interface *mi = ib_qp_get_ownerdata ( qp );
127
+	union ib_mad *mad;
128
+	struct ib_mad_hdr *hdr;
129
+
130
+	/* Ignore errors */
131
+	if ( rc != 0 ) {
132
+		DBGC ( mi, "MI %p RX error: %s\n", mi, strerror ( rc ) );
133
+		goto out;
134
+	}
135
+
136
+	/* Sanity checks */
137
+	if ( iob_len ( iobuf ) != sizeof ( *mad ) ) {
138
+		DBGC ( mi, "MI %p RX bad size (%zd bytes)\n",
139
+		       mi, iob_len ( iobuf ) );
140
+		DBGC_HDA ( mi, 0, iobuf->data, iob_len ( iobuf ) );
141
+		goto out;
142
+	}
143
+	mad = iobuf->data;
144
+	hdr = &mad->hdr;
145
+	if ( hdr->base_version != IB_MGMT_BASE_VERSION ) {
146
+		DBGC ( mi, "MI %p RX unsupported base version %x\n",
147
+		       mi, hdr->base_version );
148
+		DBGC_HDA ( mi, 0, mad, sizeof ( *mad ) );
149
+		goto out;
150
+	}
151
+	DBGC ( mi, "MI %p RX TID %08x%08x (%02x,%02x,%02x,%04x) status "
152
+	       "%04x\n", mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
153
+	       hdr->mgmt_class, hdr->class_version, hdr->method,
154
+	       ntohs ( hdr->attr_id ), ntohs ( hdr->status ) );
155
+	DBGC2_HDA ( mi, 0, mad, sizeof ( *mad ) );
156
+
157
+	/* Handle MAD */
158
+	if ( ( rc = ib_mi_handle ( ibdev, mi, mad, av ) ) != 0 )
159
+		goto out;
160
+
161
+ out:
162
+	free_iob ( iobuf );
163
+}
164
+
165
+/** Management interface completion operations */
166
+static struct ib_completion_queue_operations ib_mi_completion_ops = {
167
+	.complete_recv = ib_mi_complete_recv,
168
+};
169
+
170
+/**
171
+ * Transmit MAD
172
+ *
173
+ * @v ibdev		Infiniband device
174
+ * @v mi		Management interface
175
+ * @v mad		MAD
176
+ * @v av		Destination address vector
177
+ * @ret rc		Return status code
178
+ */
179
+int ib_mi_send ( struct ib_device *ibdev, struct ib_mad_interface *mi,
180
+		 union ib_mad *mad, struct ib_address_vector *av ) {
181
+	struct ib_mad_hdr *hdr = &mad->hdr;
182
+	struct io_buffer *iobuf;
183
+	int rc;
184
+
185
+	/* Set common fields */
186
+	hdr->base_version = IB_MGMT_BASE_VERSION;
187
+	if ( ( hdr->tid[0] == 0 ) && ( hdr->tid[1] == 0 ) ) {
188
+		hdr->tid[0] = htonl ( IB_MI_TID_MAGIC );
189
+		hdr->tid[1] = htonl ( ++next_tid );
190
+	}
191
+	DBGC ( mi, "MI %p TX TID %08x%08x (%02x,%02x,%02x,%04x) status "
192
+	       "%04x\n", mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
193
+	       hdr->mgmt_class, hdr->class_version, hdr->method,
194
+	       ntohs ( hdr->attr_id ), ntohs ( hdr->status ) );
195
+	DBGC2_HDA ( mi, 0, mad, sizeof ( *mad ) );
196
+
197
+	/* Construct directed route portion of response, if necessary */
198
+	if ( hdr->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) {
199
+		struct ib_mad_smp *smp = &mad->smp;
200
+		unsigned int hop_pointer;
201
+		unsigned int hop_count;
202
+
203
+		smp->mad_hdr.status |= htons ( IB_SMP_STATUS_D_INBOUND );
204
+		hop_pointer = smp->mad_hdr.class_specific.smp.hop_pointer;
205
+		hop_count = smp->mad_hdr.class_specific.smp.hop_count;
206
+		assert ( hop_count == hop_pointer );
207
+		if ( hop_pointer < ( sizeof ( smp->return_path.hops ) /
208
+				     sizeof ( smp->return_path.hops[0] ) ) ) {
209
+			smp->return_path.hops[hop_pointer] = ibdev->port;
210
+		} else {
211
+			DBGC ( mi, "MI %p TX TID %08x%08x invalid hop pointer "
212
+			       "%d\n", mi, ntohl ( hdr->tid[0] ),
213
+			       ntohl ( hdr->tid[1] ), hop_pointer );
214
+			return -EINVAL;
215
+		}
216
+	}
217
+
218
+	/* Construct I/O buffer */
219
+	iobuf = alloc_iob ( sizeof ( *mad ) );
220
+	if ( ! iobuf ) {
221
+		DBGC ( mi, "MI %p could not allocate buffer for TID "
222
+		       "%08x%08x\n",
223
+		       mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ) );
224
+		return -ENOMEM;
225
+	}
226
+	memcpy ( iob_put ( iobuf, sizeof ( *mad ) ), mad, sizeof ( *mad ) );
227
+
228
+	/* Send I/O buffer */
229
+	if ( ( rc = ib_post_send ( ibdev, mi->qp, av, iobuf ) ) != 0 ) {
230
+		DBGC ( mi, "MI %p TX TID %08x%08x failed: %s\n",
231
+		       mi,  ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
232
+		       strerror ( rc ) );
233
+		free_iob ( iobuf );
234
+		return rc;
235
+	}
236
+
237
+	return 0;
238
+}
239
+
240
+/**
241
+ * Handle management transaction timer expiry
242
+ *
243
+ * @v timer		Retry timer
244
+ * @v expired		Failure indicator
245
+ */
246
+static void ib_mi_timer_expired ( struct retry_timer *timer, int expired ) {
247
+	struct ib_mad_transaction *madx =
248
+		container_of ( timer, struct ib_mad_transaction, timer );
249
+	struct ib_mad_interface *mi = madx->mi;
250
+	struct ib_device *ibdev = mi->ibdev;
251
+	struct ib_mad_hdr *hdr = &madx->mad.hdr;
252
+
253
+	/* Abandon transaction if we have tried too many times */
254
+	if ( expired ) {
255
+		DBGC ( mi, "MI %p abandoning TID %08x%08x\n",
256
+		       mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ) );
257
+		madx->op->complete ( ibdev, mi, madx, -ETIMEDOUT, NULL, NULL );
258
+		return;
259
+	}
260
+
261
+	/* Restart retransmission timer */
262
+	start_timer ( timer );
263
+
264
+	/* Resend MAD */
265
+	ib_mi_send ( ibdev, mi, &madx->mad, &madx->av );
266
+}
267
+
268
+/**
269
+ * Create management transaction
270
+ *
271
+ * @v ibdev		Infiniband device
272
+ * @v mi		Management interface
273
+ * @v mad		MAD to send
274
+ * @v av		Destination address, or NULL to use SM's GSI
275
+ * @v op		Management transaction operations
276
+ * @ret madx		Management transaction, or NULL
277
+ */
278
+struct ib_mad_transaction *
279
+ib_create_madx ( struct ib_device *ibdev, struct ib_mad_interface *mi,
280
+		 union ib_mad *mad, struct ib_address_vector *av,
281
+		 struct ib_mad_transaction_operations *op ) {
282
+	struct ib_mad_transaction *madx;
283
+
284
+	/* Allocate and initialise structure */
285
+	madx = zalloc ( sizeof ( *madx ) );
286
+	if ( ! madx )
287
+		return NULL;
288
+	madx->mi = mi;
289
+	madx->timer.expired = ib_mi_timer_expired;
290
+	madx->op = op;
291
+
292
+	/* Determine address vector */
293
+	if ( av ) {
294
+		memcpy ( &madx->av, av, sizeof ( madx->av ) );
295
+	} else {
296
+		madx->av.lid = ibdev->sm_lid;
297
+		madx->av.sl = ibdev->sm_sl;
298
+		madx->av.qpn = IB_QPN_GSI;
299
+		madx->av.qkey = IB_QKEY_GSI;
300
+	}
301
+
302
+	/* Copy MAD */
303
+	memcpy ( &madx->mad, mad, sizeof ( madx->mad ) );
304
+
305
+	/* Add to list and start timer to send initial MAD */
306
+	list_add ( &madx->list, &mi->madx );
307
+	start_timer_nodelay ( &madx->timer );
308
+
309
+	return madx;
310
+}
311
+
312
+/**
313
+ * Destroy management transaction
314
+ *
315
+ * @v ibdev		Infiniband device
316
+ * @v mi		Management interface
317
+ * @v madx		Management transaction
318
+ */
319
+void ib_destroy_madx ( struct ib_device *ibdev __unused,
320
+		       struct ib_mad_interface *mi __unused,
321
+		       struct ib_mad_transaction *madx ) {
322
+
323
+	/* Stop timer and remove from list */
324
+	stop_timer ( &madx->timer );
325
+	list_del ( &madx->list );
326
+
327
+	/* Free transaction */
328
+	free ( madx );
329
+}
330
+
331
+/**
332
+ * Create management interface
333
+ *
334
+ * @v ibdev		Infiniband device
335
+ * @v type		Queue pair type
336
+ * @ret mi		Management agent, or NULL
337
+ */
338
+struct ib_mad_interface * ib_create_mi ( struct ib_device *ibdev,
339
+					 enum ib_queue_pair_type type ) {
340
+	struct ib_mad_interface *mi;
341
+	int rc;
342
+
343
+	/* Allocate and initialise fields */
344
+	mi = zalloc ( sizeof ( *mi ) );
345
+	if ( ! mi )
346
+		goto err_alloc;
347
+	mi->ibdev = ibdev;
348
+	INIT_LIST_HEAD ( &mi->madx );
349
+
350
+	/* Create completion queue */
351
+	mi->cq = ib_create_cq ( ibdev, IB_MI_NUM_CQES, &ib_mi_completion_ops );
352
+	if ( ! mi->cq ) {
353
+		DBGC ( mi, "MI %p could not allocate completion queue\n", mi );
354
+		goto err_create_cq;
355
+	}
356
+
357
+	/* Create queue pair */
358
+	mi->qp = ib_create_qp ( ibdev, type, IB_MI_NUM_SEND_WQES, mi->cq,
359
+				IB_MI_NUM_RECV_WQES, mi->cq );
360
+	if ( ! mi->qp ) {
361
+		DBGC ( mi, "MI %p could not allocate queue pair\n", mi );
362
+		goto err_create_qp;
363
+	}
364
+	ib_qp_set_ownerdata ( mi->qp, mi );
365
+	DBGC ( mi, "MI %p (%s) running on QPN %#lx\n",
366
+	       mi, ( ( type == IB_QPT_SMI ) ? "SMI" : "GSI" ), mi->qp->qpn );
367
+
368
+	/* Set queue key */
369
+	mi->qp->qkey = ( ( type == IB_QPT_SMI ) ? IB_QKEY_SMI : IB_QKEY_GSI );
370
+	if ( ( rc = ib_modify_qp ( ibdev, mi->qp ) ) != 0 ) {
371
+		DBGC ( mi, "MI %p could not set queue key: %s\n",
372
+		       mi, strerror ( rc ) );
373
+		goto err_modify_qp;
374
+	}
375
+
376
+	/* Fill receive ring */
377
+	ib_refill_recv ( ibdev, mi->qp );
378
+	return mi;
379
+
380
+ err_modify_qp:
381
+	ib_destroy_qp ( ibdev, mi->qp );
382
+ err_create_qp:
383
+	ib_destroy_cq ( ibdev, mi->cq );
384
+ err_create_cq:
385
+	free ( mi );
386
+ err_alloc:
387
+	return NULL;
388
+}
389
+
390
+/**
391
+ * Destroy management interface
392
+ *
393
+ * @v mi		Management interface
394
+ */
395
+void ib_destroy_mi ( struct ib_device *ibdev, struct ib_mad_interface *mi ) {
396
+	struct ib_mad_transaction *madx;
397
+	struct ib_mad_transaction *tmp;
398
+
399
+	/* Flush any outstanding requests */
400
+	list_for_each_entry_safe ( madx, tmp, &mi->madx, list ) {
401
+		DBGC ( mi, "MI %p destroyed while TID %08x%08x in progress\n",
402
+		       mi, ntohl ( madx->mad.hdr.tid[0] ),
403
+		       ntohl ( madx->mad.hdr.tid[1] ) );
404
+		madx->op->complete ( ibdev, mi, madx, -ECANCELED, NULL, NULL );
405
+	}
406
+
407
+	ib_destroy_qp ( ibdev, mi->qp );
408
+	ib_destroy_cq ( ibdev, mi->cq );
409
+	free ( mi );
410
+}

Načítá se…
Zrušit
Uložit