xref: /freebsd/contrib/ofed/libibverbs/verbs.c (revision a687910fc4352117413b8e0275383e4c687d4c4c)
1d6b92ffaSHans Petter Selasky /*
2d6b92ffaSHans Petter Selasky  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
3d6b92ffaSHans Petter Selasky  * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
4d6b92ffaSHans Petter Selasky  *
5d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
6d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
7d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
8d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
9d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
10d6b92ffaSHans Petter Selasky  *
11d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
12d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
13d6b92ffaSHans Petter Selasky  *     conditions are met:
14d6b92ffaSHans Petter Selasky  *
15d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
16d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
17d6b92ffaSHans Petter Selasky  *        disclaimer.
18d6b92ffaSHans Petter Selasky  *
19d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
20d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
21d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
22d6b92ffaSHans Petter Selasky  *        provided with the distribution.
23d6b92ffaSHans Petter Selasky  *
24d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31d6b92ffaSHans Petter Selasky  * SOFTWARE.
32d6b92ffaSHans Petter Selasky  */
33d6b92ffaSHans Petter Selasky 
34d6b92ffaSHans Petter Selasky #define _GNU_SOURCE
35d6b92ffaSHans Petter Selasky #include <config.h>
36d6b92ffaSHans Petter Selasky 
37d6b92ffaSHans Petter Selasky #include <infiniband/endian.h>
38d6b92ffaSHans Petter Selasky #include <stdio.h>
39d6b92ffaSHans Petter Selasky #include <unistd.h>
40d6b92ffaSHans Petter Selasky #include <stdlib.h>
41d6b92ffaSHans Petter Selasky #include <errno.h>
42d6b92ffaSHans Petter Selasky #include <string.h>
43d6b92ffaSHans Petter Selasky #include <dirent.h>
44d6b92ffaSHans Petter Selasky #include <netinet/in.h>
45d6b92ffaSHans Petter Selasky #include <netinet/ip.h>
46d6b92ffaSHans Petter Selasky #include <sys/socket.h>
47d6b92ffaSHans Petter Selasky 
48d6b92ffaSHans Petter Selasky #include "ibverbs.h"
49d6b92ffaSHans Petter Selasky #ifndef NRESOLVE_NEIGH
50d6b92ffaSHans Petter Selasky #include <net/if.h>
51d6b92ffaSHans Petter Selasky #include <net/if_arp.h>
52d6b92ffaSHans Petter Selasky #include "neigh.h"
53d6b92ffaSHans Petter Selasky #endif
54d6b92ffaSHans Petter Selasky 
55d6b92ffaSHans Petter Selasky /* Hack to avoid GCC's -Wmissing-prototypes and the similar error from sparse
56d6b92ffaSHans Petter Selasky    with these prototypes. Symbol versionining requires the goofy names, the
57d6b92ffaSHans Petter Selasky    prototype must match the version in verbs.h.
58d6b92ffaSHans Petter Selasky  */
59d6b92ffaSHans Petter Selasky int __ibv_query_device(struct ibv_context *context,
60d6b92ffaSHans Petter Selasky 		       struct ibv_device_attr *device_attr);
61d6b92ffaSHans Petter Selasky int __ibv_query_port(struct ibv_context *context, uint8_t port_num,
62d6b92ffaSHans Petter Selasky 		     struct ibv_port_attr *port_attr);
63d6b92ffaSHans Petter Selasky int __ibv_query_gid(struct ibv_context *context, uint8_t port_num, int index,
64d6b92ffaSHans Petter Selasky 		    union ibv_gid *gid);
65d6b92ffaSHans Petter Selasky int __ibv_query_pkey(struct ibv_context *context, uint8_t port_num, int index,
66d6b92ffaSHans Petter Selasky 		     __be16 *pkey);
67d6b92ffaSHans Petter Selasky struct ibv_pd *__ibv_alloc_pd(struct ibv_context *context);
68d6b92ffaSHans Petter Selasky int __ibv_dealloc_pd(struct ibv_pd *pd);
69d6b92ffaSHans Petter Selasky struct ibv_mr *__ibv_reg_mr(struct ibv_pd *pd, void *addr, size_t length,
70d6b92ffaSHans Petter Selasky 			    int access);
71d6b92ffaSHans Petter Selasky int __ibv_rereg_mr(struct ibv_mr *mr, int flags, struct ibv_pd *pd, void *addr,
72d6b92ffaSHans Petter Selasky 		   size_t length, int access);
73d6b92ffaSHans Petter Selasky int __ibv_dereg_mr(struct ibv_mr *mr);
74d6b92ffaSHans Petter Selasky struct ibv_cq *__ibv_create_cq(struct ibv_context *context, int cqe,
75d6b92ffaSHans Petter Selasky 			       void *cq_context,
76d6b92ffaSHans Petter Selasky 			       struct ibv_comp_channel *channel,
77d6b92ffaSHans Petter Selasky 			       int comp_vector);
78d6b92ffaSHans Petter Selasky int __ibv_resize_cq(struct ibv_cq *cq, int cqe);
79d6b92ffaSHans Petter Selasky int __ibv_destroy_cq(struct ibv_cq *cq);
80d6b92ffaSHans Petter Selasky int __ibv_get_cq_event(struct ibv_comp_channel *channel, struct ibv_cq **cq,
81d6b92ffaSHans Petter Selasky 		       void **cq_context);
82d6b92ffaSHans Petter Selasky void __ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents);
83d6b92ffaSHans Petter Selasky struct ibv_srq *__ibv_create_srq(struct ibv_pd *pd,
84d6b92ffaSHans Petter Selasky 				 struct ibv_srq_init_attr *srq_init_attr);
85d6b92ffaSHans Petter Selasky int __ibv_modify_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr,
86d6b92ffaSHans Petter Selasky 		     int srq_attr_mask);
87d6b92ffaSHans Petter Selasky int __ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr);
88d6b92ffaSHans Petter Selasky int __ibv_destroy_srq(struct ibv_srq *srq);
89d6b92ffaSHans Petter Selasky struct ibv_qp *__ibv_create_qp(struct ibv_pd *pd,
90d6b92ffaSHans Petter Selasky 			       struct ibv_qp_init_attr *qp_init_attr);
91d6b92ffaSHans Petter Selasky int __ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask,
92d6b92ffaSHans Petter Selasky 		   struct ibv_qp_init_attr *init_attr);
93d6b92ffaSHans Petter Selasky int __ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask);
94d6b92ffaSHans Petter Selasky int __ibv_destroy_qp(struct ibv_qp *qp);
95d6b92ffaSHans Petter Selasky struct ibv_ah *__ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr);
96d6b92ffaSHans Petter Selasky int __ibv_destroy_ah(struct ibv_ah *ah);
97d6b92ffaSHans Petter Selasky int __ibv_attach_mcast(struct ibv_qp *qp, const union ibv_gid *gid,
98d6b92ffaSHans Petter Selasky 		       uint16_t lid);
99d6b92ffaSHans Petter Selasky int __ibv_detach_mcast(struct ibv_qp *qp, const union ibv_gid *gid,
100d6b92ffaSHans Petter Selasky 		       uint16_t lid);
101d6b92ffaSHans Petter Selasky 
ibv_rate_to_mult(enum ibv_rate rate)102d6b92ffaSHans Petter Selasky int __attribute__((const)) ibv_rate_to_mult(enum ibv_rate rate)
103d6b92ffaSHans Petter Selasky {
104d6b92ffaSHans Petter Selasky 	switch (rate) {
105d6b92ffaSHans Petter Selasky 	case IBV_RATE_2_5_GBPS: return  1;
106d6b92ffaSHans Petter Selasky 	case IBV_RATE_5_GBPS:   return  2;
107d6b92ffaSHans Petter Selasky 	case IBV_RATE_10_GBPS:  return  4;
108d6b92ffaSHans Petter Selasky 	case IBV_RATE_20_GBPS:  return  8;
109d6b92ffaSHans Petter Selasky 	case IBV_RATE_30_GBPS:  return 12;
110d6b92ffaSHans Petter Selasky 	case IBV_RATE_40_GBPS:  return 16;
111d6b92ffaSHans Petter Selasky 	case IBV_RATE_60_GBPS:  return 24;
112d6b92ffaSHans Petter Selasky 	case IBV_RATE_80_GBPS:  return 32;
113d6b92ffaSHans Petter Selasky 	case IBV_RATE_120_GBPS: return 48;
114daceb336SHans Petter Selasky 	case IBV_RATE_28_GBPS:  return 11;
115daceb336SHans Petter Selasky 	case IBV_RATE_50_GBPS:  return 20;
116daceb336SHans Petter Selasky 	case IBV_RATE_400_GBPS: return 160;
117daceb336SHans Petter Selasky 	case IBV_RATE_600_GBPS: return 240;
118d6b92ffaSHans Petter Selasky 	default:           return -1;
119d6b92ffaSHans Petter Selasky 	}
120d6b92ffaSHans Petter Selasky }
121d6b92ffaSHans Petter Selasky 
mult_to_ibv_rate(int mult)122d6b92ffaSHans Petter Selasky enum ibv_rate __attribute__((const)) mult_to_ibv_rate(int mult)
123d6b92ffaSHans Petter Selasky {
124d6b92ffaSHans Petter Selasky 	switch (mult) {
125d6b92ffaSHans Petter Selasky 	case 1:  return IBV_RATE_2_5_GBPS;
126d6b92ffaSHans Petter Selasky 	case 2:  return IBV_RATE_5_GBPS;
127d6b92ffaSHans Petter Selasky 	case 4:  return IBV_RATE_10_GBPS;
128d6b92ffaSHans Petter Selasky 	case 8:  return IBV_RATE_20_GBPS;
129d6b92ffaSHans Petter Selasky 	case 12: return IBV_RATE_30_GBPS;
130d6b92ffaSHans Petter Selasky 	case 16: return IBV_RATE_40_GBPS;
131d6b92ffaSHans Petter Selasky 	case 24: return IBV_RATE_60_GBPS;
132d6b92ffaSHans Petter Selasky 	case 32: return IBV_RATE_80_GBPS;
133d6b92ffaSHans Petter Selasky 	case 48: return IBV_RATE_120_GBPS;
134daceb336SHans Petter Selasky 	case 11: return IBV_RATE_28_GBPS;
135daceb336SHans Petter Selasky 	case 20: return IBV_RATE_50_GBPS;
136daceb336SHans Petter Selasky 	case 160: return IBV_RATE_400_GBPS;
137daceb336SHans Petter Selasky 	case 240: return IBV_RATE_600_GBPS;
138d6b92ffaSHans Petter Selasky 	default: return IBV_RATE_MAX;
139d6b92ffaSHans Petter Selasky 	}
140d6b92ffaSHans Petter Selasky }
141d6b92ffaSHans Petter Selasky 
ibv_rate_to_mbps(enum ibv_rate rate)142d6b92ffaSHans Petter Selasky int  __attribute__((const)) ibv_rate_to_mbps(enum ibv_rate rate)
143d6b92ffaSHans Petter Selasky {
144d6b92ffaSHans Petter Selasky 	switch (rate) {
145d6b92ffaSHans Petter Selasky 	case IBV_RATE_2_5_GBPS: return 2500;
146d6b92ffaSHans Petter Selasky 	case IBV_RATE_5_GBPS:   return 5000;
147d6b92ffaSHans Petter Selasky 	case IBV_RATE_10_GBPS:  return 10000;
148d6b92ffaSHans Petter Selasky 	case IBV_RATE_20_GBPS:  return 20000;
149d6b92ffaSHans Petter Selasky 	case IBV_RATE_30_GBPS:  return 30000;
150d6b92ffaSHans Petter Selasky 	case IBV_RATE_40_GBPS:  return 40000;
151d6b92ffaSHans Petter Selasky 	case IBV_RATE_60_GBPS:  return 60000;
152d6b92ffaSHans Petter Selasky 	case IBV_RATE_80_GBPS:  return 80000;
153d6b92ffaSHans Petter Selasky 	case IBV_RATE_120_GBPS: return 120000;
154d6b92ffaSHans Petter Selasky 	case IBV_RATE_14_GBPS:  return 14062;
155d6b92ffaSHans Petter Selasky 	case IBV_RATE_56_GBPS:  return 56250;
156d6b92ffaSHans Petter Selasky 	case IBV_RATE_112_GBPS: return 112500;
157d6b92ffaSHans Petter Selasky 	case IBV_RATE_168_GBPS: return 168750;
158d6b92ffaSHans Petter Selasky 	case IBV_RATE_25_GBPS:  return 25781;
159d6b92ffaSHans Petter Selasky 	case IBV_RATE_100_GBPS: return 103125;
160d6b92ffaSHans Petter Selasky 	case IBV_RATE_200_GBPS: return 206250;
161d6b92ffaSHans Petter Selasky 	case IBV_RATE_300_GBPS: return 309375;
162daceb336SHans Petter Selasky 	case IBV_RATE_28_GBPS:  return 28125;
163daceb336SHans Petter Selasky 	case IBV_RATE_50_GBPS:  return 53125;
164daceb336SHans Petter Selasky 	case IBV_RATE_400_GBPS: return 425000;
165daceb336SHans Petter Selasky 	case IBV_RATE_600_GBPS: return 637500;
166d6b92ffaSHans Petter Selasky 	default:               return -1;
167d6b92ffaSHans Petter Selasky 	}
168d6b92ffaSHans Petter Selasky }
169d6b92ffaSHans Petter Selasky 
mbps_to_ibv_rate(int mbps)170d6b92ffaSHans Petter Selasky enum ibv_rate __attribute__((const)) mbps_to_ibv_rate(int mbps)
171d6b92ffaSHans Petter Selasky {
172d6b92ffaSHans Petter Selasky 	switch (mbps) {
173d6b92ffaSHans Petter Selasky 	case 2500:   return IBV_RATE_2_5_GBPS;
174d6b92ffaSHans Petter Selasky 	case 5000:   return IBV_RATE_5_GBPS;
175d6b92ffaSHans Petter Selasky 	case 10000:  return IBV_RATE_10_GBPS;
176d6b92ffaSHans Petter Selasky 	case 20000:  return IBV_RATE_20_GBPS;
177d6b92ffaSHans Petter Selasky 	case 30000:  return IBV_RATE_30_GBPS;
178d6b92ffaSHans Petter Selasky 	case 40000:  return IBV_RATE_40_GBPS;
179d6b92ffaSHans Petter Selasky 	case 60000:  return IBV_RATE_60_GBPS;
180d6b92ffaSHans Petter Selasky 	case 80000:  return IBV_RATE_80_GBPS;
181d6b92ffaSHans Petter Selasky 	case 120000: return IBV_RATE_120_GBPS;
182d6b92ffaSHans Petter Selasky 	case 14062:  return IBV_RATE_14_GBPS;
183d6b92ffaSHans Petter Selasky 	case 56250:  return IBV_RATE_56_GBPS;
184d6b92ffaSHans Petter Selasky 	case 112500: return IBV_RATE_112_GBPS;
185d6b92ffaSHans Petter Selasky 	case 168750: return IBV_RATE_168_GBPS;
186d6b92ffaSHans Petter Selasky 	case 25781:  return IBV_RATE_25_GBPS;
187d6b92ffaSHans Petter Selasky 	case 103125: return IBV_RATE_100_GBPS;
188d6b92ffaSHans Petter Selasky 	case 206250: return IBV_RATE_200_GBPS;
189d6b92ffaSHans Petter Selasky 	case 309375: return IBV_RATE_300_GBPS;
190daceb336SHans Petter Selasky 	case 28125:  return IBV_RATE_28_GBPS;
191daceb336SHans Petter Selasky 	case 53125:  return IBV_RATE_50_GBPS;
192daceb336SHans Petter Selasky 	case 425000: return IBV_RATE_400_GBPS;
193daceb336SHans Petter Selasky 	case 637500: return IBV_RATE_600_GBPS;
194d6b92ffaSHans Petter Selasky 	default:     return IBV_RATE_MAX;
195d6b92ffaSHans Petter Selasky 	}
196d6b92ffaSHans Petter Selasky }
197d6b92ffaSHans Petter Selasky 
__ibv_query_device(struct ibv_context * context,struct ibv_device_attr * device_attr)198d6b92ffaSHans Petter Selasky int __ibv_query_device(struct ibv_context *context,
199d6b92ffaSHans Petter Selasky 		       struct ibv_device_attr *device_attr)
200d6b92ffaSHans Petter Selasky {
201d6b92ffaSHans Petter Selasky 	return context->ops.query_device(context, device_attr);
202d6b92ffaSHans Petter Selasky }
203d6b92ffaSHans Petter Selasky default_symver(__ibv_query_device, ibv_query_device);
204d6b92ffaSHans Petter Selasky 
__ibv_query_port(struct ibv_context * context,uint8_t port_num,struct ibv_port_attr * port_attr)205d6b92ffaSHans Petter Selasky int __ibv_query_port(struct ibv_context *context, uint8_t port_num,
206d6b92ffaSHans Petter Selasky 		     struct ibv_port_attr *port_attr)
207d6b92ffaSHans Petter Selasky {
208d6b92ffaSHans Petter Selasky 	return context->ops.query_port(context, port_num, port_attr);
209d6b92ffaSHans Petter Selasky }
210d6b92ffaSHans Petter Selasky default_symver(__ibv_query_port, ibv_query_port);
211d6b92ffaSHans Petter Selasky 
__ibv_query_gid(struct ibv_context * context,uint8_t port_num,int index,union ibv_gid * gid)212d6b92ffaSHans Petter Selasky int __ibv_query_gid(struct ibv_context *context, uint8_t port_num,
213d6b92ffaSHans Petter Selasky 		    int index, union ibv_gid *gid)
214d6b92ffaSHans Petter Selasky {
215d6b92ffaSHans Petter Selasky 	char name[24];
216d6b92ffaSHans Petter Selasky 	char attr[41];
217d6b92ffaSHans Petter Selasky 	uint16_t val;
218d6b92ffaSHans Petter Selasky 	int i;
219d6b92ffaSHans Petter Selasky 
220d6b92ffaSHans Petter Selasky 	snprintf(name, sizeof name, "ports/%d/gids/%d", port_num, index);
221d6b92ffaSHans Petter Selasky 
222d6b92ffaSHans Petter Selasky 	if (ibv_read_sysfs_file(context->device->ibdev_path, name,
223d6b92ffaSHans Petter Selasky 				attr, sizeof attr) < 0)
224d6b92ffaSHans Petter Selasky 		return -1;
225d6b92ffaSHans Petter Selasky 
226d6b92ffaSHans Petter Selasky 	for (i = 0; i < 8; ++i) {
227d6b92ffaSHans Petter Selasky 		if (sscanf(attr + i * 5, "%hx", &val) != 1)
228d6b92ffaSHans Petter Selasky 			return -1;
229d6b92ffaSHans Petter Selasky 		gid->raw[i * 2    ] = val >> 8;
230d6b92ffaSHans Petter Selasky 		gid->raw[i * 2 + 1] = val & 0xff;
231d6b92ffaSHans Petter Selasky 	}
232d6b92ffaSHans Petter Selasky 
233d6b92ffaSHans Petter Selasky 	return 0;
234d6b92ffaSHans Petter Selasky }
235d6b92ffaSHans Petter Selasky default_symver(__ibv_query_gid, ibv_query_gid);
236d6b92ffaSHans Petter Selasky 
__ibv_query_pkey(struct ibv_context * context,uint8_t port_num,int index,__be16 * pkey)237d6b92ffaSHans Petter Selasky int __ibv_query_pkey(struct ibv_context *context, uint8_t port_num,
238d6b92ffaSHans Petter Selasky 		     int index, __be16 *pkey)
239d6b92ffaSHans Petter Selasky {
240d6b92ffaSHans Petter Selasky 	char name[24];
241d6b92ffaSHans Petter Selasky 	char attr[8];
242d6b92ffaSHans Petter Selasky 	uint16_t val;
243d6b92ffaSHans Petter Selasky 
244d6b92ffaSHans Petter Selasky 	snprintf(name, sizeof name, "ports/%d/pkeys/%d", port_num, index);
245d6b92ffaSHans Petter Selasky 
246d6b92ffaSHans Petter Selasky 	if (ibv_read_sysfs_file(context->device->ibdev_path, name,
247d6b92ffaSHans Petter Selasky 				attr, sizeof attr) < 0)
248d6b92ffaSHans Petter Selasky 		return -1;
249d6b92ffaSHans Petter Selasky 
250d6b92ffaSHans Petter Selasky 	if (sscanf(attr, "%hx", &val) != 1)
251d6b92ffaSHans Petter Selasky 		return -1;
252d6b92ffaSHans Petter Selasky 
253d6b92ffaSHans Petter Selasky 	*pkey = htobe16(val);
254d6b92ffaSHans Petter Selasky 	return 0;
255d6b92ffaSHans Petter Selasky }
256d6b92ffaSHans Petter Selasky default_symver(__ibv_query_pkey, ibv_query_pkey);
257d6b92ffaSHans Petter Selasky 
__ibv_alloc_pd(struct ibv_context * context)258d6b92ffaSHans Petter Selasky struct ibv_pd *__ibv_alloc_pd(struct ibv_context *context)
259d6b92ffaSHans Petter Selasky {
260d6b92ffaSHans Petter Selasky 	struct ibv_pd *pd;
261d6b92ffaSHans Petter Selasky 
262d6b92ffaSHans Petter Selasky 	pd = context->ops.alloc_pd(context);
263d6b92ffaSHans Petter Selasky 	if (pd)
264d6b92ffaSHans Petter Selasky 		pd->context = context;
265d6b92ffaSHans Petter Selasky 
266d6b92ffaSHans Petter Selasky 	return pd;
267d6b92ffaSHans Petter Selasky }
268d6b92ffaSHans Petter Selasky default_symver(__ibv_alloc_pd, ibv_alloc_pd);
269d6b92ffaSHans Petter Selasky 
__ibv_dealloc_pd(struct ibv_pd * pd)270d6b92ffaSHans Petter Selasky int __ibv_dealloc_pd(struct ibv_pd *pd)
271d6b92ffaSHans Petter Selasky {
272d6b92ffaSHans Petter Selasky 	return pd->context->ops.dealloc_pd(pd);
273d6b92ffaSHans Petter Selasky }
274d6b92ffaSHans Petter Selasky default_symver(__ibv_dealloc_pd, ibv_dealloc_pd);
275d6b92ffaSHans Petter Selasky 
__ibv_reg_mr(struct ibv_pd * pd,void * addr,size_t length,int access)276d6b92ffaSHans Petter Selasky struct ibv_mr *__ibv_reg_mr(struct ibv_pd *pd, void *addr,
277d6b92ffaSHans Petter Selasky 			    size_t length, int access)
278d6b92ffaSHans Petter Selasky {
279d6b92ffaSHans Petter Selasky 	struct ibv_mr *mr;
280d6b92ffaSHans Petter Selasky 
281d6b92ffaSHans Petter Selasky 	if (ibv_dontfork_range(addr, length))
282d6b92ffaSHans Petter Selasky 		return NULL;
283d6b92ffaSHans Petter Selasky 
284d6b92ffaSHans Petter Selasky 	mr = pd->context->ops.reg_mr(pd, addr, length, access);
285d6b92ffaSHans Petter Selasky 	if (mr) {
286d6b92ffaSHans Petter Selasky 		mr->context = pd->context;
287d6b92ffaSHans Petter Selasky 		mr->pd      = pd;
288d6b92ffaSHans Petter Selasky 		mr->addr    = addr;
289d6b92ffaSHans Petter Selasky 		mr->length  = length;
290d6b92ffaSHans Petter Selasky 	} else
291d6b92ffaSHans Petter Selasky 		ibv_dofork_range(addr, length);
292d6b92ffaSHans Petter Selasky 
293d6b92ffaSHans Petter Selasky 	return mr;
294d6b92ffaSHans Petter Selasky }
295d6b92ffaSHans Petter Selasky default_symver(__ibv_reg_mr, ibv_reg_mr);
296d6b92ffaSHans Petter Selasky 
__ibv_rereg_mr(struct ibv_mr * mr,int flags,struct ibv_pd * pd,void * addr,size_t length,int access)297d6b92ffaSHans Petter Selasky int __ibv_rereg_mr(struct ibv_mr *mr, int flags,
298d6b92ffaSHans Petter Selasky 		   struct ibv_pd *pd, void *addr,
299d6b92ffaSHans Petter Selasky 		   size_t length, int access)
300d6b92ffaSHans Petter Selasky {
301d6b92ffaSHans Petter Selasky 	int dofork_onfail = 0;
302d6b92ffaSHans Petter Selasky 	int err;
303d6b92ffaSHans Petter Selasky 	void *old_addr;
304d6b92ffaSHans Petter Selasky 	size_t old_len;
305d6b92ffaSHans Petter Selasky 
306d6b92ffaSHans Petter Selasky 	if (flags & ~IBV_REREG_MR_FLAGS_SUPPORTED) {
307d6b92ffaSHans Petter Selasky 		errno = EINVAL;
308d6b92ffaSHans Petter Selasky 		return IBV_REREG_MR_ERR_INPUT;
309d6b92ffaSHans Petter Selasky 	}
310d6b92ffaSHans Petter Selasky 
311d6b92ffaSHans Petter Selasky 	if ((flags & IBV_REREG_MR_CHANGE_TRANSLATION) &&
312d6b92ffaSHans Petter Selasky 	    (!length || !addr)) {
313d6b92ffaSHans Petter Selasky 		errno = EINVAL;
314d6b92ffaSHans Petter Selasky 		return IBV_REREG_MR_ERR_INPUT;
315d6b92ffaSHans Petter Selasky 	}
316d6b92ffaSHans Petter Selasky 
317d6b92ffaSHans Petter Selasky 	if (access && !(flags & IBV_REREG_MR_CHANGE_ACCESS)) {
318d6b92ffaSHans Petter Selasky 		errno = EINVAL;
319d6b92ffaSHans Petter Selasky 		return IBV_REREG_MR_ERR_INPUT;
320d6b92ffaSHans Petter Selasky 	}
321d6b92ffaSHans Petter Selasky 
322d6b92ffaSHans Petter Selasky 	if (!mr->context->ops.rereg_mr) {
323d6b92ffaSHans Petter Selasky 		errno = ENOSYS;
324d6b92ffaSHans Petter Selasky 		return IBV_REREG_MR_ERR_INPUT;
325d6b92ffaSHans Petter Selasky 	}
326d6b92ffaSHans Petter Selasky 
327d6b92ffaSHans Petter Selasky 	if (flags & IBV_REREG_MR_CHANGE_TRANSLATION) {
328d6b92ffaSHans Petter Selasky 		err = ibv_dontfork_range(addr, length);
329d6b92ffaSHans Petter Selasky 		if (err)
330d6b92ffaSHans Petter Selasky 			return IBV_REREG_MR_ERR_DONT_FORK_NEW;
331d6b92ffaSHans Petter Selasky 		dofork_onfail = 1;
332d6b92ffaSHans Petter Selasky 	}
333d6b92ffaSHans Petter Selasky 
334d6b92ffaSHans Petter Selasky 	old_addr = mr->addr;
335d6b92ffaSHans Petter Selasky 	old_len = mr->length;
336d6b92ffaSHans Petter Selasky 	err = mr->context->ops.rereg_mr(mr, flags, pd, addr, length, access);
337d6b92ffaSHans Petter Selasky 	if (!err) {
338d6b92ffaSHans Petter Selasky 		if (flags & IBV_REREG_MR_CHANGE_PD)
339d6b92ffaSHans Petter Selasky 			mr->pd = pd;
340d6b92ffaSHans Petter Selasky 		if (flags & IBV_REREG_MR_CHANGE_TRANSLATION) {
341d6b92ffaSHans Petter Selasky 			mr->addr    = addr;
342d6b92ffaSHans Petter Selasky 			mr->length  = length;
343d6b92ffaSHans Petter Selasky 			err = ibv_dofork_range(old_addr, old_len);
344d6b92ffaSHans Petter Selasky 			if (err)
345d6b92ffaSHans Petter Selasky 				return IBV_REREG_MR_ERR_DO_FORK_OLD;
346d6b92ffaSHans Petter Selasky 		}
347d6b92ffaSHans Petter Selasky 	} else {
348d6b92ffaSHans Petter Selasky 		err = IBV_REREG_MR_ERR_CMD;
349d6b92ffaSHans Petter Selasky 		if (dofork_onfail) {
350d6b92ffaSHans Petter Selasky 			if (ibv_dofork_range(addr, length))
351d6b92ffaSHans Petter Selasky 				err = IBV_REREG_MR_ERR_CMD_AND_DO_FORK_NEW;
352d6b92ffaSHans Petter Selasky 		}
353d6b92ffaSHans Petter Selasky 	}
354d6b92ffaSHans Petter Selasky 
355d6b92ffaSHans Petter Selasky 	return err;
356d6b92ffaSHans Petter Selasky }
357d6b92ffaSHans Petter Selasky default_symver(__ibv_rereg_mr, ibv_rereg_mr);
358d6b92ffaSHans Petter Selasky 
__ibv_dereg_mr(struct ibv_mr * mr)359d6b92ffaSHans Petter Selasky int __ibv_dereg_mr(struct ibv_mr *mr)
360d6b92ffaSHans Petter Selasky {
361d6b92ffaSHans Petter Selasky 	int ret;
362d6b92ffaSHans Petter Selasky 	void *addr	= mr->addr;
363d6b92ffaSHans Petter Selasky 	size_t length	= mr->length;
364d6b92ffaSHans Petter Selasky 
365d6b92ffaSHans Petter Selasky 	ret = mr->context->ops.dereg_mr(mr);
366d6b92ffaSHans Petter Selasky 	if (!ret)
367d6b92ffaSHans Petter Selasky 		ibv_dofork_range(addr, length);
368d6b92ffaSHans Petter Selasky 
369d6b92ffaSHans Petter Selasky 	return ret;
370d6b92ffaSHans Petter Selasky }
371d6b92ffaSHans Petter Selasky default_symver(__ibv_dereg_mr, ibv_dereg_mr);
372d6b92ffaSHans Petter Selasky 
ibv_create_comp_channel_v2(struct ibv_context * context)373d6b92ffaSHans Petter Selasky static struct ibv_comp_channel *ibv_create_comp_channel_v2(struct ibv_context *context)
374d6b92ffaSHans Petter Selasky {
375d6b92ffaSHans Petter Selasky 	struct ibv_abi_compat_v2 *t = context->abi_compat;
376d6b92ffaSHans Petter Selasky 	static int warned;
377d6b92ffaSHans Petter Selasky 
378d6b92ffaSHans Petter Selasky 	if (!pthread_mutex_trylock(&t->in_use))
379d6b92ffaSHans Petter Selasky 		return &t->channel;
380d6b92ffaSHans Petter Selasky 
381d6b92ffaSHans Petter Selasky 	if (!warned) {
382d6b92ffaSHans Petter Selasky 		fprintf(stderr, PFX "Warning: kernel's ABI version %d limits capacity.\n"
383d6b92ffaSHans Petter Selasky 			"    Only one completion channel can be created per context.\n",
384d6b92ffaSHans Petter Selasky 			abi_ver);
385d6b92ffaSHans Petter Selasky 		++warned;
386d6b92ffaSHans Petter Selasky 	}
387d6b92ffaSHans Petter Selasky 
388d6b92ffaSHans Petter Selasky 	return NULL;
389d6b92ffaSHans Petter Selasky }
390d6b92ffaSHans Petter Selasky 
ibv_create_comp_channel(struct ibv_context * context)391d6b92ffaSHans Petter Selasky struct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context *context)
392d6b92ffaSHans Petter Selasky {
393d6b92ffaSHans Petter Selasky 	struct ibv_comp_channel            *channel;
394d6b92ffaSHans Petter Selasky 	struct ibv_create_comp_channel      cmd;
395d6b92ffaSHans Petter Selasky 	struct ibv_create_comp_channel_resp resp;
396d6b92ffaSHans Petter Selasky 
397d6b92ffaSHans Petter Selasky 	if (abi_ver <= 2)
398d6b92ffaSHans Petter Selasky 		return ibv_create_comp_channel_v2(context);
399d6b92ffaSHans Petter Selasky 
400d6b92ffaSHans Petter Selasky 	channel = malloc(sizeof *channel);
401d6b92ffaSHans Petter Selasky 	if (!channel)
402d6b92ffaSHans Petter Selasky 		return NULL;
403d6b92ffaSHans Petter Selasky 
404d6b92ffaSHans Petter Selasky 	IBV_INIT_CMD_RESP(&cmd, sizeof cmd, CREATE_COMP_CHANNEL, &resp, sizeof resp);
405d6b92ffaSHans Petter Selasky 	if (write(context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) {
406d6b92ffaSHans Petter Selasky 		free(channel);
407d6b92ffaSHans Petter Selasky 		return NULL;
408d6b92ffaSHans Petter Selasky 	}
409d6b92ffaSHans Petter Selasky 
410d6b92ffaSHans Petter Selasky 	(void) VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
411d6b92ffaSHans Petter Selasky 
412d6b92ffaSHans Petter Selasky 	channel->context = context;
413d6b92ffaSHans Petter Selasky 	channel->fd      = resp.fd;
414d6b92ffaSHans Petter Selasky 	channel->refcnt  = 0;
415d6b92ffaSHans Petter Selasky 
416d6b92ffaSHans Petter Selasky 	return channel;
417d6b92ffaSHans Petter Selasky }
418d6b92ffaSHans Petter Selasky 
ibv_destroy_comp_channel_v2(struct ibv_comp_channel * channel)419d6b92ffaSHans Petter Selasky static int ibv_destroy_comp_channel_v2(struct ibv_comp_channel *channel)
420d6b92ffaSHans Petter Selasky {
421d6b92ffaSHans Petter Selasky 	struct ibv_abi_compat_v2 *t = (struct ibv_abi_compat_v2 *) channel;
422d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&t->in_use);
423d6b92ffaSHans Petter Selasky 	return 0;
424d6b92ffaSHans Petter Selasky }
425d6b92ffaSHans Petter Selasky 
ibv_destroy_comp_channel(struct ibv_comp_channel * channel)426d6b92ffaSHans Petter Selasky int ibv_destroy_comp_channel(struct ibv_comp_channel *channel)
427d6b92ffaSHans Petter Selasky {
428d6b92ffaSHans Petter Selasky 	struct ibv_context *context;
429d6b92ffaSHans Petter Selasky 	int ret;
430d6b92ffaSHans Petter Selasky 
431d6b92ffaSHans Petter Selasky 	context = channel->context;
432d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&context->mutex);
433d6b92ffaSHans Petter Selasky 
434d6b92ffaSHans Petter Selasky 	if (channel->refcnt) {
435d6b92ffaSHans Petter Selasky 		ret = EBUSY;
436d6b92ffaSHans Petter Selasky 		goto out;
437d6b92ffaSHans Petter Selasky 	}
438d6b92ffaSHans Petter Selasky 
439d6b92ffaSHans Petter Selasky 	if (abi_ver <= 2) {
440d6b92ffaSHans Petter Selasky 		ret = ibv_destroy_comp_channel_v2(channel);
441d6b92ffaSHans Petter Selasky 		goto out;
442d6b92ffaSHans Petter Selasky 	}
443d6b92ffaSHans Petter Selasky 
444d6b92ffaSHans Petter Selasky 	close(channel->fd);
445d6b92ffaSHans Petter Selasky 	free(channel);
446d6b92ffaSHans Petter Selasky 	ret = 0;
447d6b92ffaSHans Petter Selasky 
448d6b92ffaSHans Petter Selasky out:
449d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&context->mutex);
450d6b92ffaSHans Petter Selasky 
451d6b92ffaSHans Petter Selasky 	return ret;
452d6b92ffaSHans Petter Selasky }
453d6b92ffaSHans Petter Selasky 
__ibv_create_cq(struct ibv_context * context,int cqe,void * cq_context,struct ibv_comp_channel * channel,int comp_vector)454d6b92ffaSHans Petter Selasky struct ibv_cq *__ibv_create_cq(struct ibv_context *context, int cqe, void *cq_context,
455d6b92ffaSHans Petter Selasky 			       struct ibv_comp_channel *channel, int comp_vector)
456d6b92ffaSHans Petter Selasky {
457d6b92ffaSHans Petter Selasky 	struct ibv_cq *cq;
458*a687910fSSean Lim 	int err = 0;
459d6b92ffaSHans Petter Selasky 
460d6b92ffaSHans Petter Selasky 	cq = context->ops.create_cq(context, cqe, channel, comp_vector);
461d6b92ffaSHans Petter Selasky 
462*a687910fSSean Lim 	if (!cq)
463*a687910fSSean Lim 		return NULL;
464*a687910fSSean Lim 
465*a687910fSSean Lim 	err = verbs_init_cq(cq, context, channel, cq_context);
466*a687910fSSean Lim 	if (err)
467*a687910fSSean Lim 		goto err;
468d6b92ffaSHans Petter Selasky 
469d6b92ffaSHans Petter Selasky 	return cq;
470*a687910fSSean Lim 
471*a687910fSSean Lim err:
472*a687910fSSean Lim 	context->ops.destroy_cq(cq);
473*a687910fSSean Lim 
474*a687910fSSean Lim 	return NULL;
475d6b92ffaSHans Petter Selasky }
476d6b92ffaSHans Petter Selasky default_symver(__ibv_create_cq, ibv_create_cq);
477d6b92ffaSHans Petter Selasky 
__ibv_resize_cq(struct ibv_cq * cq,int cqe)478d6b92ffaSHans Petter Selasky int __ibv_resize_cq(struct ibv_cq *cq, int cqe)
479d6b92ffaSHans Petter Selasky {
480d6b92ffaSHans Petter Selasky 	if (!cq->context->ops.resize_cq)
481d6b92ffaSHans Petter Selasky 		return ENOSYS;
482d6b92ffaSHans Petter Selasky 
483d6b92ffaSHans Petter Selasky 	return cq->context->ops.resize_cq(cq, cqe);
484d6b92ffaSHans Petter Selasky }
485d6b92ffaSHans Petter Selasky default_symver(__ibv_resize_cq, ibv_resize_cq);
486d6b92ffaSHans Petter Selasky 
__ibv_destroy_cq(struct ibv_cq * cq)487d6b92ffaSHans Petter Selasky int __ibv_destroy_cq(struct ibv_cq *cq)
488d6b92ffaSHans Petter Selasky {
489d6b92ffaSHans Petter Selasky 	struct ibv_comp_channel *channel = cq->channel;
490d6b92ffaSHans Petter Selasky 	int ret;
491d6b92ffaSHans Petter Selasky 
492d6b92ffaSHans Petter Selasky 	ret = cq->context->ops.destroy_cq(cq);
493d6b92ffaSHans Petter Selasky 
494d6b92ffaSHans Petter Selasky 	if (channel) {
495d6b92ffaSHans Petter Selasky 		if (!ret) {
496d6b92ffaSHans Petter Selasky 			pthread_mutex_lock(&channel->context->mutex);
497d6b92ffaSHans Petter Selasky 			--channel->refcnt;
498d6b92ffaSHans Petter Selasky 			pthread_mutex_unlock(&channel->context->mutex);
499d6b92ffaSHans Petter Selasky 		}
500d6b92ffaSHans Petter Selasky 	}
501d6b92ffaSHans Petter Selasky 
502d6b92ffaSHans Petter Selasky 	return ret;
503d6b92ffaSHans Petter Selasky }
504d6b92ffaSHans Petter Selasky default_symver(__ibv_destroy_cq, ibv_destroy_cq);
505d6b92ffaSHans Petter Selasky 
__ibv_get_cq_event(struct ibv_comp_channel * channel,struct ibv_cq ** cq,void ** cq_context)506d6b92ffaSHans Petter Selasky int __ibv_get_cq_event(struct ibv_comp_channel *channel,
507d6b92ffaSHans Petter Selasky 		       struct ibv_cq **cq, void **cq_context)
508d6b92ffaSHans Petter Selasky {
509d6b92ffaSHans Petter Selasky 	struct ibv_comp_event ev;
510d6b92ffaSHans Petter Selasky 
511d6b92ffaSHans Petter Selasky 	if (read(channel->fd, &ev, sizeof ev) != sizeof ev)
512d6b92ffaSHans Petter Selasky 		return -1;
513d6b92ffaSHans Petter Selasky 
514d6b92ffaSHans Petter Selasky 	*cq         = (struct ibv_cq *) (uintptr_t) ev.cq_handle;
515d6b92ffaSHans Petter Selasky 	*cq_context = (*cq)->cq_context;
516d6b92ffaSHans Petter Selasky 
517d6b92ffaSHans Petter Selasky 	if ((*cq)->context->ops.cq_event)
518d6b92ffaSHans Petter Selasky 		(*cq)->context->ops.cq_event(*cq);
519d6b92ffaSHans Petter Selasky 
520d6b92ffaSHans Petter Selasky 	return 0;
521d6b92ffaSHans Petter Selasky }
522d6b92ffaSHans Petter Selasky default_symver(__ibv_get_cq_event, ibv_get_cq_event);
523d6b92ffaSHans Petter Selasky 
__ibv_ack_cq_events(struct ibv_cq * cq,unsigned int nevents)524d6b92ffaSHans Petter Selasky void __ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
525d6b92ffaSHans Petter Selasky {
526d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&cq->mutex);
527d6b92ffaSHans Petter Selasky 	cq->comp_events_completed += nevents;
528d6b92ffaSHans Petter Selasky 	pthread_cond_signal(&cq->cond);
529d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&cq->mutex);
530d6b92ffaSHans Petter Selasky }
531d6b92ffaSHans Petter Selasky default_symver(__ibv_ack_cq_events, ibv_ack_cq_events);
532d6b92ffaSHans Petter Selasky 
__ibv_create_srq(struct ibv_pd * pd,struct ibv_srq_init_attr * srq_init_attr)533d6b92ffaSHans Petter Selasky struct ibv_srq *__ibv_create_srq(struct ibv_pd *pd,
534d6b92ffaSHans Petter Selasky 				 struct ibv_srq_init_attr *srq_init_attr)
535d6b92ffaSHans Petter Selasky {
536d6b92ffaSHans Petter Selasky 	struct ibv_srq *srq;
537d6b92ffaSHans Petter Selasky 
538d6b92ffaSHans Petter Selasky 	if (!pd->context->ops.create_srq)
539d6b92ffaSHans Petter Selasky 		return NULL;
540d6b92ffaSHans Petter Selasky 
541d6b92ffaSHans Petter Selasky 	srq = pd->context->ops.create_srq(pd, srq_init_attr);
542*a687910fSSean Lim 	if (!srq)
543*a687910fSSean Lim 		return NULL;
544*a687910fSSean Lim 
545d6b92ffaSHans Petter Selasky 	srq->context		  = pd->context;
546d6b92ffaSHans Petter Selasky 	srq->srq_context	  = srq_init_attr->srq_context;
547d6b92ffaSHans Petter Selasky 	srq->pd				  = pd;
548d6b92ffaSHans Petter Selasky 	srq->events_completed = 0;
549*a687910fSSean Lim 	if (pthread_mutex_init(&srq->mutex, NULL))
550*a687910fSSean Lim 		goto err;
551*a687910fSSean Lim 	if (pthread_cond_init(&srq->cond, NULL))
552*a687910fSSean Lim 		goto err_mutex;
553d6b92ffaSHans Petter Selasky 
554d6b92ffaSHans Petter Selasky 	return srq;
555*a687910fSSean Lim 
556*a687910fSSean Lim err_mutex:
557*a687910fSSean Lim 	pthread_mutex_destroy(&srq->mutex);
558*a687910fSSean Lim err:
559*a687910fSSean Lim 	pd->context->ops.destroy_srq(srq);
560*a687910fSSean Lim 
561*a687910fSSean Lim 	return NULL;
562d6b92ffaSHans Petter Selasky }
563d6b92ffaSHans Petter Selasky default_symver(__ibv_create_srq, ibv_create_srq);
564d6b92ffaSHans Petter Selasky 
__ibv_modify_srq(struct ibv_srq * srq,struct ibv_srq_attr * srq_attr,int srq_attr_mask)565d6b92ffaSHans Petter Selasky int __ibv_modify_srq(struct ibv_srq *srq,
566d6b92ffaSHans Petter Selasky 		     struct ibv_srq_attr *srq_attr,
567d6b92ffaSHans Petter Selasky 		     int srq_attr_mask)
568d6b92ffaSHans Petter Selasky {
569d6b92ffaSHans Petter Selasky 	return srq->context->ops.modify_srq(srq, srq_attr, srq_attr_mask);
570d6b92ffaSHans Petter Selasky }
571d6b92ffaSHans Petter Selasky default_symver(__ibv_modify_srq, ibv_modify_srq);
572d6b92ffaSHans Petter Selasky 
__ibv_query_srq(struct ibv_srq * srq,struct ibv_srq_attr * srq_attr)573d6b92ffaSHans Petter Selasky int __ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr)
574d6b92ffaSHans Petter Selasky {
575d6b92ffaSHans Petter Selasky 	return srq->context->ops.query_srq(srq, srq_attr);
576d6b92ffaSHans Petter Selasky }
577d6b92ffaSHans Petter Selasky default_symver(__ibv_query_srq, ibv_query_srq);
578d6b92ffaSHans Petter Selasky 
__ibv_destroy_srq(struct ibv_srq * srq)579d6b92ffaSHans Petter Selasky int __ibv_destroy_srq(struct ibv_srq *srq)
580d6b92ffaSHans Petter Selasky {
581*a687910fSSean Lim 	pthread_cond_destroy(&srq->cond);
582*a687910fSSean Lim 	pthread_mutex_destroy(&srq->mutex);
583d6b92ffaSHans Petter Selasky 	return srq->context->ops.destroy_srq(srq);
584d6b92ffaSHans Petter Selasky }
585d6b92ffaSHans Petter Selasky default_symver(__ibv_destroy_srq, ibv_destroy_srq);
586d6b92ffaSHans Petter Selasky 
__ibv_create_qp(struct ibv_pd * pd,struct ibv_qp_init_attr * qp_init_attr)587d6b92ffaSHans Petter Selasky struct ibv_qp *__ibv_create_qp(struct ibv_pd *pd,
588d6b92ffaSHans Petter Selasky 			       struct ibv_qp_init_attr *qp_init_attr)
589d6b92ffaSHans Petter Selasky {
590d6b92ffaSHans Petter Selasky 	struct ibv_qp *qp = pd->context->ops.create_qp(pd, qp_init_attr);
591d6b92ffaSHans Petter Selasky 
592d6b92ffaSHans Petter Selasky 	if (qp) {
593d6b92ffaSHans Petter Selasky 		qp->context    	     = pd->context;
594d6b92ffaSHans Petter Selasky 		qp->qp_context 	     = qp_init_attr->qp_context;
595d6b92ffaSHans Petter Selasky 		qp->pd         	     = pd;
596d6b92ffaSHans Petter Selasky 		qp->send_cq    	     = qp_init_attr->send_cq;
597d6b92ffaSHans Petter Selasky 		qp->recv_cq    	     = qp_init_attr->recv_cq;
598d6b92ffaSHans Petter Selasky 		qp->srq        	     = qp_init_attr->srq;
599d6b92ffaSHans Petter Selasky 		qp->qp_type          = qp_init_attr->qp_type;
600d6b92ffaSHans Petter Selasky 		qp->state	     = IBV_QPS_RESET;
601d6b92ffaSHans Petter Selasky 		qp->events_completed = 0;
602d6b92ffaSHans Petter Selasky 		pthread_mutex_init(&qp->mutex, NULL);
603d6b92ffaSHans Petter Selasky 		pthread_cond_init(&qp->cond, NULL);
604d6b92ffaSHans Petter Selasky 	}
605d6b92ffaSHans Petter Selasky 
606d6b92ffaSHans Petter Selasky 	return qp;
607d6b92ffaSHans Petter Selasky }
608d6b92ffaSHans Petter Selasky default_symver(__ibv_create_qp, ibv_create_qp);
609d6b92ffaSHans Petter Selasky 
__ibv_query_qp(struct ibv_qp * qp,struct ibv_qp_attr * attr,int attr_mask,struct ibv_qp_init_attr * init_attr)610d6b92ffaSHans Petter Selasky int __ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
611d6b92ffaSHans Petter Selasky 		   int attr_mask,
612d6b92ffaSHans Petter Selasky 		   struct ibv_qp_init_attr *init_attr)
613d6b92ffaSHans Petter Selasky {
614d6b92ffaSHans Petter Selasky 	int ret;
615d6b92ffaSHans Petter Selasky 
616d6b92ffaSHans Petter Selasky 	ret = qp->context->ops.query_qp(qp, attr, attr_mask, init_attr);
617d6b92ffaSHans Petter Selasky 	if (ret)
618d6b92ffaSHans Petter Selasky 		return ret;
619d6b92ffaSHans Petter Selasky 
620d6b92ffaSHans Petter Selasky 	if (attr_mask & IBV_QP_STATE)
621d6b92ffaSHans Petter Selasky 		qp->state = attr->qp_state;
622d6b92ffaSHans Petter Selasky 
623d6b92ffaSHans Petter Selasky 	return 0;
624d6b92ffaSHans Petter Selasky }
625d6b92ffaSHans Petter Selasky default_symver(__ibv_query_qp, ibv_query_qp);
626d6b92ffaSHans Petter Selasky 
__ibv_modify_qp(struct ibv_qp * qp,struct ibv_qp_attr * attr,int attr_mask)627d6b92ffaSHans Petter Selasky int __ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
628d6b92ffaSHans Petter Selasky 		    int attr_mask)
629d6b92ffaSHans Petter Selasky {
630d6b92ffaSHans Petter Selasky 	int ret;
631d6b92ffaSHans Petter Selasky 
632d6b92ffaSHans Petter Selasky 	ret = qp->context->ops.modify_qp(qp, attr, attr_mask);
633d6b92ffaSHans Petter Selasky 	if (ret)
634d6b92ffaSHans Petter Selasky 		return ret;
635d6b92ffaSHans Petter Selasky 
636d6b92ffaSHans Petter Selasky 	if (attr_mask & IBV_QP_STATE)
637d6b92ffaSHans Petter Selasky 		qp->state = attr->qp_state;
638d6b92ffaSHans Petter Selasky 
639d6b92ffaSHans Petter Selasky 	return 0;
640d6b92ffaSHans Petter Selasky }
641d6b92ffaSHans Petter Selasky default_symver(__ibv_modify_qp, ibv_modify_qp);
642d6b92ffaSHans Petter Selasky 
__ibv_destroy_qp(struct ibv_qp * qp)643d6b92ffaSHans Petter Selasky int __ibv_destroy_qp(struct ibv_qp *qp)
644d6b92ffaSHans Petter Selasky {
645d6b92ffaSHans Petter Selasky 	return qp->context->ops.destroy_qp(qp);
646d6b92ffaSHans Petter Selasky }
647d6b92ffaSHans Petter Selasky default_symver(__ibv_destroy_qp, ibv_destroy_qp);
648d6b92ffaSHans Petter Selasky 
__ibv_create_ah(struct ibv_pd * pd,struct ibv_ah_attr * attr)649d6b92ffaSHans Petter Selasky struct ibv_ah *__ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr)
650d6b92ffaSHans Petter Selasky {
651d6b92ffaSHans Petter Selasky 	struct ibv_ah *ah = pd->context->ops.create_ah(pd, attr);
652d6b92ffaSHans Petter Selasky 
653d6b92ffaSHans Petter Selasky 	if (ah) {
654d6b92ffaSHans Petter Selasky 		ah->context = pd->context;
655d6b92ffaSHans Petter Selasky 		ah->pd      = pd;
656d6b92ffaSHans Petter Selasky 	}
657d6b92ffaSHans Petter Selasky 
658d6b92ffaSHans Petter Selasky 	return ah;
659d6b92ffaSHans Petter Selasky }
660d6b92ffaSHans Petter Selasky default_symver(__ibv_create_ah, ibv_create_ah);
661d6b92ffaSHans Petter Selasky 
662d6b92ffaSHans Petter Selasky /* GID types as appear in sysfs, no change is expected as of ABI
663d6b92ffaSHans Petter Selasky  * compatibility.
664d6b92ffaSHans Petter Selasky  */
665d6b92ffaSHans Petter Selasky #define V1_TYPE "IB/RoCE v1"
666d6b92ffaSHans Petter Selasky #define V2_TYPE "RoCE v2"
ibv_query_gid_type(struct ibv_context * context,uint8_t port_num,unsigned int index,enum ibv_gid_type * type)667d6b92ffaSHans Petter Selasky int ibv_query_gid_type(struct ibv_context *context, uint8_t port_num,
668d6b92ffaSHans Petter Selasky 		       unsigned int index, enum ibv_gid_type *type)
669d6b92ffaSHans Petter Selasky {
670d6b92ffaSHans Petter Selasky 	char name[32];
671d6b92ffaSHans Petter Selasky 	char buff[11];
672d6b92ffaSHans Petter Selasky 
673d6b92ffaSHans Petter Selasky 	snprintf(name, sizeof(name), "ports/%d/gid_attrs/types/%d", port_num,
674d6b92ffaSHans Petter Selasky 		 index);
675d6b92ffaSHans Petter Selasky 
676d6b92ffaSHans Petter Selasky 	/* Reset errno so that we can rely on its value upon any error flow in
677d6b92ffaSHans Petter Selasky 	 * ibv_read_sysfs_file.
678d6b92ffaSHans Petter Selasky 	 */
679d6b92ffaSHans Petter Selasky 	errno = 0;
680d6b92ffaSHans Petter Selasky 	if (ibv_read_sysfs_file(context->device->ibdev_path, name, buff,
681d6b92ffaSHans Petter Selasky 				sizeof(buff)) <= 0) {
682d6b92ffaSHans Petter Selasky 		char *dir_path;
683d6b92ffaSHans Petter Selasky 		DIR *dir;
684d6b92ffaSHans Petter Selasky 
685d6b92ffaSHans Petter Selasky 		if (errno == EINVAL) {
686d6b92ffaSHans Petter Selasky 			/* In IB, this file doesn't exist and the kernel sets
687d6b92ffaSHans Petter Selasky 			 * errno to -EINVAL.
688d6b92ffaSHans Petter Selasky 			 */
689d6b92ffaSHans Petter Selasky 			*type = IBV_GID_TYPE_IB_ROCE_V1;
690d6b92ffaSHans Petter Selasky 			return 0;
691d6b92ffaSHans Petter Selasky 		}
692d6b92ffaSHans Petter Selasky 		if (asprintf(&dir_path, "%s/%s/%d/%s/",
693d6b92ffaSHans Petter Selasky 			     context->device->ibdev_path, "ports", port_num,
694d6b92ffaSHans Petter Selasky 			     "gid_attrs") < 0)
695d6b92ffaSHans Petter Selasky 			return -1;
696d6b92ffaSHans Petter Selasky 		dir = opendir(dir_path);
697d6b92ffaSHans Petter Selasky 		free(dir_path);
698d6b92ffaSHans Petter Selasky 		if (!dir) {
699d6b92ffaSHans Petter Selasky 			if (errno == ENOENT)
700d6b92ffaSHans Petter Selasky 				/* Assuming that if gid_attrs doesn't exist,
701d6b92ffaSHans Petter Selasky 				 * we have an old kernel and all GIDs are
702d6b92ffaSHans Petter Selasky 				 * IB/RoCE v1
703d6b92ffaSHans Petter Selasky 				 */
704d6b92ffaSHans Petter Selasky 				*type = IBV_GID_TYPE_IB_ROCE_V1;
705d6b92ffaSHans Petter Selasky 			else
706d6b92ffaSHans Petter Selasky 				return -1;
707d6b92ffaSHans Petter Selasky 		} else {
708d6b92ffaSHans Petter Selasky 			closedir(dir);
709d6b92ffaSHans Petter Selasky 			errno = EFAULT;
710d6b92ffaSHans Petter Selasky 			return -1;
711d6b92ffaSHans Petter Selasky 		}
712d6b92ffaSHans Petter Selasky 	} else {
713d6b92ffaSHans Petter Selasky 		if (!strcmp(buff, V1_TYPE)) {
714d6b92ffaSHans Petter Selasky 			*type = IBV_GID_TYPE_IB_ROCE_V1;
715d6b92ffaSHans Petter Selasky 		} else if (!strcmp(buff, V2_TYPE)) {
716d6b92ffaSHans Petter Selasky 			*type = IBV_GID_TYPE_ROCE_V2;
717d6b92ffaSHans Petter Selasky 		} else {
718d6b92ffaSHans Petter Selasky 			errno = ENOTSUP;
719d6b92ffaSHans Petter Selasky 			return -1;
720d6b92ffaSHans Petter Selasky 		}
721d6b92ffaSHans Petter Selasky 	}
722d6b92ffaSHans Petter Selasky 
723d6b92ffaSHans Petter Selasky 	return 0;
724d6b92ffaSHans Petter Selasky }
725d6b92ffaSHans Petter Selasky 
ibv_find_gid_index(struct ibv_context * context,uint8_t port_num,union ibv_gid * gid,enum ibv_gid_type gid_type)726d6b92ffaSHans Petter Selasky static int ibv_find_gid_index(struct ibv_context *context, uint8_t port_num,
727d6b92ffaSHans Petter Selasky 			      union ibv_gid *gid, enum ibv_gid_type gid_type)
728d6b92ffaSHans Petter Selasky {
729d6b92ffaSHans Petter Selasky 	enum ibv_gid_type sgid_type = 0;
730d6b92ffaSHans Petter Selasky 	union ibv_gid sgid;
731d6b92ffaSHans Petter Selasky 	int i = 0, ret;
732d6b92ffaSHans Petter Selasky 
733d6b92ffaSHans Petter Selasky 	do {
734d6b92ffaSHans Petter Selasky 		ret = ibv_query_gid(context, port_num, i, &sgid);
735d6b92ffaSHans Petter Selasky 		if (!ret) {
736d6b92ffaSHans Petter Selasky 			ret = ibv_query_gid_type(context, port_num, i,
737d6b92ffaSHans Petter Selasky 						 &sgid_type);
738d6b92ffaSHans Petter Selasky 		}
739d6b92ffaSHans Petter Selasky 		i++;
740d6b92ffaSHans Petter Selasky 	} while (!ret && (memcmp(&sgid, gid, sizeof(*gid)) ||
741d6b92ffaSHans Petter Selasky 		 (gid_type != sgid_type)));
742d6b92ffaSHans Petter Selasky 
743d6b92ffaSHans Petter Selasky 	return ret ? ret : i - 1;
744d6b92ffaSHans Petter Selasky }
745d6b92ffaSHans Petter Selasky 
map_ipv4_addr_to_ipv6(__be32 ipv4,struct in6_addr * ipv6)746d6b92ffaSHans Petter Selasky static inline void map_ipv4_addr_to_ipv6(__be32 ipv4, struct in6_addr *ipv6)
747d6b92ffaSHans Petter Selasky {
748d6b92ffaSHans Petter Selasky 	ipv6->s6_addr32[0] = 0;
749d6b92ffaSHans Petter Selasky 	ipv6->s6_addr32[1] = 0;
750d6b92ffaSHans Petter Selasky 	ipv6->s6_addr32[2] = htobe32(0x0000FFFF);
751d6b92ffaSHans Petter Selasky 	ipv6->s6_addr32[3] = ipv4;
752d6b92ffaSHans Petter Selasky }
753d6b92ffaSHans Petter Selasky 
ipv4_calc_hdr_csum(uint16_t * data,unsigned int num_hwords)754d6b92ffaSHans Petter Selasky static inline __sum16 ipv4_calc_hdr_csum(uint16_t *data, unsigned int num_hwords)
755d6b92ffaSHans Petter Selasky {
756d6b92ffaSHans Petter Selasky 	unsigned int i = 0;
757d6b92ffaSHans Petter Selasky 	uint32_t sum = 0;
758d6b92ffaSHans Petter Selasky 
759d6b92ffaSHans Petter Selasky 	for (i = 0; i < num_hwords; i++)
760d6b92ffaSHans Petter Selasky 		sum += *(data++);
761d6b92ffaSHans Petter Selasky 
762d6b92ffaSHans Petter Selasky 	sum = (sum & 0xffff) + (sum >> 16);
763d6b92ffaSHans Petter Selasky 
764d6b92ffaSHans Petter Selasky 	return (__sum16)~sum;
765d6b92ffaSHans Petter Selasky }
766d6b92ffaSHans Petter Selasky 
get_grh_header_version(struct ibv_grh * grh)767d6b92ffaSHans Petter Selasky static inline int get_grh_header_version(struct ibv_grh *grh)
768d6b92ffaSHans Petter Selasky {
769d6b92ffaSHans Petter Selasky 	int ip6h_version = (be32toh(grh->version_tclass_flow) >> 28) & 0xf;
770d6b92ffaSHans Petter Selasky 	struct ip *ip4h = (struct ip *)((void *)grh + 20);
771d6b92ffaSHans Petter Selasky 	struct ip ip4h_checked;
772d6b92ffaSHans Petter Selasky 
773d6b92ffaSHans Petter Selasky 	if (ip6h_version != 6) {
774d6b92ffaSHans Petter Selasky 		if (ip4h->ip_v == 4)
775d6b92ffaSHans Petter Selasky 			return 4;
776d6b92ffaSHans Petter Selasky 		errno = EPROTONOSUPPORT;
777d6b92ffaSHans Petter Selasky 		return -1;
778d6b92ffaSHans Petter Selasky 	}
779d6b92ffaSHans Petter Selasky 	/* version may be 6 or 4 */
780d6b92ffaSHans Petter Selasky 	if (ip4h->ip_hl != 5) /* IPv4 header length must be 5 for RoCE v2. */
781d6b92ffaSHans Petter Selasky 		return 6;
782d6b92ffaSHans Petter Selasky 	/*
783d6b92ffaSHans Petter Selasky 	* Verify checksum.
784d6b92ffaSHans Petter Selasky 	* We can't write on scattered buffers so we have to copy to temp
785d6b92ffaSHans Petter Selasky 	* buffer.
786d6b92ffaSHans Petter Selasky 	*/
787d6b92ffaSHans Petter Selasky 	memcpy(&ip4h_checked, ip4h, sizeof(ip4h_checked));
788d6b92ffaSHans Petter Selasky 	/* Need to set the checksum field (check) to 0 before re-calculating
789d6b92ffaSHans Petter Selasky 	 * the checksum.
790d6b92ffaSHans Petter Selasky 	 */
791d6b92ffaSHans Petter Selasky 	ip4h_checked.ip_sum = 0;
792d6b92ffaSHans Petter Selasky 	ip4h_checked.ip_sum = ipv4_calc_hdr_csum((uint16_t *)&ip4h_checked, 10);
793d6b92ffaSHans Petter Selasky 	/* if IPv4 header checksum is OK, believe it */
794d6b92ffaSHans Petter Selasky 	if (ip4h->ip_sum == ip4h_checked.ip_sum)
795d6b92ffaSHans Petter Selasky 		return 4;
796d6b92ffaSHans Petter Selasky 	return 6;
797d6b92ffaSHans Petter Selasky }
798d6b92ffaSHans Petter Selasky 
set_ah_attr_generic_fields(struct ibv_ah_attr * ah_attr,struct ibv_wc * wc,struct ibv_grh * grh,uint8_t port_num)799d6b92ffaSHans Petter Selasky static inline void set_ah_attr_generic_fields(struct ibv_ah_attr *ah_attr,
800d6b92ffaSHans Petter Selasky 					      struct ibv_wc *wc,
801d6b92ffaSHans Petter Selasky 					      struct ibv_grh *grh,
802d6b92ffaSHans Petter Selasky 					      uint8_t port_num)
803d6b92ffaSHans Petter Selasky {
804d6b92ffaSHans Petter Selasky 	uint32_t flow_class;
805d6b92ffaSHans Petter Selasky 
806d6b92ffaSHans Petter Selasky 	flow_class = be32toh(grh->version_tclass_flow);
807d6b92ffaSHans Petter Selasky 	ah_attr->grh.flow_label = flow_class & 0xFFFFF;
808d6b92ffaSHans Petter Selasky 	ah_attr->dlid = wc->slid;
809d6b92ffaSHans Petter Selasky 	ah_attr->sl = wc->sl;
810d6b92ffaSHans Petter Selasky 	ah_attr->src_path_bits = wc->dlid_path_bits;
811d6b92ffaSHans Petter Selasky 	ah_attr->port_num = port_num;
812d6b92ffaSHans Petter Selasky }
813d6b92ffaSHans Petter Selasky 
set_ah_attr_by_ipv4(struct ibv_context * context,struct ibv_ah_attr * ah_attr,struct ip * ip4h,uint8_t port_num)814d6b92ffaSHans Petter Selasky static inline int set_ah_attr_by_ipv4(struct ibv_context *context,
815d6b92ffaSHans Petter Selasky 				      struct ibv_ah_attr *ah_attr,
816d6b92ffaSHans Petter Selasky 				      struct ip *ip4h, uint8_t port_num)
817d6b92ffaSHans Petter Selasky {
818d6b92ffaSHans Petter Selasky 	union ibv_gid sgid;
819d6b92ffaSHans Petter Selasky 	int ret;
820d6b92ffaSHans Petter Selasky 
821d6b92ffaSHans Petter Selasky 	/* No point searching multicast GIDs in GID table */
822d6b92ffaSHans Petter Selasky 	if (IN_CLASSD(be32toh(ip4h->ip_dst.s_addr))) {
823d6b92ffaSHans Petter Selasky 		errno = EINVAL;
824d6b92ffaSHans Petter Selasky 		return -1;
825d6b92ffaSHans Petter Selasky 	}
826d6b92ffaSHans Petter Selasky 
827d6b92ffaSHans Petter Selasky 	map_ipv4_addr_to_ipv6(ip4h->ip_dst.s_addr, (struct in6_addr *)&sgid);
828d6b92ffaSHans Petter Selasky 	ret = ibv_find_gid_index(context, port_num, &sgid,
829d6b92ffaSHans Petter Selasky 				 IBV_GID_TYPE_ROCE_V2);
830d6b92ffaSHans Petter Selasky 	if (ret < 0)
831d6b92ffaSHans Petter Selasky 		return ret;
832d6b92ffaSHans Petter Selasky 
833d6b92ffaSHans Petter Selasky 	map_ipv4_addr_to_ipv6(ip4h->ip_src.s_addr,
834d6b92ffaSHans Petter Selasky 			      (struct in6_addr *)&ah_attr->grh.dgid);
835d6b92ffaSHans Petter Selasky 	ah_attr->grh.sgid_index = (uint8_t) ret;
836d6b92ffaSHans Petter Selasky 	ah_attr->grh.hop_limit = ip4h->ip_ttl;
837d6b92ffaSHans Petter Selasky 	ah_attr->grh.traffic_class = ip4h->ip_tos;
838d6b92ffaSHans Petter Selasky 
839d6b92ffaSHans Petter Selasky 	return 0;
840d6b92ffaSHans Petter Selasky }
841d6b92ffaSHans Petter Selasky 
842d6b92ffaSHans Petter Selasky #define IB_NEXT_HDR    0x1b
set_ah_attr_by_ipv6(struct ibv_context * context,struct ibv_ah_attr * ah_attr,struct ibv_grh * grh,uint8_t port_num)843d6b92ffaSHans Petter Selasky static inline int set_ah_attr_by_ipv6(struct ibv_context *context,
844d6b92ffaSHans Petter Selasky 				  struct ibv_ah_attr *ah_attr,
845d6b92ffaSHans Petter Selasky 				  struct ibv_grh *grh, uint8_t port_num)
846d6b92ffaSHans Petter Selasky {
847d6b92ffaSHans Petter Selasky 	uint32_t flow_class;
848d6b92ffaSHans Petter Selasky 	uint32_t sgid_type;
849d6b92ffaSHans Petter Selasky 	int ret;
850d6b92ffaSHans Petter Selasky 
851d6b92ffaSHans Petter Selasky 	/* No point searching multicast GIDs in GID table */
852d6b92ffaSHans Petter Selasky 	if (grh->dgid.raw[0] == 0xFF) {
853d6b92ffaSHans Petter Selasky 		errno = EINVAL;
854d6b92ffaSHans Petter Selasky 		return -1;
855d6b92ffaSHans Petter Selasky 	}
856d6b92ffaSHans Petter Selasky 
857d6b92ffaSHans Petter Selasky 	ah_attr->grh.dgid = grh->sgid;
858d6b92ffaSHans Petter Selasky 	if (grh->next_hdr == IPPROTO_UDP) {
859d6b92ffaSHans Petter Selasky 		sgid_type = IBV_GID_TYPE_ROCE_V2;
860d6b92ffaSHans Petter Selasky 	} else if (grh->next_hdr == IB_NEXT_HDR) {
861d6b92ffaSHans Petter Selasky 		sgid_type = IBV_GID_TYPE_IB_ROCE_V1;
862d6b92ffaSHans Petter Selasky 	} else {
863d6b92ffaSHans Petter Selasky 		errno = EPROTONOSUPPORT;
864d6b92ffaSHans Petter Selasky 		return -1;
865d6b92ffaSHans Petter Selasky 	}
866d6b92ffaSHans Petter Selasky 
867d6b92ffaSHans Petter Selasky 	ret = ibv_find_gid_index(context, port_num, &grh->dgid,
868d6b92ffaSHans Petter Selasky 				 sgid_type);
869d6b92ffaSHans Petter Selasky 	if (ret < 0)
870d6b92ffaSHans Petter Selasky 		return ret;
871d6b92ffaSHans Petter Selasky 
872d6b92ffaSHans Petter Selasky 	ah_attr->grh.sgid_index = (uint8_t) ret;
873d6b92ffaSHans Petter Selasky 	flow_class = be32toh(grh->version_tclass_flow);
874d6b92ffaSHans Petter Selasky 	ah_attr->grh.hop_limit = grh->hop_limit;
875d6b92ffaSHans Petter Selasky 	ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF;
876d6b92ffaSHans Petter Selasky 
877d6b92ffaSHans Petter Selasky 	return 0;
878d6b92ffaSHans Petter Selasky }
879d6b92ffaSHans Petter Selasky 
ibv_init_ah_from_wc(struct ibv_context * context,uint8_t port_num,struct ibv_wc * wc,struct ibv_grh * grh,struct ibv_ah_attr * ah_attr)880d6b92ffaSHans Petter Selasky int ibv_init_ah_from_wc(struct ibv_context *context, uint8_t port_num,
881d6b92ffaSHans Petter Selasky 			struct ibv_wc *wc, struct ibv_grh *grh,
882d6b92ffaSHans Petter Selasky 			struct ibv_ah_attr *ah_attr)
883d6b92ffaSHans Petter Selasky {
884d6b92ffaSHans Petter Selasky 	int version;
885d6b92ffaSHans Petter Selasky 	int ret = 0;
886d6b92ffaSHans Petter Selasky 
887d6b92ffaSHans Petter Selasky 	memset(ah_attr, 0, sizeof *ah_attr);
888d6b92ffaSHans Petter Selasky 	set_ah_attr_generic_fields(ah_attr, wc, grh, port_num);
889d6b92ffaSHans Petter Selasky 
890d6b92ffaSHans Petter Selasky 	if (wc->wc_flags & IBV_WC_GRH) {
891d6b92ffaSHans Petter Selasky 		ah_attr->is_global = 1;
892d6b92ffaSHans Petter Selasky 		version = get_grh_header_version(grh);
893d6b92ffaSHans Petter Selasky 
894d6b92ffaSHans Petter Selasky 		if (version == 4)
895d6b92ffaSHans Petter Selasky 			ret = set_ah_attr_by_ipv4(context, ah_attr,
896d6b92ffaSHans Petter Selasky 						  (struct ip *)((void *)grh + 20),
897d6b92ffaSHans Petter Selasky 						  port_num);
898d6b92ffaSHans Petter Selasky 		else if (version == 6)
899d6b92ffaSHans Petter Selasky 			ret = set_ah_attr_by_ipv6(context, ah_attr, grh,
900d6b92ffaSHans Petter Selasky 						  port_num);
901d6b92ffaSHans Petter Selasky 		else
902d6b92ffaSHans Petter Selasky 			ret = -1;
903d6b92ffaSHans Petter Selasky 	}
904d6b92ffaSHans Petter Selasky 
905d6b92ffaSHans Petter Selasky 	return ret;
906d6b92ffaSHans Petter Selasky }
907d6b92ffaSHans Petter Selasky 
ibv_create_ah_from_wc(struct ibv_pd * pd,struct ibv_wc * wc,struct ibv_grh * grh,uint8_t port_num)908d6b92ffaSHans Petter Selasky struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc,
909d6b92ffaSHans Petter Selasky 				     struct ibv_grh *grh, uint8_t port_num)
910d6b92ffaSHans Petter Selasky {
911d6b92ffaSHans Petter Selasky 	struct ibv_ah_attr ah_attr;
912d6b92ffaSHans Petter Selasky 	int ret;
913d6b92ffaSHans Petter Selasky 
914d6b92ffaSHans Petter Selasky 	ret = ibv_init_ah_from_wc(pd->context, port_num, wc, grh, &ah_attr);
915d6b92ffaSHans Petter Selasky 	if (ret)
916d6b92ffaSHans Petter Selasky 		return NULL;
917d6b92ffaSHans Petter Selasky 
918d6b92ffaSHans Petter Selasky 	return ibv_create_ah(pd, &ah_attr);
919d6b92ffaSHans Petter Selasky }
920d6b92ffaSHans Petter Selasky 
__ibv_destroy_ah(struct ibv_ah * ah)921d6b92ffaSHans Petter Selasky int __ibv_destroy_ah(struct ibv_ah *ah)
922d6b92ffaSHans Petter Selasky {
923d6b92ffaSHans Petter Selasky 	return ah->context->ops.destroy_ah(ah);
924d6b92ffaSHans Petter Selasky }
925d6b92ffaSHans Petter Selasky default_symver(__ibv_destroy_ah, ibv_destroy_ah);
926d6b92ffaSHans Petter Selasky 
__ibv_attach_mcast(struct ibv_qp * qp,const union ibv_gid * gid,uint16_t lid)927d6b92ffaSHans Petter Selasky int __ibv_attach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid)
928d6b92ffaSHans Petter Selasky {
929d6b92ffaSHans Petter Selasky 	return qp->context->ops.attach_mcast(qp, gid, lid);
930d6b92ffaSHans Petter Selasky }
931d6b92ffaSHans Petter Selasky default_symver(__ibv_attach_mcast, ibv_attach_mcast);
932d6b92ffaSHans Petter Selasky 
__ibv_detach_mcast(struct ibv_qp * qp,const union ibv_gid * gid,uint16_t lid)933d6b92ffaSHans Petter Selasky int __ibv_detach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid)
934d6b92ffaSHans Petter Selasky {
935d6b92ffaSHans Petter Selasky 	return qp->context->ops.detach_mcast(qp, gid, lid);
936d6b92ffaSHans Petter Selasky }
937d6b92ffaSHans Petter Selasky default_symver(__ibv_detach_mcast, ibv_detach_mcast);
938d6b92ffaSHans Petter Selasky 
ipv6_addr_v4mapped(const struct in6_addr * a)939d6b92ffaSHans Petter Selasky static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
940d6b92ffaSHans Petter Selasky {
941d6b92ffaSHans Petter Selasky 	return IN6_IS_ADDR_V4MAPPED(a) ||
942d6b92ffaSHans Petter Selasky 		/* IPv4 encoded multicast addresses */
943d6b92ffaSHans Petter Selasky 		(a->s6_addr32[0]  == htobe32(0xff0e0000) &&
944d6b92ffaSHans Petter Selasky 		((a->s6_addr32[1] |
945d6b92ffaSHans Petter Selasky 		 (a->s6_addr32[2] ^ htobe32(0x0000ffff))) == 0UL));
946d6b92ffaSHans Petter Selasky }
947d6b92ffaSHans Petter Selasky 
948d6b92ffaSHans Petter Selasky struct peer_address {
949d6b92ffaSHans Petter Selasky 	void *address;
950d6b92ffaSHans Petter Selasky 	uint32_t size;
951d6b92ffaSHans Petter Selasky };
952d6b92ffaSHans Petter Selasky 
create_peer_from_gid(int family,void * raw_gid,struct peer_address * peer_address)953d6b92ffaSHans Petter Selasky static inline int create_peer_from_gid(int family, void *raw_gid,
954d6b92ffaSHans Petter Selasky 				       struct peer_address *peer_address)
955d6b92ffaSHans Petter Selasky {
956d6b92ffaSHans Petter Selasky 	switch (family) {
957d6b92ffaSHans Petter Selasky 	case AF_INET:
958d6b92ffaSHans Petter Selasky 		peer_address->address = raw_gid + 12;
959d6b92ffaSHans Petter Selasky 		peer_address->size = 4;
960d6b92ffaSHans Petter Selasky 		break;
961d6b92ffaSHans Petter Selasky 	case AF_INET6:
962d6b92ffaSHans Petter Selasky 		peer_address->address = raw_gid;
963d6b92ffaSHans Petter Selasky 		peer_address->size = 16;
964d6b92ffaSHans Petter Selasky 		break;
965d6b92ffaSHans Petter Selasky 	default:
966d6b92ffaSHans Petter Selasky 		return -1;
967d6b92ffaSHans Petter Selasky 	}
968d6b92ffaSHans Petter Selasky 
969d6b92ffaSHans Petter Selasky 	return 0;
970d6b92ffaSHans Petter Selasky }
971d6b92ffaSHans Petter Selasky 
972d6b92ffaSHans Petter Selasky #define NEIGH_GET_DEFAULT_TIMEOUT_MS 3000
ibv_resolve_eth_l2_from_gid(struct ibv_context * context,struct ibv_ah_attr * attr,uint8_t eth_mac[ETHERNET_LL_SIZE],uint16_t * vid)973d6b92ffaSHans Petter Selasky int ibv_resolve_eth_l2_from_gid(struct ibv_context *context,
974d6b92ffaSHans Petter Selasky 				struct ibv_ah_attr *attr,
975d6b92ffaSHans Petter Selasky 				uint8_t eth_mac[ETHERNET_LL_SIZE],
976d6b92ffaSHans Petter Selasky 				uint16_t *vid)
977d6b92ffaSHans Petter Selasky {
978d6b92ffaSHans Petter Selasky #ifndef NRESOLVE_NEIGH
979d6b92ffaSHans Petter Selasky 	int dst_family;
980d6b92ffaSHans Petter Selasky 	int src_family;
981d6b92ffaSHans Petter Selasky 	int oif;
982d6b92ffaSHans Petter Selasky 	struct get_neigh_handler neigh_handler;
983d6b92ffaSHans Petter Selasky 	union ibv_gid sgid;
984d6b92ffaSHans Petter Selasky 	int ether_len;
985d6b92ffaSHans Petter Selasky 	struct peer_address src;
986d6b92ffaSHans Petter Selasky 	struct peer_address dst;
987d6b92ffaSHans Petter Selasky 	uint16_t ret_vid;
988d6b92ffaSHans Petter Selasky 	int ret = -EINVAL;
989d6b92ffaSHans Petter Selasky 	int err;
990d6b92ffaSHans Petter Selasky 
991d6b92ffaSHans Petter Selasky 	err = ibv_query_gid(context, attr->port_num,
992d6b92ffaSHans Petter Selasky 			    attr->grh.sgid_index, &sgid);
993d6b92ffaSHans Petter Selasky 
994d6b92ffaSHans Petter Selasky 	if (err)
995d6b92ffaSHans Petter Selasky 		return err;
996d6b92ffaSHans Petter Selasky 
997d6b92ffaSHans Petter Selasky 	err = neigh_init_resources(&neigh_handler,
998d6b92ffaSHans Petter Selasky 				   NEIGH_GET_DEFAULT_TIMEOUT_MS);
999d6b92ffaSHans Petter Selasky 
1000d6b92ffaSHans Petter Selasky 	if (err)
1001d6b92ffaSHans Petter Selasky 		return err;
1002d6b92ffaSHans Petter Selasky 
1003d6b92ffaSHans Petter Selasky 	dst_family = ipv6_addr_v4mapped((struct in6_addr *)attr->grh.dgid.raw) ?
1004d6b92ffaSHans Petter Selasky 			AF_INET : AF_INET6;
1005d6b92ffaSHans Petter Selasky 	src_family = ipv6_addr_v4mapped((struct in6_addr *)sgid.raw) ?
1006d6b92ffaSHans Petter Selasky 			AF_INET : AF_INET6;
1007d6b92ffaSHans Petter Selasky 
1008d6b92ffaSHans Petter Selasky 	if (create_peer_from_gid(dst_family, attr->grh.dgid.raw, &dst))
1009d6b92ffaSHans Petter Selasky 		goto free_resources;
1010d6b92ffaSHans Petter Selasky 
1011d6b92ffaSHans Petter Selasky 	if (create_peer_from_gid(src_family, &sgid.raw, &src))
1012d6b92ffaSHans Petter Selasky 		goto free_resources;
1013d6b92ffaSHans Petter Selasky 
1014d6b92ffaSHans Petter Selasky 	if (neigh_set_dst(&neigh_handler, dst_family, dst.address,
1015d6b92ffaSHans Petter Selasky 			  dst.size))
1016d6b92ffaSHans Petter Selasky 		goto free_resources;
1017d6b92ffaSHans Petter Selasky 
1018d6b92ffaSHans Petter Selasky 	if (neigh_set_src(&neigh_handler, src_family, src.address,
1019d6b92ffaSHans Petter Selasky 			  src.size))
1020d6b92ffaSHans Petter Selasky 		goto free_resources;
1021d6b92ffaSHans Petter Selasky 
1022d6b92ffaSHans Petter Selasky 	oif = neigh_get_oif_from_src(&neigh_handler);
1023d6b92ffaSHans Petter Selasky 
1024d6b92ffaSHans Petter Selasky 	if (oif > 0)
1025d6b92ffaSHans Petter Selasky 		neigh_set_oif(&neigh_handler, oif);
1026d6b92ffaSHans Petter Selasky 	else
1027d6b92ffaSHans Petter Selasky 		goto free_resources;
1028d6b92ffaSHans Petter Selasky 
1029d6b92ffaSHans Petter Selasky 	ret = -EHOSTUNREACH;
1030d6b92ffaSHans Petter Selasky 
1031d6b92ffaSHans Petter Selasky 	/* blocking call */
1032d6b92ffaSHans Petter Selasky 	if (process_get_neigh(&neigh_handler))
1033d6b92ffaSHans Petter Selasky 		goto free_resources;
1034d6b92ffaSHans Petter Selasky 
1035d6b92ffaSHans Petter Selasky 	ret_vid = neigh_get_vlan_id_from_dev(&neigh_handler);
1036d6b92ffaSHans Petter Selasky 
1037d6b92ffaSHans Petter Selasky 	if (ret_vid <= 0xfff)
1038d6b92ffaSHans Petter Selasky 		neigh_set_vlan_id(&neigh_handler, ret_vid);
1039d6b92ffaSHans Petter Selasky 
1040d6b92ffaSHans Petter Selasky 	/* We are using only Ethernet here */
1041d6b92ffaSHans Petter Selasky 	ether_len = neigh_get_ll(&neigh_handler,
1042d6b92ffaSHans Petter Selasky 				 eth_mac,
1043d6b92ffaSHans Petter Selasky 				 sizeof(uint8_t) * ETHERNET_LL_SIZE);
1044d6b92ffaSHans Petter Selasky 
1045d6b92ffaSHans Petter Selasky 	if (ether_len <= 0)
1046d6b92ffaSHans Petter Selasky 		goto free_resources;
1047d6b92ffaSHans Petter Selasky 
1048d6b92ffaSHans Petter Selasky 	*vid = ret_vid;
1049d6b92ffaSHans Petter Selasky 
1050d6b92ffaSHans Petter Selasky 	ret = 0;
1051d6b92ffaSHans Petter Selasky 
1052d6b92ffaSHans Petter Selasky free_resources:
1053d6b92ffaSHans Petter Selasky 	neigh_free_resources(&neigh_handler);
1054d6b92ffaSHans Petter Selasky 
1055d6b92ffaSHans Petter Selasky 	return ret;
1056d6b92ffaSHans Petter Selasky #else
1057d6b92ffaSHans Petter Selasky 	return -ENOSYS;
1058d6b92ffaSHans Petter Selasky #endif
1059d6b92ffaSHans Petter Selasky }
1060