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