Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause 2 : * Copyright (C) 2020 Intel Corporation. All rights reserved. 3 : * Copyright (c) Mellanox Technologies LTD. All rights reserved. 4 : */ 5 : 6 : #include <rdma/rdma_cma.h> 7 : 8 : #include "spdk/stdinc.h" 9 : #include "spdk/string.h" 10 : #include "spdk/likely.h" 11 : 12 : #include "spdk_internal/rdma.h" 13 : #include "spdk/log.h" 14 : 15 : struct spdk_rdma_qp * 16 0 : spdk_rdma_qp_create(struct rdma_cm_id *cm_id, struct spdk_rdma_qp_init_attr *qp_attr) 17 : { 18 : struct spdk_rdma_qp *spdk_rdma_qp; 19 : int rc; 20 0 : struct ibv_qp_init_attr attr = { 21 0 : .qp_context = qp_attr->qp_context, 22 0 : .send_cq = qp_attr->send_cq, 23 0 : .recv_cq = qp_attr->recv_cq, 24 0 : .srq = qp_attr->srq, 25 : .cap = qp_attr->cap, 26 : .qp_type = IBV_QPT_RC 27 : }; 28 : 29 0 : spdk_rdma_qp = calloc(1, sizeof(*spdk_rdma_qp)); 30 0 : if (!spdk_rdma_qp) { 31 0 : SPDK_ERRLOG("qp memory allocation failed\n"); 32 0 : return NULL; 33 : } 34 : 35 0 : if (qp_attr->stats) { 36 0 : spdk_rdma_qp->stats = qp_attr->stats; 37 0 : spdk_rdma_qp->shared_stats = true; 38 : } else { 39 0 : spdk_rdma_qp->stats = calloc(1, sizeof(*spdk_rdma_qp->stats)); 40 0 : if (!spdk_rdma_qp->stats) { 41 0 : SPDK_ERRLOG("qp statistics memory allocation failed\n"); 42 0 : free(spdk_rdma_qp); 43 0 : return NULL; 44 : } 45 : } 46 : 47 0 : rc = rdma_create_qp(cm_id, qp_attr->pd, &attr); 48 0 : if (rc) { 49 0 : SPDK_ERRLOG("Failed to create qp, errno %s (%d)\n", spdk_strerror(errno), errno); 50 0 : free(spdk_rdma_qp); 51 0 : return NULL; 52 : } 53 : 54 0 : qp_attr->cap = attr.cap; 55 0 : spdk_rdma_qp->qp = cm_id->qp; 56 0 : spdk_rdma_qp->cm_id = cm_id; 57 : 58 0 : return spdk_rdma_qp; 59 : } 60 : 61 : int 62 0 : spdk_rdma_qp_accept(struct spdk_rdma_qp *spdk_rdma_qp, struct rdma_conn_param *conn_param) 63 : { 64 0 : assert(spdk_rdma_qp != NULL); 65 0 : assert(spdk_rdma_qp->cm_id != NULL); 66 : 67 0 : return rdma_accept(spdk_rdma_qp->cm_id, conn_param); 68 : } 69 : 70 : int 71 0 : spdk_rdma_qp_complete_connect(struct spdk_rdma_qp *spdk_rdma_qp) 72 : { 73 : /* Nothing to be done for Verbs */ 74 0 : return 0; 75 : } 76 : 77 : void 78 0 : spdk_rdma_qp_destroy(struct spdk_rdma_qp *spdk_rdma_qp) 79 : { 80 0 : assert(spdk_rdma_qp != NULL); 81 : 82 0 : if (spdk_rdma_qp->send_wrs.first != NULL) { 83 0 : SPDK_WARNLOG("Destroying qpair with queued Work Requests\n"); 84 : } 85 : 86 0 : if (spdk_rdma_qp->qp) { 87 0 : rdma_destroy_qp(spdk_rdma_qp->cm_id); 88 : } 89 : 90 0 : if (!spdk_rdma_qp->shared_stats) { 91 0 : free(spdk_rdma_qp->stats); 92 : } 93 : 94 0 : free(spdk_rdma_qp); 95 0 : } 96 : 97 : int 98 0 : spdk_rdma_qp_disconnect(struct spdk_rdma_qp *spdk_rdma_qp) 99 : { 100 0 : int rc = 0; 101 : 102 0 : assert(spdk_rdma_qp != NULL); 103 : 104 0 : if (spdk_rdma_qp->cm_id) { 105 0 : rc = rdma_disconnect(spdk_rdma_qp->cm_id); 106 0 : if (rc) { 107 0 : if (errno == EINVAL && spdk_rdma_qp->qp->context->device->transport_type == IBV_TRANSPORT_IWARP) { 108 : /* rdma_disconnect may return an error and set errno to EINVAL in case of iWARP. 109 : * This behaviour is expected since iWARP handles disconnect event other than IB and 110 : * qpair is already in error state when we call rdma_disconnect */ 111 0 : return 0; 112 : } 113 0 : SPDK_ERRLOG("rdma_disconnect failed, errno %s (%d)\n", spdk_strerror(errno), errno); 114 : } 115 : } 116 : 117 0 : return rc; 118 : } 119 : 120 : bool 121 0 : spdk_rdma_qp_queue_send_wrs(struct spdk_rdma_qp *spdk_rdma_qp, struct ibv_send_wr *first) 122 : { 123 : struct ibv_send_wr *last; 124 : 125 0 : assert(spdk_rdma_qp); 126 0 : assert(first); 127 : 128 0 : spdk_rdma_qp->stats->send.num_submitted_wrs++; 129 0 : last = first; 130 0 : while (last->next != NULL) { 131 0 : last = last->next; 132 0 : spdk_rdma_qp->stats->send.num_submitted_wrs++; 133 : } 134 : 135 0 : if (spdk_rdma_qp->send_wrs.first == NULL) { 136 0 : spdk_rdma_qp->send_wrs.first = first; 137 0 : spdk_rdma_qp->send_wrs.last = last; 138 0 : return true; 139 : } else { 140 0 : spdk_rdma_qp->send_wrs.last->next = first; 141 0 : spdk_rdma_qp->send_wrs.last = last; 142 0 : return false; 143 : } 144 : } 145 : 146 : int 147 0 : spdk_rdma_qp_flush_send_wrs(struct spdk_rdma_qp *spdk_rdma_qp, struct ibv_send_wr **bad_wr) 148 : { 149 : int rc; 150 : 151 0 : assert(spdk_rdma_qp); 152 0 : assert(bad_wr); 153 : 154 0 : if (spdk_unlikely(!spdk_rdma_qp->send_wrs.first)) { 155 0 : return 0; 156 : } 157 : 158 0 : rc = ibv_post_send(spdk_rdma_qp->qp, spdk_rdma_qp->send_wrs.first, bad_wr); 159 : 160 0 : spdk_rdma_qp->send_wrs.first = NULL; 161 0 : spdk_rdma_qp->stats->send.doorbell_updates++; 162 : 163 0 : return rc; 164 : }