1 /* 2 * Copyright (c) 2010-2014 Intel Corporation. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32 33 #if !defined(RDMA_VERBS_H) 34 #define RDMA_VERBS_H 35 36 #include <assert.h> 37 #include <infiniband/verbs.h> 38 #include <rdma/rdma_cma.h> 39 #include <errno.h> 40 41 #ifdef __cplusplus 42 extern "C" { 43 #endif 44 45 static inline int rdma_seterrno(int ret) 46 { 47 if (ret) { 48 errno = ret; 49 ret = -1; 50 } 51 return ret; 52 } 53 54 /* 55 * Shared receive queues. 56 */ 57 int rdma_create_srq(struct rdma_cm_id *id, struct ibv_pd *pd, 58 struct ibv_srq_init_attr *attr); 59 int rdma_create_srq_ex(struct rdma_cm_id *id, struct ibv_srq_init_attr_ex *attr); 60 61 void rdma_destroy_srq(struct rdma_cm_id *id); 62 63 64 /* 65 * Memory registration helpers. 66 */ 67 static inline struct ibv_mr * 68 rdma_reg_msgs(struct rdma_cm_id *id, void *addr, size_t length) 69 { 70 return ibv_reg_mr(id->pd, addr, length, IBV_ACCESS_LOCAL_WRITE); 71 } 72 73 static inline struct ibv_mr * 74 rdma_reg_read(struct rdma_cm_id *id, void *addr, size_t length) 75 { 76 return ibv_reg_mr(id->pd, addr, length, IBV_ACCESS_LOCAL_WRITE | 77 IBV_ACCESS_REMOTE_READ); 78 } 79 80 static inline struct ibv_mr * 81 rdma_reg_write(struct rdma_cm_id *id, void *addr, size_t length) 82 { 83 return ibv_reg_mr(id->pd, addr, length, IBV_ACCESS_LOCAL_WRITE | 84 IBV_ACCESS_REMOTE_WRITE); 85 } 86 87 static inline int 88 rdma_dereg_mr(struct ibv_mr *mr) 89 { 90 return rdma_seterrno(ibv_dereg_mr(mr)); 91 } 92 93 94 /* 95 * Vectored send, receive, and RDMA operations. 96 * Support multiple scatter-gather entries. 97 */ 98 static inline int 99 rdma_post_recvv(struct rdma_cm_id *id, void *context, struct ibv_sge *sgl, 100 int nsge) 101 { 102 struct ibv_recv_wr wr, *bad; 103 104 wr.wr_id = (uintptr_t) context; 105 wr.next = NULL; 106 wr.sg_list = sgl; 107 wr.num_sge = nsge; 108 109 if (id->srq) 110 return rdma_seterrno(ibv_post_srq_recv(id->srq, &wr, &bad)); 111 else 112 return rdma_seterrno(ibv_post_recv(id->qp, &wr, &bad)); 113 } 114 115 static inline int 116 rdma_post_sendv(struct rdma_cm_id *id, void *context, struct ibv_sge *sgl, 117 int nsge, int flags) 118 { 119 struct ibv_send_wr wr, *bad; 120 121 wr.wr_id = (uintptr_t) context; 122 wr.next = NULL; 123 wr.sg_list = sgl; 124 wr.num_sge = nsge; 125 wr.opcode = IBV_WR_SEND; 126 wr.send_flags = flags; 127 128 return rdma_seterrno(ibv_post_send(id->qp, &wr, &bad)); 129 } 130 131 static inline int 132 rdma_post_readv(struct rdma_cm_id *id, void *context, struct ibv_sge *sgl, 133 int nsge, int flags, uint64_t remote_addr, uint32_t rkey) 134 { 135 struct ibv_send_wr wr, *bad; 136 137 wr.wr_id = (uintptr_t) context; 138 wr.next = NULL; 139 wr.sg_list = sgl; 140 wr.num_sge = nsge; 141 wr.opcode = IBV_WR_RDMA_READ; 142 wr.send_flags = flags; 143 wr.wr.rdma.remote_addr = remote_addr; 144 wr.wr.rdma.rkey = rkey; 145 146 return rdma_seterrno(ibv_post_send(id->qp, &wr, &bad)); 147 } 148 149 static inline int 150 rdma_post_writev(struct rdma_cm_id *id, void *context, struct ibv_sge *sgl, 151 int nsge, int flags, uint64_t remote_addr, uint32_t rkey) 152 { 153 struct ibv_send_wr wr, *bad; 154 155 wr.wr_id = (uintptr_t) context; 156 wr.next = NULL; 157 wr.sg_list = sgl; 158 wr.num_sge = nsge; 159 wr.opcode = IBV_WR_RDMA_WRITE; 160 wr.send_flags = flags; 161 wr.wr.rdma.remote_addr = remote_addr; 162 wr.wr.rdma.rkey = rkey; 163 164 return rdma_seterrno(ibv_post_send(id->qp, &wr, &bad)); 165 } 166 167 /* 168 * Simple send, receive, and RDMA calls. 169 */ 170 static inline int 171 rdma_post_recv(struct rdma_cm_id *id, void *context, void *addr, 172 size_t length, struct ibv_mr *mr) 173 { 174 struct ibv_sge sge; 175 176 assert((addr >= mr->addr) && 177 (((uint8_t *) addr + length) <= ((uint8_t *) mr->addr + mr->length))); 178 sge.addr = (uint64_t) (uintptr_t) addr; 179 sge.length = (uint32_t) length; 180 sge.lkey = mr->lkey; 181 182 return rdma_post_recvv(id, context, &sge, 1); 183 } 184 185 static inline int 186 rdma_post_send(struct rdma_cm_id *id, void *context, void *addr, 187 size_t length, struct ibv_mr *mr, int flags) 188 { 189 struct ibv_sge sge; 190 191 sge.addr = (uint64_t) (uintptr_t) addr; 192 sge.length = (uint32_t) length; 193 sge.lkey = mr ? mr->lkey : 0; 194 195 return rdma_post_sendv(id, context, &sge, 1, flags); 196 } 197 198 static inline int 199 rdma_post_read(struct rdma_cm_id *id, void *context, void *addr, 200 size_t length, struct ibv_mr *mr, int flags, 201 uint64_t remote_addr, uint32_t rkey) 202 { 203 struct ibv_sge sge; 204 205 sge.addr = (uint64_t) (uintptr_t) addr; 206 sge.length = (uint32_t) length; 207 sge.lkey = mr->lkey; 208 209 return rdma_post_readv(id, context, &sge, 1, flags, remote_addr, rkey); 210 } 211 212 static inline int 213 rdma_post_write(struct rdma_cm_id *id, void *context, void *addr, 214 size_t length, struct ibv_mr *mr, int flags, 215 uint64_t remote_addr, uint32_t rkey) 216 { 217 struct ibv_sge sge; 218 219 sge.addr = (uint64_t) (uintptr_t) addr; 220 sge.length = (uint32_t) length; 221 sge.lkey = mr ? mr->lkey : 0; 222 223 return rdma_post_writev(id, context, &sge, 1, flags, remote_addr, rkey); 224 } 225 226 static inline int 227 rdma_post_ud_send(struct rdma_cm_id *id, void *context, void *addr, 228 size_t length, struct ibv_mr *mr, int flags, 229 struct ibv_ah *ah, uint32_t remote_qpn) 230 { 231 struct ibv_send_wr wr, *bad; 232 struct ibv_sge sge; 233 234 sge.addr = (uint64_t) (uintptr_t) addr; 235 sge.length = (uint32_t) length; 236 sge.lkey = mr ? mr->lkey : 0; 237 238 wr.wr_id = (uintptr_t) context; 239 wr.next = NULL; 240 wr.sg_list = &sge; 241 wr.num_sge = 1; 242 wr.opcode = IBV_WR_SEND; 243 wr.send_flags = flags; 244 wr.wr.ud.ah = ah; 245 wr.wr.ud.remote_qpn = remote_qpn; 246 wr.wr.ud.remote_qkey = RDMA_UDP_QKEY; 247 248 return rdma_seterrno(ibv_post_send(id->qp, &wr, &bad)); 249 } 250 251 static inline int 252 rdma_get_send_comp(struct rdma_cm_id *id, struct ibv_wc *wc) 253 { 254 struct ibv_cq *cq; 255 void *context; 256 int ret; 257 258 do { 259 ret = ibv_poll_cq(id->send_cq, 1, wc); 260 if (ret) 261 break; 262 263 ret = ibv_req_notify_cq(id->send_cq, 0); 264 if (ret) 265 return rdma_seterrno(ret); 266 267 ret = ibv_poll_cq(id->send_cq, 1, wc); 268 if (ret) 269 break; 270 271 ret = ibv_get_cq_event(id->send_cq_channel, &cq, &context); 272 if (ret) 273 return ret; 274 275 assert(cq == id->send_cq && context == id); 276 ibv_ack_cq_events(id->send_cq, 1); 277 } while (1); 278 279 return (ret < 0) ? rdma_seterrno(ret) : ret; 280 } 281 282 static inline int 283 rdma_get_recv_comp(struct rdma_cm_id *id, struct ibv_wc *wc) 284 { 285 struct ibv_cq *cq; 286 void *context; 287 int ret; 288 289 do { 290 ret = ibv_poll_cq(id->recv_cq, 1, wc); 291 if (ret) 292 break; 293 294 ret = ibv_req_notify_cq(id->recv_cq, 0); 295 if (ret) 296 return rdma_seterrno(ret); 297 298 ret = ibv_poll_cq(id->recv_cq, 1, wc); 299 if (ret) 300 break; 301 302 ret = ibv_get_cq_event(id->recv_cq_channel, &cq, &context); 303 if (ret) 304 return ret; 305 306 assert(cq == id->recv_cq && context == id); 307 ibv_ack_cq_events(id->recv_cq, 1); 308 } while (1); 309 310 return (ret < 0) ? rdma_seterrno(ret) : ret; 311 } 312 313 #ifdef __cplusplus 314 } 315 #endif 316 317 #endif /* RDMA_CMA_H */ 318