xref: /spdk/lib/rdma_provider/rdma_provider_verbs.c (revision d1c46ed8e5f61500a9ef69d922f8d3f89a4e9cb3)
1cf151d60SAlexey Marchuk /*   SPDX-License-Identifier: BSD-3-Clause
2cf151d60SAlexey Marchuk  *   Copyright (C) 2020 Intel Corporation. All rights reserved.
3cf151d60SAlexey Marchuk  *   Copyright (c) Mellanox Technologies LTD. All rights reserved.
4cf151d60SAlexey Marchuk  *   Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5cf151d60SAlexey Marchuk  */
6cf151d60SAlexey Marchuk 
7cf151d60SAlexey Marchuk #include <rdma/rdma_cma.h>
8cf151d60SAlexey Marchuk 
9cf151d60SAlexey Marchuk #include "spdk/stdinc.h"
10cf151d60SAlexey Marchuk #include "spdk/string.h"
11cf151d60SAlexey Marchuk #include "spdk/likely.h"
12cf151d60SAlexey Marchuk 
13cf151d60SAlexey Marchuk #include "spdk_internal/rdma_provider.h"
141794c395SAlexey Marchuk #include "spdk_internal/rdma_utils.h"
15cf151d60SAlexey Marchuk #include "spdk/log.h"
16cf151d60SAlexey Marchuk 
17cf151d60SAlexey Marchuk struct spdk_rdma_provider_qp *
18cf151d60SAlexey Marchuk spdk_rdma_provider_qp_create(struct rdma_cm_id *cm_id,
19cf151d60SAlexey Marchuk 			     struct spdk_rdma_provider_qp_init_attr *qp_attr)
20cf151d60SAlexey Marchuk {
21cf151d60SAlexey Marchuk 	struct spdk_rdma_provider_qp *spdk_rdma_qp;
22cf151d60SAlexey Marchuk 	int rc;
23cf151d60SAlexey Marchuk 	struct ibv_qp_init_attr attr = {
24cf151d60SAlexey Marchuk 		.qp_context = qp_attr->qp_context,
25cf151d60SAlexey Marchuk 		.send_cq = qp_attr->send_cq,
26cf151d60SAlexey Marchuk 		.recv_cq = qp_attr->recv_cq,
27cf151d60SAlexey Marchuk 		.srq = qp_attr->srq,
28cf151d60SAlexey Marchuk 		.cap = qp_attr->cap,
29cf151d60SAlexey Marchuk 		.qp_type = IBV_QPT_RC
30cf151d60SAlexey Marchuk 	};
31cf151d60SAlexey Marchuk 
3207416b7eSAlexey Marchuk 	if (qp_attr->domain_transfer) {
3307416b7eSAlexey Marchuk 		SPDK_ERRLOG("verbs provider doesn't support memory domain transfer functionality");
3407416b7eSAlexey Marchuk 		return NULL;
3507416b7eSAlexey Marchuk 	}
3607416b7eSAlexey Marchuk 
37cf151d60SAlexey Marchuk 	spdk_rdma_qp = calloc(1, sizeof(*spdk_rdma_qp));
38cf151d60SAlexey Marchuk 	if (!spdk_rdma_qp) {
39cf151d60SAlexey Marchuk 		SPDK_ERRLOG("qp memory allocation failed\n");
40cf151d60SAlexey Marchuk 		return NULL;
41cf151d60SAlexey Marchuk 	}
42cf151d60SAlexey Marchuk 
43cf151d60SAlexey Marchuk 	if (qp_attr->stats) {
44cf151d60SAlexey Marchuk 		spdk_rdma_qp->stats = qp_attr->stats;
45cf151d60SAlexey Marchuk 		spdk_rdma_qp->shared_stats = true;
46cf151d60SAlexey Marchuk 	} else {
47cf151d60SAlexey Marchuk 		spdk_rdma_qp->stats = calloc(1, sizeof(*spdk_rdma_qp->stats));
48cf151d60SAlexey Marchuk 		if (!spdk_rdma_qp->stats) {
49cf151d60SAlexey Marchuk 			SPDK_ERRLOG("qp statistics memory allocation failed\n");
50cf151d60SAlexey Marchuk 			free(spdk_rdma_qp);
51cf151d60SAlexey Marchuk 			return NULL;
52cf151d60SAlexey Marchuk 		}
53cf151d60SAlexey Marchuk 	}
54cf151d60SAlexey Marchuk 
55cf151d60SAlexey Marchuk 	rc = rdma_create_qp(cm_id, qp_attr->pd, &attr);
56cf151d60SAlexey Marchuk 	if (rc) {
57cf151d60SAlexey Marchuk 		SPDK_ERRLOG("Failed to create qp, rc %d, errno %s (%d)\n", rc, spdk_strerror(errno), errno);
58cf151d60SAlexey Marchuk 		free(spdk_rdma_qp);
59cf151d60SAlexey Marchuk 		return NULL;
60cf151d60SAlexey Marchuk 	}
61cf151d60SAlexey Marchuk 	spdk_rdma_qp->qp = cm_id->qp;
62cf151d60SAlexey Marchuk 	spdk_rdma_qp->cm_id = cm_id;
631794c395SAlexey Marchuk 	spdk_rdma_qp->domain = spdk_rdma_utils_get_memory_domain(qp_attr->pd);
641794c395SAlexey Marchuk 	if (!spdk_rdma_qp->domain) {
651794c395SAlexey Marchuk 		spdk_rdma_provider_qp_destroy(spdk_rdma_qp);
661794c395SAlexey Marchuk 		return NULL;
671794c395SAlexey Marchuk 	}
681794c395SAlexey Marchuk 
691794c395SAlexey Marchuk 	qp_attr->cap = attr.cap;
70cf151d60SAlexey Marchuk 
71cf151d60SAlexey Marchuk 	return spdk_rdma_qp;
72cf151d60SAlexey Marchuk }
73cf151d60SAlexey Marchuk 
74cf151d60SAlexey Marchuk int
75cf151d60SAlexey Marchuk spdk_rdma_provider_qp_accept(struct spdk_rdma_provider_qp *spdk_rdma_qp,
76cf151d60SAlexey Marchuk 			     struct rdma_conn_param *conn_param)
77cf151d60SAlexey Marchuk {
78cf151d60SAlexey Marchuk 	assert(spdk_rdma_qp != NULL);
79cf151d60SAlexey Marchuk 	assert(spdk_rdma_qp->cm_id != NULL);
80cf151d60SAlexey Marchuk 
81cf151d60SAlexey Marchuk 	return rdma_accept(spdk_rdma_qp->cm_id, conn_param);
82cf151d60SAlexey Marchuk }
83cf151d60SAlexey Marchuk 
84cf151d60SAlexey Marchuk int
85cf151d60SAlexey Marchuk spdk_rdma_provider_qp_complete_connect(struct spdk_rdma_provider_qp *spdk_rdma_qp)
86cf151d60SAlexey Marchuk {
87cf151d60SAlexey Marchuk 	/* Nothing to be done for Verbs */
88cf151d60SAlexey Marchuk 	return 0;
89cf151d60SAlexey Marchuk }
90cf151d60SAlexey Marchuk 
91cf151d60SAlexey Marchuk void
92cf151d60SAlexey Marchuk spdk_rdma_provider_qp_destroy(struct spdk_rdma_provider_qp *spdk_rdma_qp)
93cf151d60SAlexey Marchuk {
94cf151d60SAlexey Marchuk 	assert(spdk_rdma_qp != NULL);
95cf151d60SAlexey Marchuk 
96cf151d60SAlexey Marchuk 	if (spdk_rdma_qp->send_wrs.first != NULL) {
97cf151d60SAlexey Marchuk 		SPDK_WARNLOG("Destroying qpair with queued Work Requests\n");
98cf151d60SAlexey Marchuk 	}
99cf151d60SAlexey Marchuk 
100cf151d60SAlexey Marchuk 	if (spdk_rdma_qp->qp) {
101cf151d60SAlexey Marchuk 		rdma_destroy_qp(spdk_rdma_qp->cm_id);
102cf151d60SAlexey Marchuk 	}
103cf151d60SAlexey Marchuk 
104cf151d60SAlexey Marchuk 	if (!spdk_rdma_qp->shared_stats) {
105cf151d60SAlexey Marchuk 		free(spdk_rdma_qp->stats);
106cf151d60SAlexey Marchuk 	}
1071794c395SAlexey Marchuk 	if (spdk_rdma_qp->domain) {
1081794c395SAlexey Marchuk 		spdk_rdma_utils_put_memory_domain(spdk_rdma_qp->domain);
1091794c395SAlexey Marchuk 	}
110cf151d60SAlexey Marchuk 
111cf151d60SAlexey Marchuk 	free(spdk_rdma_qp);
112cf151d60SAlexey Marchuk }
113cf151d60SAlexey Marchuk 
114cf151d60SAlexey Marchuk int
115cf151d60SAlexey Marchuk spdk_rdma_provider_qp_disconnect(struct spdk_rdma_provider_qp *spdk_rdma_qp)
116cf151d60SAlexey Marchuk {
117cf151d60SAlexey Marchuk 	int rc = 0;
118cf151d60SAlexey Marchuk 
119cf151d60SAlexey Marchuk 	assert(spdk_rdma_qp != NULL);
120cf151d60SAlexey Marchuk 
121cf151d60SAlexey Marchuk 	if (spdk_rdma_qp->cm_id) {
122cf151d60SAlexey Marchuk 		rc = rdma_disconnect(spdk_rdma_qp->cm_id);
123cf151d60SAlexey Marchuk 		if (rc) {
124cf151d60SAlexey Marchuk 			if (errno == EINVAL && spdk_rdma_qp->qp->context->device->transport_type == IBV_TRANSPORT_IWARP) {
125cf151d60SAlexey Marchuk 				/* rdma_disconnect may return an error and set errno to EINVAL in case of iWARP.
126cf151d60SAlexey Marchuk 				 * This behaviour is expected since iWARP handles disconnect event other than IB and
127cf151d60SAlexey Marchuk 				 * qpair is already in error state when we call rdma_disconnect */
128cf151d60SAlexey Marchuk 				return 0;
129cf151d60SAlexey Marchuk 			}
130cf151d60SAlexey Marchuk 			SPDK_ERRLOG("rdma_disconnect failed, errno %s (%d)\n", spdk_strerror(errno), errno);
131cf151d60SAlexey Marchuk 		}
132cf151d60SAlexey Marchuk 	}
133cf151d60SAlexey Marchuk 
134cf151d60SAlexey Marchuk 	return rc;
135cf151d60SAlexey Marchuk }
136cf151d60SAlexey Marchuk 
137cf151d60SAlexey Marchuk bool
138cf151d60SAlexey Marchuk spdk_rdma_provider_qp_queue_send_wrs(struct spdk_rdma_provider_qp *spdk_rdma_qp,
139cf151d60SAlexey Marchuk 				     struct ibv_send_wr *first)
140cf151d60SAlexey Marchuk {
141cf151d60SAlexey Marchuk 	struct ibv_send_wr *last;
142cf151d60SAlexey Marchuk 
143cf151d60SAlexey Marchuk 	assert(spdk_rdma_qp);
144cf151d60SAlexey Marchuk 	assert(first);
145cf151d60SAlexey Marchuk 
146cf151d60SAlexey Marchuk 	spdk_rdma_qp->stats->send.num_submitted_wrs++;
147cf151d60SAlexey Marchuk 	last = first;
148cf151d60SAlexey Marchuk 	while (last->next != NULL) {
149cf151d60SAlexey Marchuk 		last = last->next;
150cf151d60SAlexey Marchuk 		spdk_rdma_qp->stats->send.num_submitted_wrs++;
151cf151d60SAlexey Marchuk 	}
152cf151d60SAlexey Marchuk 
153cf151d60SAlexey Marchuk 	if (spdk_rdma_qp->send_wrs.first == NULL) {
154cf151d60SAlexey Marchuk 		spdk_rdma_qp->send_wrs.first = first;
155cf151d60SAlexey Marchuk 		spdk_rdma_qp->send_wrs.last = last;
156cf151d60SAlexey Marchuk 		return true;
157cf151d60SAlexey Marchuk 	} else {
158cf151d60SAlexey Marchuk 		spdk_rdma_qp->send_wrs.last->next = first;
159cf151d60SAlexey Marchuk 		spdk_rdma_qp->send_wrs.last = last;
160cf151d60SAlexey Marchuk 		return false;
161cf151d60SAlexey Marchuk 	}
162cf151d60SAlexey Marchuk }
163cf151d60SAlexey Marchuk 
164cf151d60SAlexey Marchuk int
165cf151d60SAlexey Marchuk spdk_rdma_provider_qp_flush_send_wrs(struct spdk_rdma_provider_qp *spdk_rdma_qp,
166cf151d60SAlexey Marchuk 				     struct ibv_send_wr **bad_wr)
167cf151d60SAlexey Marchuk {
168cf151d60SAlexey Marchuk 	int rc;
169cf151d60SAlexey Marchuk 
170cf151d60SAlexey Marchuk 	assert(spdk_rdma_qp);
171cf151d60SAlexey Marchuk 	assert(bad_wr);
172cf151d60SAlexey Marchuk 
173cf151d60SAlexey Marchuk 	if (spdk_unlikely(!spdk_rdma_qp->send_wrs.first)) {
174cf151d60SAlexey Marchuk 		return 0;
175cf151d60SAlexey Marchuk 	}
176cf151d60SAlexey Marchuk 
177cf151d60SAlexey Marchuk 	rc = ibv_post_send(spdk_rdma_qp->qp, spdk_rdma_qp->send_wrs.first, bad_wr);
178cf151d60SAlexey Marchuk 
179cf151d60SAlexey Marchuk 	spdk_rdma_qp->send_wrs.first = NULL;
180cf151d60SAlexey Marchuk 	spdk_rdma_qp->stats->send.doorbell_updates++;
181cf151d60SAlexey Marchuk 
182cf151d60SAlexey Marchuk 	return rc;
183cf151d60SAlexey Marchuk }
184*d1c46ed8SAlexey Marchuk 
185*d1c46ed8SAlexey Marchuk bool
186*d1c46ed8SAlexey Marchuk spdk_rdma_provider_accel_sequence_supported(void)
187*d1c46ed8SAlexey Marchuk {
188*d1c46ed8SAlexey Marchuk 	return false;
189*d1c46ed8SAlexey Marchuk }
190