xref: /freebsd/contrib/ofed/librdmacm/cma.c (revision a687910fc4352117413b8e0275383e4c687d4c4c)
1d6b92ffaSHans Petter Selasky /*
2d6b92ffaSHans Petter Selasky  * Copyright (c) 2005-2014 Intel Corporation.  All rights reserved.
3d6b92ffaSHans Petter Selasky  *
4d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
5d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
6d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
7d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
8d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
9d6b92ffaSHans Petter Selasky  *
10d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
11d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
12d6b92ffaSHans Petter Selasky  *     conditions are met:
13d6b92ffaSHans Petter Selasky  *
14d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
15d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
16d6b92ffaSHans Petter Selasky  *        disclaimer.
17d6b92ffaSHans Petter Selasky  *
18d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
19d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
20d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
21d6b92ffaSHans Petter Selasky  *        provided with the distribution.
22d6b92ffaSHans Petter Selasky  *
23d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30d6b92ffaSHans Petter Selasky  * SOFTWARE.
31d6b92ffaSHans Petter Selasky  */
32d6b92ffaSHans Petter Selasky 
33d6b92ffaSHans Petter Selasky #include <config.h>
34d6b92ffaSHans Petter Selasky 
35d6b92ffaSHans Petter Selasky #include <stdlib.h>
36d6b92ffaSHans Petter Selasky #include <string.h>
37d6b92ffaSHans Petter Selasky #include <glob.h>
38d6b92ffaSHans Petter Selasky #include <stdio.h>
39d6b92ffaSHans Petter Selasky #include <fcntl.h>
40d6b92ffaSHans Petter Selasky #include <errno.h>
41d6b92ffaSHans Petter Selasky #include <stdint.h>
42d6b92ffaSHans Petter Selasky #include <poll.h>
43d6b92ffaSHans Petter Selasky #include <unistd.h>
44d6b92ffaSHans Petter Selasky #include <pthread.h>
45d6b92ffaSHans Petter Selasky #include <infiniband/endian.h>
46d6b92ffaSHans Petter Selasky #include <stddef.h>
47d6b92ffaSHans Petter Selasky #include <netdb.h>
48d6b92ffaSHans Petter Selasky #include <syslog.h>
49d6b92ffaSHans Petter Selasky #include <limits.h>
50d6b92ffaSHans Petter Selasky 
51d6b92ffaSHans Petter Selasky #include "cma.h"
52d6b92ffaSHans Petter Selasky #include "indexer.h"
53d6b92ffaSHans Petter Selasky #include <infiniband/driver.h>
54d6b92ffaSHans Petter Selasky #include <infiniband/marshall.h>
55d6b92ffaSHans Petter Selasky #include <rdma/rdma_cma.h>
56d6b92ffaSHans Petter Selasky #include <rdma/rdma_cma_abi.h>
57d6b92ffaSHans Petter Selasky #include <rdma/rdma_verbs.h>
58d6b92ffaSHans Petter Selasky #include <infiniband/ib.h>
59d6b92ffaSHans Petter Selasky 
60d6b92ffaSHans Petter Selasky #define CMA_INIT_CMD(req, req_size, op)		\
61d6b92ffaSHans Petter Selasky do {						\
62d6b92ffaSHans Petter Selasky 	memset(req, 0, req_size);		\
63d6b92ffaSHans Petter Selasky 	(req)->cmd = UCMA_CMD_##op;		\
64d6b92ffaSHans Petter Selasky 	(req)->in  = req_size - sizeof(struct ucma_abi_cmd_hdr); \
65d6b92ffaSHans Petter Selasky } while (0)
66d6b92ffaSHans Petter Selasky 
67d6b92ffaSHans Petter Selasky #define CMA_INIT_CMD_RESP(req, req_size, op, resp, resp_size) \
68d6b92ffaSHans Petter Selasky do {						\
69d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD(req, req_size, op);	\
70d6b92ffaSHans Petter Selasky 	(req)->out = resp_size;			\
71d6b92ffaSHans Petter Selasky 	(req)->response = (uintptr_t) (resp);	\
72d6b92ffaSHans Petter Selasky } while (0)
73d6b92ffaSHans Petter Selasky 
74d6b92ffaSHans Petter Selasky struct cma_port {
75d6b92ffaSHans Petter Selasky 	uint8_t			link_layer;
76d6b92ffaSHans Petter Selasky };
77d6b92ffaSHans Petter Selasky 
78d6b92ffaSHans Petter Selasky struct cma_device {
79d6b92ffaSHans Petter Selasky 	struct ibv_context *verbs;
80d6b92ffaSHans Petter Selasky 	struct ibv_pd	   *pd;
81d6b92ffaSHans Petter Selasky 	struct ibv_xrcd    *xrcd;
82d6b92ffaSHans Petter Selasky 	struct cma_port    *port;
83d6b92ffaSHans Petter Selasky 	__be64		    guid;
84d6b92ffaSHans Petter Selasky 	int		    port_cnt;
85d6b92ffaSHans Petter Selasky 	int		    refcnt;
86d6b92ffaSHans Petter Selasky 	int		    max_qpsize;
87d6b92ffaSHans Petter Selasky 	uint8_t		    max_initiator_depth;
88d6b92ffaSHans Petter Selasky 	uint8_t		    max_responder_resources;
89d6b92ffaSHans Petter Selasky };
90d6b92ffaSHans Petter Selasky 
91d6b92ffaSHans Petter Selasky struct cma_id_private {
92d6b92ffaSHans Petter Selasky 	struct rdma_cm_id	id;
93d6b92ffaSHans Petter Selasky 	struct cma_device	*cma_dev;
94d6b92ffaSHans Petter Selasky 	void			*connect;
95d6b92ffaSHans Petter Selasky 	size_t			connect_len;
96d6b92ffaSHans Petter Selasky 	int			events_completed;
97d6b92ffaSHans Petter Selasky 	int			connect_error;
98d6b92ffaSHans Petter Selasky 	int			sync;
99d6b92ffaSHans Petter Selasky 	pthread_cond_t		cond;
100d6b92ffaSHans Petter Selasky 	pthread_mutex_t		mut;
101d6b92ffaSHans Petter Selasky 	uint32_t		handle;
102d6b92ffaSHans Petter Selasky 	struct cma_multicast	*mc_list;
103d6b92ffaSHans Petter Selasky 	struct ibv_qp_init_attr	*qp_init_attr;
104d6b92ffaSHans Petter Selasky 	uint8_t			initiator_depth;
105d6b92ffaSHans Petter Selasky 	uint8_t			responder_resources;
106d6b92ffaSHans Petter Selasky };
107d6b92ffaSHans Petter Selasky 
108d6b92ffaSHans Petter Selasky struct cma_multicast {
109d6b92ffaSHans Petter Selasky 	struct cma_multicast  *next;
110d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
111d6b92ffaSHans Petter Selasky 	void		*context;
112d6b92ffaSHans Petter Selasky 	int		events_completed;
113d6b92ffaSHans Petter Selasky 	pthread_cond_t	cond;
114d6b92ffaSHans Petter Selasky 	uint32_t	handle;
115d6b92ffaSHans Petter Selasky 	union ibv_gid	mgid;
116d6b92ffaSHans Petter Selasky 	uint16_t	mlid;
117d6b92ffaSHans Petter Selasky 	struct sockaddr_storage addr;
118d6b92ffaSHans Petter Selasky };
119d6b92ffaSHans Petter Selasky 
120d6b92ffaSHans Petter Selasky struct cma_event {
121d6b92ffaSHans Petter Selasky 	struct rdma_cm_event	event;
122d6b92ffaSHans Petter Selasky 	uint8_t			private_data[RDMA_MAX_PRIVATE_DATA];
123d6b92ffaSHans Petter Selasky 	struct cma_id_private	*id_priv;
124d6b92ffaSHans Petter Selasky 	struct cma_multicast	*mc;
125d6b92ffaSHans Petter Selasky };
126d6b92ffaSHans Petter Selasky 
127d6b92ffaSHans Petter Selasky static struct cma_device *cma_dev_array;
128d6b92ffaSHans Petter Selasky static int cma_dev_cnt;
129d6b92ffaSHans Petter Selasky static int cma_init_cnt;
130d6b92ffaSHans Petter Selasky static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
131d6b92ffaSHans Petter Selasky static int abi_ver = RDMA_USER_CM_MAX_ABI_VERSION;
132d6b92ffaSHans Petter Selasky int af_ib_support;
133d6b92ffaSHans Petter Selasky static struct index_map ucma_idm;
134d6b92ffaSHans Petter Selasky static fastlock_t idm_lock;
135d6b92ffaSHans Petter Selasky 
check_abi_version(void)136d6b92ffaSHans Petter Selasky static int check_abi_version(void)
137d6b92ffaSHans Petter Selasky {
138d6b92ffaSHans Petter Selasky 	char value[8];
139d6b92ffaSHans Petter Selasky 
140d6b92ffaSHans Petter Selasky 	if ((ibv_read_sysfs_file(ibv_get_sysfs_path(),
141d6b92ffaSHans Petter Selasky 				 "class/misc/rdma_cm/abi_version",
142d6b92ffaSHans Petter Selasky 				 value, sizeof value) < 0) &&
143d6b92ffaSHans Petter Selasky 	    (ibv_read_sysfs_file(ibv_get_sysfs_path(),
144d6b92ffaSHans Petter Selasky 				 "class/infiniband_ucma/abi_version",
145d6b92ffaSHans Petter Selasky 				 value, sizeof value) < 0)) {
146d6b92ffaSHans Petter Selasky 		/*
147d6b92ffaSHans Petter Selasky 		 * Older version of Linux do not have class/misc.  To support
148d6b92ffaSHans Petter Selasky 		 * backports, assume the most recent version of the ABI.  If
149d6b92ffaSHans Petter Selasky 		 * we're wrong, we'll simply fail later when calling the ABI.
150d6b92ffaSHans Petter Selasky 		 */
151d6b92ffaSHans Petter Selasky 		return 0;
152d6b92ffaSHans Petter Selasky 	}
153d6b92ffaSHans Petter Selasky 
154d6b92ffaSHans Petter Selasky 	abi_ver = strtol(value, NULL, 10);
155d6b92ffaSHans Petter Selasky 	if (abi_ver < RDMA_USER_CM_MIN_ABI_VERSION ||
156d6b92ffaSHans Petter Selasky 	    abi_ver > RDMA_USER_CM_MAX_ABI_VERSION) {
157d6b92ffaSHans Petter Selasky 		return -1;
158d6b92ffaSHans Petter Selasky 	}
159d6b92ffaSHans Petter Selasky 	return 0;
160d6b92ffaSHans Petter Selasky }
161d6b92ffaSHans Petter Selasky 
162d6b92ffaSHans Petter Selasky /*
163d6b92ffaSHans Petter Selasky  * This function is called holding the mutex lock
164d6b92ffaSHans Petter Selasky  * cma_dev_cnt must be set before calling this function to
165d6b92ffaSHans Petter Selasky  * ensure that the lock is not acquired recursively.
166d6b92ffaSHans Petter Selasky  */
ucma_set_af_ib_support(void)167d6b92ffaSHans Petter Selasky static void ucma_set_af_ib_support(void)
168d6b92ffaSHans Petter Selasky {
169d6b92ffaSHans Petter Selasky 	struct rdma_cm_id *id;
170d6b92ffaSHans Petter Selasky 	struct sockaddr_ib sib;
171d6b92ffaSHans Petter Selasky 	int ret;
172d6b92ffaSHans Petter Selasky 
173d6b92ffaSHans Petter Selasky 	ret = rdma_create_id(NULL, &id, NULL, RDMA_PS_IB);
174d6b92ffaSHans Petter Selasky 	if (ret)
175d6b92ffaSHans Petter Selasky 		return;
176d6b92ffaSHans Petter Selasky 
177d6b92ffaSHans Petter Selasky 	memset(&sib, 0, sizeof sib);
178d6b92ffaSHans Petter Selasky 	sib.sib_family = AF_IB;
179d6b92ffaSHans Petter Selasky 	sib.sib_sid = htobe64(RDMA_IB_IP_PS_TCP);
180d6b92ffaSHans Petter Selasky 	sib.sib_sid_mask = htobe64(RDMA_IB_IP_PS_MASK);
181d6b92ffaSHans Petter Selasky 	af_ib_support = 1;
182d6b92ffaSHans Petter Selasky 	ret = rdma_bind_addr(id, (struct sockaddr *) &sib);
183d6b92ffaSHans Petter Selasky 	af_ib_support = !ret;
184d6b92ffaSHans Petter Selasky 
185d6b92ffaSHans Petter Selasky 	rdma_destroy_id(id);
186d6b92ffaSHans Petter Selasky }
187d6b92ffaSHans Petter Selasky 
ucma_init(void)188d6b92ffaSHans Petter Selasky int ucma_init(void)
189d6b92ffaSHans Petter Selasky {
190d6b92ffaSHans Petter Selasky 	struct ibv_device **dev_list = NULL;
191d6b92ffaSHans Petter Selasky 	int i, ret, dev_cnt;
192d6b92ffaSHans Petter Selasky 
193d6b92ffaSHans Petter Selasky 	/* Quick check without lock to see if we're already initialized */
194d6b92ffaSHans Petter Selasky 	if (cma_dev_cnt)
195d6b92ffaSHans Petter Selasky 		return 0;
196d6b92ffaSHans Petter Selasky 
197d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&mut);
198d6b92ffaSHans Petter Selasky 	if (cma_dev_cnt) {
199d6b92ffaSHans Petter Selasky 		pthread_mutex_unlock(&mut);
200d6b92ffaSHans Petter Selasky 		return 0;
201d6b92ffaSHans Petter Selasky 	}
202d6b92ffaSHans Petter Selasky 
203d6b92ffaSHans Petter Selasky 	fastlock_init(&idm_lock);
204d6b92ffaSHans Petter Selasky 	ret = check_abi_version();
205d6b92ffaSHans Petter Selasky 	if (ret)
206d6b92ffaSHans Petter Selasky 		goto err1;
207d6b92ffaSHans Petter Selasky 
208d6b92ffaSHans Petter Selasky 	dev_list = ibv_get_device_list(&dev_cnt);
209d6b92ffaSHans Petter Selasky 	if (!dev_list) {
210d6b92ffaSHans Petter Selasky 		ret = ERR(ENODEV);
211d6b92ffaSHans Petter Selasky 		goto err1;
212d6b92ffaSHans Petter Selasky 	}
213d6b92ffaSHans Petter Selasky 
214d6b92ffaSHans Petter Selasky 	if (!dev_cnt) {
215d6b92ffaSHans Petter Selasky 		ret = ERR(ENODEV);
216d6b92ffaSHans Petter Selasky 		goto err2;
217d6b92ffaSHans Petter Selasky 	}
218d6b92ffaSHans Petter Selasky 
219d6b92ffaSHans Petter Selasky 	cma_dev_array = calloc(dev_cnt, sizeof(*cma_dev_array));
220d6b92ffaSHans Petter Selasky 	if (!cma_dev_array) {
221d6b92ffaSHans Petter Selasky 		ret = ERR(ENOMEM);
222d6b92ffaSHans Petter Selasky 		goto err2;
223d6b92ffaSHans Petter Selasky 	}
224d6b92ffaSHans Petter Selasky 
225d6b92ffaSHans Petter Selasky 	for (i = 0; dev_list[i]; i++)
226d6b92ffaSHans Petter Selasky 		cma_dev_array[i].guid = ibv_get_device_guid(dev_list[i]);
227d6b92ffaSHans Petter Selasky 
228d6b92ffaSHans Petter Selasky 	cma_dev_cnt = dev_cnt;
229d6b92ffaSHans Petter Selasky 	ucma_set_af_ib_support();
230d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&mut);
231d6b92ffaSHans Petter Selasky 	ibv_free_device_list(dev_list);
232d6b92ffaSHans Petter Selasky 	return 0;
233d6b92ffaSHans Petter Selasky 
234d6b92ffaSHans Petter Selasky err2:
235d6b92ffaSHans Petter Selasky 	ibv_free_device_list(dev_list);
236d6b92ffaSHans Petter Selasky err1:
237d6b92ffaSHans Petter Selasky 	fastlock_destroy(&idm_lock);
238d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&mut);
239d6b92ffaSHans Petter Selasky 	return ret;
240d6b92ffaSHans Petter Selasky }
241d6b92ffaSHans Petter Selasky 
ucma_open_device(__be64 guid)242d6b92ffaSHans Petter Selasky static struct ibv_context *ucma_open_device(__be64 guid)
243d6b92ffaSHans Petter Selasky {
244d6b92ffaSHans Petter Selasky 	struct ibv_device **dev_list;
245d6b92ffaSHans Petter Selasky 	struct ibv_context *verbs = NULL;
246d6b92ffaSHans Petter Selasky 	int i;
247d6b92ffaSHans Petter Selasky 
248d6b92ffaSHans Petter Selasky 	dev_list = ibv_get_device_list(NULL);
249d6b92ffaSHans Petter Selasky 	if (!dev_list) {
250d6b92ffaSHans Petter Selasky 		return NULL;
251d6b92ffaSHans Petter Selasky 	}
252d6b92ffaSHans Petter Selasky 
253d6b92ffaSHans Petter Selasky 	for (i = 0; dev_list[i]; i++) {
254d6b92ffaSHans Petter Selasky 		if (ibv_get_device_guid(dev_list[i]) == guid) {
255d6b92ffaSHans Petter Selasky 			verbs = ibv_open_device(dev_list[i]);
256d6b92ffaSHans Petter Selasky 			break;
257d6b92ffaSHans Petter Selasky 		}
258d6b92ffaSHans Petter Selasky 	}
259d6b92ffaSHans Petter Selasky 
260d6b92ffaSHans Petter Selasky 	ibv_free_device_list(dev_list);
261d6b92ffaSHans Petter Selasky 	return verbs;
262d6b92ffaSHans Petter Selasky }
263d6b92ffaSHans Petter Selasky 
ucma_init_device(struct cma_device * cma_dev)264d6b92ffaSHans Petter Selasky static int ucma_init_device(struct cma_device *cma_dev)
265d6b92ffaSHans Petter Selasky {
266d6b92ffaSHans Petter Selasky 	struct ibv_port_attr port_attr;
267d6b92ffaSHans Petter Selasky 	struct ibv_device_attr attr;
268d6b92ffaSHans Petter Selasky 	int i, ret;
269d6b92ffaSHans Petter Selasky 
270d6b92ffaSHans Petter Selasky 	if (cma_dev->verbs)
271d6b92ffaSHans Petter Selasky 		return 0;
272d6b92ffaSHans Petter Selasky 
273d6b92ffaSHans Petter Selasky 	cma_dev->verbs = ucma_open_device(cma_dev->guid);
274d6b92ffaSHans Petter Selasky 	if (!cma_dev->verbs)
275d6b92ffaSHans Petter Selasky 		return ERR(ENODEV);
276d6b92ffaSHans Petter Selasky 
277d6b92ffaSHans Petter Selasky 	ret = ibv_query_device(cma_dev->verbs, &attr);
278d6b92ffaSHans Petter Selasky 	if (ret) {
279d6b92ffaSHans Petter Selasky 		ret = ERR(ret);
280d6b92ffaSHans Petter Selasky 		goto err;
281d6b92ffaSHans Petter Selasky 	}
282d6b92ffaSHans Petter Selasky 
283d6b92ffaSHans Petter Selasky 	cma_dev->port = malloc(sizeof(*cma_dev->port) * attr.phys_port_cnt);
284d6b92ffaSHans Petter Selasky 	if (!cma_dev->port) {
285d6b92ffaSHans Petter Selasky 		ret = ERR(ENOMEM);
286d6b92ffaSHans Petter Selasky 		goto err;
287d6b92ffaSHans Petter Selasky 	}
288d6b92ffaSHans Petter Selasky 
289d6b92ffaSHans Petter Selasky 	for (i = 1; i <= attr.phys_port_cnt; i++) {
290d6b92ffaSHans Petter Selasky 		if (ibv_query_port(cma_dev->verbs, i, &port_attr))
291d6b92ffaSHans Petter Selasky 			cma_dev->port[i - 1].link_layer = IBV_LINK_LAYER_UNSPECIFIED;
292d6b92ffaSHans Petter Selasky 		else
293d6b92ffaSHans Petter Selasky 			cma_dev->port[i - 1].link_layer = port_attr.link_layer;
294d6b92ffaSHans Petter Selasky 	}
295d6b92ffaSHans Petter Selasky 
296d6b92ffaSHans Petter Selasky 	cma_dev->port_cnt = attr.phys_port_cnt;
297d6b92ffaSHans Petter Selasky 	cma_dev->max_qpsize = attr.max_qp_wr;
298d6b92ffaSHans Petter Selasky 	cma_dev->max_initiator_depth = (uint8_t) attr.max_qp_init_rd_atom;
299d6b92ffaSHans Petter Selasky 	cma_dev->max_responder_resources = (uint8_t) attr.max_qp_rd_atom;
300d6b92ffaSHans Petter Selasky 	cma_init_cnt++;
301d6b92ffaSHans Petter Selasky 	return 0;
302d6b92ffaSHans Petter Selasky 
303d6b92ffaSHans Petter Selasky err:
304d6b92ffaSHans Petter Selasky 	ibv_close_device(cma_dev->verbs);
305d6b92ffaSHans Petter Selasky 	cma_dev->verbs = NULL;
306d6b92ffaSHans Petter Selasky 	return ret;
307d6b92ffaSHans Petter Selasky }
308d6b92ffaSHans Petter Selasky 
ucma_init_all(void)309d6b92ffaSHans Petter Selasky static int ucma_init_all(void)
310d6b92ffaSHans Petter Selasky {
311d6b92ffaSHans Petter Selasky 	int i, ret = 0;
312d6b92ffaSHans Petter Selasky 
313d6b92ffaSHans Petter Selasky 	if (!cma_dev_cnt) {
314d6b92ffaSHans Petter Selasky 		ret = ucma_init();
315d6b92ffaSHans Petter Selasky 		if (ret)
316d6b92ffaSHans Petter Selasky 			return ret;
317d6b92ffaSHans Petter Selasky 	}
318d6b92ffaSHans Petter Selasky 
319d6b92ffaSHans Petter Selasky 	if (cma_init_cnt == cma_dev_cnt)
320d6b92ffaSHans Petter Selasky 		return 0;
321d6b92ffaSHans Petter Selasky 
322d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&mut);
323d6b92ffaSHans Petter Selasky 	for (i = 0; i < cma_dev_cnt; i++) {
324d6b92ffaSHans Petter Selasky 		ret = ucma_init_device(&cma_dev_array[i]);
325d6b92ffaSHans Petter Selasky 		if (ret)
326d6b92ffaSHans Petter Selasky 			break;
327d6b92ffaSHans Petter Selasky 	}
328d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&mut);
329d6b92ffaSHans Petter Selasky 	return ret;
330d6b92ffaSHans Petter Selasky }
331d6b92ffaSHans Petter Selasky 
rdma_get_devices(int * num_devices)332d6b92ffaSHans Petter Selasky struct ibv_context **rdma_get_devices(int *num_devices)
333d6b92ffaSHans Petter Selasky {
334d6b92ffaSHans Petter Selasky 	struct ibv_context **devs = NULL;
335d6b92ffaSHans Petter Selasky 	int i;
336d6b92ffaSHans Petter Selasky 
337d6b92ffaSHans Petter Selasky 	if (ucma_init_all())
338d6b92ffaSHans Petter Selasky 		goto out;
339d6b92ffaSHans Petter Selasky 
340d6b92ffaSHans Petter Selasky 	devs = malloc(sizeof(*devs) * (cma_dev_cnt + 1));
341d6b92ffaSHans Petter Selasky 	if (!devs)
342d6b92ffaSHans Petter Selasky 		goto out;
343d6b92ffaSHans Petter Selasky 
344d6b92ffaSHans Petter Selasky 	for (i = 0; i < cma_dev_cnt; i++)
345d6b92ffaSHans Petter Selasky 		devs[i] = cma_dev_array[i].verbs;
346d6b92ffaSHans Petter Selasky 	devs[i] = NULL;
347d6b92ffaSHans Petter Selasky out:
348d6b92ffaSHans Petter Selasky 	if (num_devices)
349d6b92ffaSHans Petter Selasky 		*num_devices = devs ? cma_dev_cnt : 0;
350d6b92ffaSHans Petter Selasky 	return devs;
351d6b92ffaSHans Petter Selasky }
352d6b92ffaSHans Petter Selasky 
rdma_free_devices(struct ibv_context ** list)353d6b92ffaSHans Petter Selasky void rdma_free_devices(struct ibv_context **list)
354d6b92ffaSHans Petter Selasky {
355d6b92ffaSHans Petter Selasky 	free(list);
356d6b92ffaSHans Petter Selasky }
357d6b92ffaSHans Petter Selasky 
rdma_create_event_channel(void)358d6b92ffaSHans Petter Selasky struct rdma_event_channel *rdma_create_event_channel(void)
359d6b92ffaSHans Petter Selasky {
360d6b92ffaSHans Petter Selasky 	struct rdma_event_channel *channel;
361d6b92ffaSHans Petter Selasky 
362d6b92ffaSHans Petter Selasky 	if (ucma_init())
363d6b92ffaSHans Petter Selasky 		return NULL;
364d6b92ffaSHans Petter Selasky 
365d6b92ffaSHans Petter Selasky 	channel = malloc(sizeof(*channel));
366d6b92ffaSHans Petter Selasky 	if (!channel)
367d6b92ffaSHans Petter Selasky 		return NULL;
368d6b92ffaSHans Petter Selasky 
369d6b92ffaSHans Petter Selasky 	channel->fd = open("/dev/rdma_cm", O_RDWR | O_CLOEXEC);
370d6b92ffaSHans Petter Selasky 	if (channel->fd < 0) {
371d6b92ffaSHans Petter Selasky 		goto err;
372d6b92ffaSHans Petter Selasky 	}
373d6b92ffaSHans Petter Selasky 	return channel;
374d6b92ffaSHans Petter Selasky err:
375d6b92ffaSHans Petter Selasky 	free(channel);
376d6b92ffaSHans Petter Selasky 	return NULL;
377d6b92ffaSHans Petter Selasky }
378d6b92ffaSHans Petter Selasky 
rdma_destroy_event_channel(struct rdma_event_channel * channel)379d6b92ffaSHans Petter Selasky void rdma_destroy_event_channel(struct rdma_event_channel *channel)
380d6b92ffaSHans Petter Selasky {
381d6b92ffaSHans Petter Selasky 	close(channel->fd);
382d6b92ffaSHans Petter Selasky 	free(channel);
383d6b92ffaSHans Petter Selasky }
384d6b92ffaSHans Petter Selasky 
ucma_get_device(struct cma_id_private * id_priv,__be64 guid)385d6b92ffaSHans Petter Selasky static int ucma_get_device(struct cma_id_private *id_priv, __be64 guid)
386d6b92ffaSHans Petter Selasky {
387d6b92ffaSHans Petter Selasky 	struct cma_device *cma_dev;
388d6b92ffaSHans Petter Selasky 	int i, ret;
389d6b92ffaSHans Petter Selasky 
390d6b92ffaSHans Petter Selasky 	for (i = 0; i < cma_dev_cnt; i++) {
391d6b92ffaSHans Petter Selasky 		cma_dev = &cma_dev_array[i];
392d6b92ffaSHans Petter Selasky 		if (cma_dev->guid == guid)
393d6b92ffaSHans Petter Selasky 			goto match;
394d6b92ffaSHans Petter Selasky 	}
395d6b92ffaSHans Petter Selasky 
396d6b92ffaSHans Petter Selasky 	return ERR(ENODEV);
397d6b92ffaSHans Petter Selasky match:
398d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&mut);
399d6b92ffaSHans Petter Selasky 	if ((ret = ucma_init_device(cma_dev)))
400d6b92ffaSHans Petter Selasky 		goto out;
401d6b92ffaSHans Petter Selasky 
402d6b92ffaSHans Petter Selasky 	if (!cma_dev->refcnt++) {
403d6b92ffaSHans Petter Selasky 		cma_dev->pd = ibv_alloc_pd(cma_dev->verbs);
404d6b92ffaSHans Petter Selasky 		if (!cma_dev->pd) {
405d6b92ffaSHans Petter Selasky 			cma_dev->refcnt--;
406d6b92ffaSHans Petter Selasky 			ret = ERR(ENOMEM);
407d6b92ffaSHans Petter Selasky 			goto out;
408d6b92ffaSHans Petter Selasky 		}
409d6b92ffaSHans Petter Selasky 	}
410d6b92ffaSHans Petter Selasky 	id_priv->cma_dev = cma_dev;
411d6b92ffaSHans Petter Selasky 	id_priv->id.verbs = cma_dev->verbs;
412d6b92ffaSHans Petter Selasky 	id_priv->id.pd = cma_dev->pd;
413d6b92ffaSHans Petter Selasky out:
414d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&mut);
415d6b92ffaSHans Petter Selasky 	return ret;
416d6b92ffaSHans Petter Selasky }
417d6b92ffaSHans Petter Selasky 
ucma_put_device(struct cma_device * cma_dev)418d6b92ffaSHans Petter Selasky static void ucma_put_device(struct cma_device *cma_dev)
419d6b92ffaSHans Petter Selasky {
420d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&mut);
421d6b92ffaSHans Petter Selasky 	if (!--cma_dev->refcnt) {
422d6b92ffaSHans Petter Selasky 		ibv_dealloc_pd(cma_dev->pd);
423d6b92ffaSHans Petter Selasky 		if (cma_dev->xrcd)
424d6b92ffaSHans Petter Selasky 			ibv_close_xrcd(cma_dev->xrcd);
425d6b92ffaSHans Petter Selasky 	}
426d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&mut);
427d6b92ffaSHans Petter Selasky }
428d6b92ffaSHans Petter Selasky 
ucma_get_xrcd(struct cma_device * cma_dev)429d6b92ffaSHans Petter Selasky static struct ibv_xrcd *ucma_get_xrcd(struct cma_device *cma_dev)
430d6b92ffaSHans Petter Selasky {
431d6b92ffaSHans Petter Selasky 	struct ibv_xrcd_init_attr attr;
432d6b92ffaSHans Petter Selasky 
433d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&mut);
434d6b92ffaSHans Petter Selasky 	if (!cma_dev->xrcd) {
435d6b92ffaSHans Petter Selasky 		memset(&attr, 0, sizeof attr);
436d6b92ffaSHans Petter Selasky 		attr.comp_mask = IBV_XRCD_INIT_ATTR_FD | IBV_XRCD_INIT_ATTR_OFLAGS;
437d6b92ffaSHans Petter Selasky 		attr.fd = -1;
438d6b92ffaSHans Petter Selasky 		attr.oflags = O_CREAT;
439d6b92ffaSHans Petter Selasky 		cma_dev->xrcd = ibv_open_xrcd(cma_dev->verbs, &attr);
440d6b92ffaSHans Petter Selasky 	}
441d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&mut);
442d6b92ffaSHans Petter Selasky 	return cma_dev->xrcd;
443d6b92ffaSHans Petter Selasky }
444d6b92ffaSHans Petter Selasky 
ucma_insert_id(struct cma_id_private * id_priv)445d6b92ffaSHans Petter Selasky static void ucma_insert_id(struct cma_id_private *id_priv)
446d6b92ffaSHans Petter Selasky {
447d6b92ffaSHans Petter Selasky 	fastlock_acquire(&idm_lock);
448d6b92ffaSHans Petter Selasky 	idm_set(&ucma_idm, id_priv->handle, id_priv);
449d6b92ffaSHans Petter Selasky 	fastlock_release(&idm_lock);
450d6b92ffaSHans Petter Selasky }
451d6b92ffaSHans Petter Selasky 
ucma_remove_id(struct cma_id_private * id_priv)452d6b92ffaSHans Petter Selasky static void ucma_remove_id(struct cma_id_private *id_priv)
453d6b92ffaSHans Petter Selasky {
454d6b92ffaSHans Petter Selasky 	if (id_priv->handle <= IDX_MAX_INDEX)
455d6b92ffaSHans Petter Selasky 		idm_clear(&ucma_idm, id_priv->handle);
456d6b92ffaSHans Petter Selasky }
457d6b92ffaSHans Petter Selasky 
ucma_lookup_id(int handle)458d6b92ffaSHans Petter Selasky static struct cma_id_private *ucma_lookup_id(int handle)
459d6b92ffaSHans Petter Selasky {
460d6b92ffaSHans Petter Selasky 	return idm_lookup(&ucma_idm, handle);
461d6b92ffaSHans Petter Selasky }
462d6b92ffaSHans Petter Selasky 
ucma_free_id(struct cma_id_private * id_priv)463d6b92ffaSHans Petter Selasky static void ucma_free_id(struct cma_id_private *id_priv)
464d6b92ffaSHans Petter Selasky {
465d6b92ffaSHans Petter Selasky 	ucma_remove_id(id_priv);
466d6b92ffaSHans Petter Selasky 	if (id_priv->cma_dev)
467d6b92ffaSHans Petter Selasky 		ucma_put_device(id_priv->cma_dev);
468d6b92ffaSHans Petter Selasky 	pthread_cond_destroy(&id_priv->cond);
469d6b92ffaSHans Petter Selasky 	pthread_mutex_destroy(&id_priv->mut);
470d6b92ffaSHans Petter Selasky 	if (id_priv->id.route.path_rec)
471d6b92ffaSHans Petter Selasky 		free(id_priv->id.route.path_rec);
472d6b92ffaSHans Petter Selasky 
473d6b92ffaSHans Petter Selasky 	if (id_priv->sync)
474d6b92ffaSHans Petter Selasky 		rdma_destroy_event_channel(id_priv->id.channel);
475d6b92ffaSHans Petter Selasky 	if (id_priv->connect_len)
476d6b92ffaSHans Petter Selasky 		free(id_priv->connect);
477d6b92ffaSHans Petter Selasky 	free(id_priv);
478d6b92ffaSHans Petter Selasky }
479d6b92ffaSHans Petter Selasky 
ucma_alloc_id(struct rdma_event_channel * channel,void * context,enum rdma_port_space ps,enum ibv_qp_type qp_type)480d6b92ffaSHans Petter Selasky static struct cma_id_private *ucma_alloc_id(struct rdma_event_channel *channel,
481d6b92ffaSHans Petter Selasky 					    void *context,
482d6b92ffaSHans Petter Selasky 					    enum rdma_port_space ps,
483d6b92ffaSHans Petter Selasky 					    enum ibv_qp_type qp_type)
484d6b92ffaSHans Petter Selasky {
485d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
486d6b92ffaSHans Petter Selasky 
487d6b92ffaSHans Petter Selasky 	id_priv = calloc(1, sizeof(*id_priv));
488d6b92ffaSHans Petter Selasky 	if (!id_priv)
489d6b92ffaSHans Petter Selasky 		return NULL;
490d6b92ffaSHans Petter Selasky 
491d6b92ffaSHans Petter Selasky 	id_priv->id.context = context;
492d6b92ffaSHans Petter Selasky 	id_priv->id.ps = ps;
493d6b92ffaSHans Petter Selasky 	id_priv->id.qp_type = qp_type;
494d6b92ffaSHans Petter Selasky 	id_priv->handle = 0xFFFFFFFF;
495d6b92ffaSHans Petter Selasky 
496d6b92ffaSHans Petter Selasky 	if (!channel) {
497d6b92ffaSHans Petter Selasky 		id_priv->id.channel = rdma_create_event_channel();
498d6b92ffaSHans Petter Selasky 		if (!id_priv->id.channel)
499d6b92ffaSHans Petter Selasky 			goto err;
500d6b92ffaSHans Petter Selasky 		id_priv->sync = 1;
501d6b92ffaSHans Petter Selasky 	} else {
502d6b92ffaSHans Petter Selasky 		id_priv->id.channel = channel;
503d6b92ffaSHans Petter Selasky 	}
504d6b92ffaSHans Petter Selasky 
505*a687910fSSean Lim 	if (pthread_mutex_init(&id_priv->mut, NULL))
506*a687910fSSean Lim 		goto err;
507d6b92ffaSHans Petter Selasky 	if (pthread_cond_init(&id_priv->cond, NULL))
508d6b92ffaSHans Petter Selasky 		goto err;
509d6b92ffaSHans Petter Selasky 
510d6b92ffaSHans Petter Selasky 	return id_priv;
511d6b92ffaSHans Petter Selasky 
512d6b92ffaSHans Petter Selasky err:	ucma_free_id(id_priv);
513d6b92ffaSHans Petter Selasky 	return NULL;
514d6b92ffaSHans Petter Selasky }
515d6b92ffaSHans Petter Selasky 
rdma_create_id2(struct rdma_event_channel * channel,struct rdma_cm_id ** id,void * context,enum rdma_port_space ps,enum ibv_qp_type qp_type)516d6b92ffaSHans Petter Selasky static int rdma_create_id2(struct rdma_event_channel *channel,
517d6b92ffaSHans Petter Selasky 			   struct rdma_cm_id **id, void *context,
518d6b92ffaSHans Petter Selasky 			   enum rdma_port_space ps, enum ibv_qp_type qp_type)
519d6b92ffaSHans Petter Selasky {
520d6b92ffaSHans Petter Selasky 	struct ucma_abi_create_id_resp resp;
521d6b92ffaSHans Petter Selasky 	struct ucma_abi_create_id cmd;
522d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
523d6b92ffaSHans Petter Selasky 	int ret;
524d6b92ffaSHans Petter Selasky 
525d6b92ffaSHans Petter Selasky 	ret = ucma_init();
526d6b92ffaSHans Petter Selasky 	if (ret)
527d6b92ffaSHans Petter Selasky 		return ret;
528d6b92ffaSHans Petter Selasky 
529d6b92ffaSHans Petter Selasky 	id_priv = ucma_alloc_id(channel, context, ps, qp_type);
530d6b92ffaSHans Petter Selasky 	if (!id_priv)
531d6b92ffaSHans Petter Selasky 		return ERR(ENOMEM);
532d6b92ffaSHans Petter Selasky 
533d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD_RESP(&cmd, sizeof cmd, CREATE_ID, &resp, sizeof resp);
534d6b92ffaSHans Petter Selasky 	cmd.uid = (uintptr_t) id_priv;
535d6b92ffaSHans Petter Selasky 	cmd.ps = ps;
536d6b92ffaSHans Petter Selasky 	cmd.qp_type = qp_type;
537d6b92ffaSHans Petter Selasky 
538d6b92ffaSHans Petter Selasky 	ret = write(id_priv->id.channel->fd, &cmd, sizeof cmd);
539d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
540d6b92ffaSHans Petter Selasky 		goto err;
541d6b92ffaSHans Petter Selasky 
542d6b92ffaSHans Petter Selasky 	VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
543d6b92ffaSHans Petter Selasky 
544d6b92ffaSHans Petter Selasky 	id_priv->handle = resp.id;
545d6b92ffaSHans Petter Selasky 	ucma_insert_id(id_priv);
546d6b92ffaSHans Petter Selasky 	*id = &id_priv->id;
547d6b92ffaSHans Petter Selasky 	return 0;
548d6b92ffaSHans Petter Selasky 
549d6b92ffaSHans Petter Selasky err:	ucma_free_id(id_priv);
550d6b92ffaSHans Petter Selasky 	return ret;
551d6b92ffaSHans Petter Selasky }
552d6b92ffaSHans Petter Selasky 
rdma_create_id(struct rdma_event_channel * channel,struct rdma_cm_id ** id,void * context,enum rdma_port_space ps)553d6b92ffaSHans Petter Selasky int rdma_create_id(struct rdma_event_channel *channel,
554d6b92ffaSHans Petter Selasky 		   struct rdma_cm_id **id, void *context,
555d6b92ffaSHans Petter Selasky 		   enum rdma_port_space ps)
556d6b92ffaSHans Petter Selasky {
557d6b92ffaSHans Petter Selasky 	enum ibv_qp_type qp_type;
558d6b92ffaSHans Petter Selasky 
559d6b92ffaSHans Petter Selasky 	qp_type = (ps == RDMA_PS_IPOIB || ps == RDMA_PS_UDP) ?
560d6b92ffaSHans Petter Selasky 		  IBV_QPT_UD : IBV_QPT_RC;
561d6b92ffaSHans Petter Selasky 	return rdma_create_id2(channel, id, context, ps, qp_type);
562d6b92ffaSHans Petter Selasky }
563d6b92ffaSHans Petter Selasky 
ucma_destroy_kern_id(int fd,uint32_t handle)564d6b92ffaSHans Petter Selasky static int ucma_destroy_kern_id(int fd, uint32_t handle)
565d6b92ffaSHans Petter Selasky {
566d6b92ffaSHans Petter Selasky 	struct ucma_abi_destroy_id_resp resp;
567d6b92ffaSHans Petter Selasky 	struct ucma_abi_destroy_id cmd;
568d6b92ffaSHans Petter Selasky 	int ret;
569d6b92ffaSHans Petter Selasky 
570d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD_RESP(&cmd, sizeof cmd, DESTROY_ID, &resp, sizeof resp);
571d6b92ffaSHans Petter Selasky 	cmd.id = handle;
572d6b92ffaSHans Petter Selasky 
573d6b92ffaSHans Petter Selasky 	ret = write(fd, &cmd, sizeof cmd);
574d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
575d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
576d6b92ffaSHans Petter Selasky 
577d6b92ffaSHans Petter Selasky 	VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
578d6b92ffaSHans Petter Selasky 
579d6b92ffaSHans Petter Selasky 	return resp.events_reported;
580d6b92ffaSHans Petter Selasky }
581d6b92ffaSHans Petter Selasky 
rdma_destroy_id(struct rdma_cm_id * id)582d6b92ffaSHans Petter Selasky int rdma_destroy_id(struct rdma_cm_id *id)
583d6b92ffaSHans Petter Selasky {
584d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
585d6b92ffaSHans Petter Selasky 	int ret;
586d6b92ffaSHans Petter Selasky 
587d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
588d6b92ffaSHans Petter Selasky 	ret = ucma_destroy_kern_id(id->channel->fd, id_priv->handle);
589d6b92ffaSHans Petter Selasky 	if (ret < 0)
590d6b92ffaSHans Petter Selasky 		return ret;
591d6b92ffaSHans Petter Selasky 
592d6b92ffaSHans Petter Selasky 	if (id_priv->id.event)
593d6b92ffaSHans Petter Selasky 		rdma_ack_cm_event(id_priv->id.event);
594d6b92ffaSHans Petter Selasky 
595d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&id_priv->mut);
596d6b92ffaSHans Petter Selasky 	while (id_priv->events_completed < ret)
597d6b92ffaSHans Petter Selasky 		pthread_cond_wait(&id_priv->cond, &id_priv->mut);
598d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&id_priv->mut);
599d6b92ffaSHans Petter Selasky 
600d6b92ffaSHans Petter Selasky 	ucma_free_id(id_priv);
601d6b92ffaSHans Petter Selasky 	return 0;
602d6b92ffaSHans Petter Selasky }
603d6b92ffaSHans Petter Selasky 
ucma_addrlen(struct sockaddr * addr)604d6b92ffaSHans Petter Selasky int ucma_addrlen(struct sockaddr *addr)
605d6b92ffaSHans Petter Selasky {
606d6b92ffaSHans Petter Selasky 	if (!addr)
607d6b92ffaSHans Petter Selasky 		return 0;
608d6b92ffaSHans Petter Selasky 
609d6b92ffaSHans Petter Selasky 	switch (addr->sa_family) {
610d6b92ffaSHans Petter Selasky 	case PF_INET:
611d6b92ffaSHans Petter Selasky 		return sizeof(struct sockaddr_in);
612d6b92ffaSHans Petter Selasky 	case PF_INET6:
613d6b92ffaSHans Petter Selasky 		return sizeof(struct sockaddr_in6);
614d6b92ffaSHans Petter Selasky 	case PF_IB:
615d6b92ffaSHans Petter Selasky 		return af_ib_support ? sizeof(struct sockaddr_ib) : 0;
616d6b92ffaSHans Petter Selasky 	default:
617d6b92ffaSHans Petter Selasky 		return 0;
618d6b92ffaSHans Petter Selasky 	}
619d6b92ffaSHans Petter Selasky }
620d6b92ffaSHans Petter Selasky 
ucma_query_addr(struct rdma_cm_id * id)621d6b92ffaSHans Petter Selasky static int ucma_query_addr(struct rdma_cm_id *id)
622d6b92ffaSHans Petter Selasky {
623d6b92ffaSHans Petter Selasky 	struct ucma_abi_query_addr_resp resp;
624d6b92ffaSHans Petter Selasky 	struct ucma_abi_query cmd;
625d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
626d6b92ffaSHans Petter Selasky 	int ret;
627d6b92ffaSHans Petter Selasky 
628d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD_RESP(&cmd, sizeof cmd, QUERY, &resp, sizeof resp);
629d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
630d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
631d6b92ffaSHans Petter Selasky 	cmd.option = UCMA_QUERY_ADDR;
632d6b92ffaSHans Petter Selasky 
633d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
634d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
635d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
636d6b92ffaSHans Petter Selasky 
637d6b92ffaSHans Petter Selasky 	VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
638d6b92ffaSHans Petter Selasky 
639d6b92ffaSHans Petter Selasky 	memcpy(&id->route.addr.src_addr, &resp.src_addr, resp.src_size);
640d6b92ffaSHans Petter Selasky 	memcpy(&id->route.addr.dst_addr, &resp.dst_addr, resp.dst_size);
641d6b92ffaSHans Petter Selasky 
642d6b92ffaSHans Petter Selasky 	if (!id_priv->cma_dev && resp.node_guid) {
643d6b92ffaSHans Petter Selasky 		ret = ucma_get_device(id_priv, resp.node_guid);
644d6b92ffaSHans Petter Selasky 		if (ret)
645d6b92ffaSHans Petter Selasky 			return ret;
646d6b92ffaSHans Petter Selasky 		id->port_num = resp.port_num;
647d6b92ffaSHans Petter Selasky 		id->route.addr.addr.ibaddr.pkey = resp.pkey;
648d6b92ffaSHans Petter Selasky 	}
649d6b92ffaSHans Petter Selasky 
650d6b92ffaSHans Petter Selasky 	return 0;
651d6b92ffaSHans Petter Selasky }
652d6b92ffaSHans Petter Selasky 
ucma_query_gid(struct rdma_cm_id * id)653d6b92ffaSHans Petter Selasky static int ucma_query_gid(struct rdma_cm_id *id)
654d6b92ffaSHans Petter Selasky {
655d6b92ffaSHans Petter Selasky 	struct ucma_abi_query_addr_resp resp;
656d6b92ffaSHans Petter Selasky 	struct ucma_abi_query cmd;
657d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
658d6b92ffaSHans Petter Selasky 	struct sockaddr_ib *sib;
659d6b92ffaSHans Petter Selasky 	int ret;
660d6b92ffaSHans Petter Selasky 
661d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD_RESP(&cmd, sizeof cmd, QUERY, &resp, sizeof resp);
662d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
663d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
664d6b92ffaSHans Petter Selasky 	cmd.option = UCMA_QUERY_GID;
665d6b92ffaSHans Petter Selasky 
666d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
667d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
668d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
669d6b92ffaSHans Petter Selasky 
670d6b92ffaSHans Petter Selasky 	VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
671d6b92ffaSHans Petter Selasky 
672d6b92ffaSHans Petter Selasky 	sib = (struct sockaddr_ib *) &resp.src_addr;
673d6b92ffaSHans Petter Selasky 	memcpy(id->route.addr.addr.ibaddr.sgid.raw, sib->sib_addr.sib_raw,
674d6b92ffaSHans Petter Selasky 	       sizeof id->route.addr.addr.ibaddr.sgid);
675d6b92ffaSHans Petter Selasky 
676d6b92ffaSHans Petter Selasky 	sib = (struct sockaddr_ib *) &resp.dst_addr;
677d6b92ffaSHans Petter Selasky 	memcpy(id->route.addr.addr.ibaddr.dgid.raw, sib->sib_addr.sib_raw,
678d6b92ffaSHans Petter Selasky 	       sizeof id->route.addr.addr.ibaddr.dgid);
679d6b92ffaSHans Petter Selasky 
680d6b92ffaSHans Petter Selasky 	return 0;
681d6b92ffaSHans Petter Selasky }
682d6b92ffaSHans Petter Selasky 
ucma_convert_path(struct ibv_path_data * path_data,struct ibv_sa_path_rec * sa_path)683d6b92ffaSHans Petter Selasky static void ucma_convert_path(struct ibv_path_data *path_data,
684d6b92ffaSHans Petter Selasky 			      struct ibv_sa_path_rec *sa_path)
685d6b92ffaSHans Petter Selasky {
686d6b92ffaSHans Petter Selasky 	uint32_t fl_hop;
687d6b92ffaSHans Petter Selasky 
688d6b92ffaSHans Petter Selasky 	sa_path->dgid = path_data->path.dgid;
689d6b92ffaSHans Petter Selasky 	sa_path->sgid = path_data->path.sgid;
690d6b92ffaSHans Petter Selasky 	sa_path->dlid = path_data->path.dlid;
691d6b92ffaSHans Petter Selasky 	sa_path->slid = path_data->path.slid;
692d6b92ffaSHans Petter Selasky 	sa_path->raw_traffic = 0;
693d6b92ffaSHans Petter Selasky 
694d6b92ffaSHans Petter Selasky 	fl_hop = be32toh(path_data->path.flowlabel_hoplimit);
695d6b92ffaSHans Petter Selasky 	sa_path->flow_label = htobe32(fl_hop >> 8);
696d6b92ffaSHans Petter Selasky 	sa_path->hop_limit = (uint8_t) fl_hop;
697d6b92ffaSHans Petter Selasky 
698d6b92ffaSHans Petter Selasky 	sa_path->traffic_class = path_data->path.tclass;
699d6b92ffaSHans Petter Selasky 	sa_path->reversible = path_data->path.reversible_numpath >> 7;
700d6b92ffaSHans Petter Selasky 	sa_path->numb_path = 1;
701d6b92ffaSHans Petter Selasky 	sa_path->pkey = path_data->path.pkey;
702d6b92ffaSHans Petter Selasky 	sa_path->sl = be16toh(path_data->path.qosclass_sl) & 0xF;
703d6b92ffaSHans Petter Selasky 	sa_path->mtu_selector = 2;	/* exactly */
704d6b92ffaSHans Petter Selasky 	sa_path->mtu = path_data->path.mtu & 0x1F;
705d6b92ffaSHans Petter Selasky 	sa_path->rate_selector = 2;
706d6b92ffaSHans Petter Selasky 	sa_path->rate = path_data->path.rate & 0x1F;
707d6b92ffaSHans Petter Selasky 	sa_path->packet_life_time_selector = 2;
708d6b92ffaSHans Petter Selasky 	sa_path->packet_life_time = path_data->path.packetlifetime & 0x1F;
709d6b92ffaSHans Petter Selasky 
710d6b92ffaSHans Petter Selasky 	sa_path->preference = (uint8_t) path_data->flags;
711d6b92ffaSHans Petter Selasky }
712d6b92ffaSHans Petter Selasky 
ucma_query_path(struct rdma_cm_id * id)713d6b92ffaSHans Petter Selasky static int ucma_query_path(struct rdma_cm_id *id)
714d6b92ffaSHans Petter Selasky {
715d6b92ffaSHans Petter Selasky 	struct ucma_abi_query_path_resp *resp;
716d6b92ffaSHans Petter Selasky 	struct ucma_abi_query cmd;
717d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
718d6b92ffaSHans Petter Selasky 	int ret, i, size;
719d6b92ffaSHans Petter Selasky 
720d6b92ffaSHans Petter Selasky 	size = sizeof(*resp) + sizeof(struct ibv_path_data) * 6;
721d6b92ffaSHans Petter Selasky 	resp = alloca(size);
722d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD_RESP(&cmd, sizeof cmd, QUERY, resp, size);
723d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
724d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
725d6b92ffaSHans Petter Selasky 	cmd.option = UCMA_QUERY_PATH;
726d6b92ffaSHans Petter Selasky 
727d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
728d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
729d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
730d6b92ffaSHans Petter Selasky 
731d6b92ffaSHans Petter Selasky 	VALGRIND_MAKE_MEM_DEFINED(resp, size);
732d6b92ffaSHans Petter Selasky 
733d6b92ffaSHans Petter Selasky 	if (resp->num_paths) {
734d6b92ffaSHans Petter Selasky 		id->route.path_rec = malloc(sizeof(*id->route.path_rec) *
735d6b92ffaSHans Petter Selasky 					    resp->num_paths);
736d6b92ffaSHans Petter Selasky 		if (!id->route.path_rec)
737d6b92ffaSHans Petter Selasky 			return ERR(ENOMEM);
738d6b92ffaSHans Petter Selasky 
739d6b92ffaSHans Petter Selasky 		id->route.num_paths = resp->num_paths;
740d6b92ffaSHans Petter Selasky 		for (i = 0; i < resp->num_paths; i++)
741d6b92ffaSHans Petter Selasky 			ucma_convert_path(&resp->path_data[i], &id->route.path_rec[i]);
742d6b92ffaSHans Petter Selasky 	}
743d6b92ffaSHans Petter Selasky 
744d6b92ffaSHans Petter Selasky 	return 0;
745d6b92ffaSHans Petter Selasky }
746d6b92ffaSHans Petter Selasky 
ucma_query_route(struct rdma_cm_id * id)747d6b92ffaSHans Petter Selasky static int ucma_query_route(struct rdma_cm_id *id)
748d6b92ffaSHans Petter Selasky {
749d6b92ffaSHans Petter Selasky 	struct ucma_abi_query_route_resp resp;
750d6b92ffaSHans Petter Selasky 	struct ucma_abi_query cmd;
751d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
752d6b92ffaSHans Petter Selasky 	int ret, i;
753d6b92ffaSHans Petter Selasky 
754d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD_RESP(&cmd, sizeof cmd, QUERY_ROUTE, &resp, sizeof resp);
755d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
756d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
757d6b92ffaSHans Petter Selasky 
758d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
759d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
760d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
761d6b92ffaSHans Petter Selasky 
762d6b92ffaSHans Petter Selasky 	VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
763d6b92ffaSHans Petter Selasky 
764d6b92ffaSHans Petter Selasky 	if (resp.num_paths) {
765d6b92ffaSHans Petter Selasky 		id->route.path_rec = malloc(sizeof(*id->route.path_rec) *
766d6b92ffaSHans Petter Selasky 					    resp.num_paths);
767d6b92ffaSHans Petter Selasky 		if (!id->route.path_rec)
768d6b92ffaSHans Petter Selasky 			return ERR(ENOMEM);
769d6b92ffaSHans Petter Selasky 
770d6b92ffaSHans Petter Selasky 		id->route.num_paths = resp.num_paths;
771d6b92ffaSHans Petter Selasky 		for (i = 0; i < resp.num_paths; i++)
772d6b92ffaSHans Petter Selasky 			ibv_copy_path_rec_from_kern(&id->route.path_rec[i],
773d6b92ffaSHans Petter Selasky 						    &resp.ib_route[i]);
774d6b92ffaSHans Petter Selasky 	}
775d6b92ffaSHans Petter Selasky 
776d6b92ffaSHans Petter Selasky 	memcpy(id->route.addr.addr.ibaddr.sgid.raw, resp.ib_route[0].sgid,
777d6b92ffaSHans Petter Selasky 	       sizeof id->route.addr.addr.ibaddr.sgid);
778d6b92ffaSHans Petter Selasky 	memcpy(id->route.addr.addr.ibaddr.dgid.raw, resp.ib_route[0].dgid,
779d6b92ffaSHans Petter Selasky 	       sizeof id->route.addr.addr.ibaddr.dgid);
780d6b92ffaSHans Petter Selasky 	id->route.addr.addr.ibaddr.pkey = resp.ib_route[0].pkey;
781d6b92ffaSHans Petter Selasky 	memcpy(&id->route.addr.src_addr, &resp.src_addr,
782d6b92ffaSHans Petter Selasky 	       sizeof resp.src_addr);
783d6b92ffaSHans Petter Selasky 	memcpy(&id->route.addr.dst_addr, &resp.dst_addr,
784d6b92ffaSHans Petter Selasky 	       sizeof resp.dst_addr);
785d6b92ffaSHans Petter Selasky 
786d6b92ffaSHans Petter Selasky 	if (!id_priv->cma_dev && resp.node_guid) {
787d6b92ffaSHans Petter Selasky 		ret = ucma_get_device(id_priv, resp.node_guid);
788d6b92ffaSHans Petter Selasky 		if (ret)
789d6b92ffaSHans Petter Selasky 			return ret;
790d6b92ffaSHans Petter Selasky 		id_priv->id.port_num = resp.port_num;
791d6b92ffaSHans Petter Selasky 	}
792d6b92ffaSHans Petter Selasky 
793d6b92ffaSHans Petter Selasky 	return 0;
794d6b92ffaSHans Petter Selasky }
795d6b92ffaSHans Petter Selasky 
rdma_bind_addr2(struct rdma_cm_id * id,struct sockaddr * addr,socklen_t addrlen)796d6b92ffaSHans Petter Selasky static int rdma_bind_addr2(struct rdma_cm_id *id, struct sockaddr *addr,
797d6b92ffaSHans Petter Selasky 			   socklen_t addrlen)
798d6b92ffaSHans Petter Selasky {
799d6b92ffaSHans Petter Selasky 	struct ucma_abi_bind cmd;
800d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
801d6b92ffaSHans Petter Selasky 	int ret;
802d6b92ffaSHans Petter Selasky 
803d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD(&cmd, sizeof cmd, BIND);
804d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
805d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
806d6b92ffaSHans Petter Selasky 	cmd.addr_size = addrlen;
807d6b92ffaSHans Petter Selasky 	memcpy(&cmd.addr, addr, addrlen);
808d6b92ffaSHans Petter Selasky 
809d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
810d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
811d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
812d6b92ffaSHans Petter Selasky 
813d6b92ffaSHans Petter Selasky 	ret = ucma_query_addr(id);
814d6b92ffaSHans Petter Selasky 	if (!ret)
815d6b92ffaSHans Petter Selasky 		ret = ucma_query_gid(id);
816d6b92ffaSHans Petter Selasky 	return ret;
817d6b92ffaSHans Petter Selasky }
818d6b92ffaSHans Petter Selasky 
rdma_bind_addr(struct rdma_cm_id * id,struct sockaddr * addr)819d6b92ffaSHans Petter Selasky int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
820d6b92ffaSHans Petter Selasky {
821d6b92ffaSHans Petter Selasky 	struct ucma_abi_bind_ip cmd;
822d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
823d6b92ffaSHans Petter Selasky 	int ret, addrlen;
824d6b92ffaSHans Petter Selasky 
825d6b92ffaSHans Petter Selasky 	addrlen = ucma_addrlen(addr);
826d6b92ffaSHans Petter Selasky 	if (!addrlen)
827d6b92ffaSHans Petter Selasky 		return ERR(EINVAL);
828d6b92ffaSHans Petter Selasky 
829d6b92ffaSHans Petter Selasky 	if (af_ib_support)
830d6b92ffaSHans Petter Selasky 		return rdma_bind_addr2(id, addr, addrlen);
831d6b92ffaSHans Petter Selasky 
832d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD(&cmd, sizeof cmd, BIND_IP);
833d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
834d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
835d6b92ffaSHans Petter Selasky 	memcpy(&cmd.addr, addr, addrlen);
836d6b92ffaSHans Petter Selasky 
837d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
838d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
839d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
840d6b92ffaSHans Petter Selasky 
841d6b92ffaSHans Petter Selasky 	return ucma_query_route(id);
842d6b92ffaSHans Petter Selasky }
843d6b92ffaSHans Petter Selasky 
ucma_complete(struct rdma_cm_id * id)844d6b92ffaSHans Petter Selasky int ucma_complete(struct rdma_cm_id *id)
845d6b92ffaSHans Petter Selasky {
846d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
847d6b92ffaSHans Petter Selasky 	int ret;
848d6b92ffaSHans Petter Selasky 
849d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
850d6b92ffaSHans Petter Selasky 	if (!id_priv->sync)
851d6b92ffaSHans Petter Selasky 		return 0;
852d6b92ffaSHans Petter Selasky 
853d6b92ffaSHans Petter Selasky 	if (id_priv->id.event) {
854d6b92ffaSHans Petter Selasky 		rdma_ack_cm_event(id_priv->id.event);
855d6b92ffaSHans Petter Selasky 		id_priv->id.event = NULL;
856d6b92ffaSHans Petter Selasky 	}
857d6b92ffaSHans Petter Selasky 
858d6b92ffaSHans Petter Selasky 	ret = rdma_get_cm_event(id_priv->id.channel, &id_priv->id.event);
859d6b92ffaSHans Petter Selasky 	if (ret)
860d6b92ffaSHans Petter Selasky 		return ret;
861d6b92ffaSHans Petter Selasky 
862d6b92ffaSHans Petter Selasky 	if (id_priv->id.event->status) {
863d6b92ffaSHans Petter Selasky 		if (id_priv->id.event->event == RDMA_CM_EVENT_REJECTED)
864d6b92ffaSHans Petter Selasky 			ret = ERR(ECONNREFUSED);
865d6b92ffaSHans Petter Selasky 		else if (id_priv->id.event->status < 0)
866d6b92ffaSHans Petter Selasky 			ret = ERR(-id_priv->id.event->status);
867d6b92ffaSHans Petter Selasky 		else
868d6b92ffaSHans Petter Selasky 			ret = ERR(-id_priv->id.event->status);
869d6b92ffaSHans Petter Selasky 	}
870d6b92ffaSHans Petter Selasky 	return ret;
871d6b92ffaSHans Petter Selasky }
872d6b92ffaSHans Petter Selasky 
rdma_resolve_addr2(struct rdma_cm_id * id,struct sockaddr * src_addr,socklen_t src_len,struct sockaddr * dst_addr,socklen_t dst_len,int timeout_ms)873d6b92ffaSHans Petter Selasky static int rdma_resolve_addr2(struct rdma_cm_id *id, struct sockaddr *src_addr,
874d6b92ffaSHans Petter Selasky 			      socklen_t src_len, struct sockaddr *dst_addr,
875d6b92ffaSHans Petter Selasky 			      socklen_t dst_len, int timeout_ms)
876d6b92ffaSHans Petter Selasky {
877d6b92ffaSHans Petter Selasky 	struct ucma_abi_resolve_addr cmd;
878d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
879d6b92ffaSHans Petter Selasky 	int ret;
880d6b92ffaSHans Petter Selasky 
881d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD(&cmd, sizeof cmd, RESOLVE_ADDR);
882d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
883d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
884d6b92ffaSHans Petter Selasky 	if ((cmd.src_size = src_len))
885d6b92ffaSHans Petter Selasky 		memcpy(&cmd.src_addr, src_addr, src_len);
886d6b92ffaSHans Petter Selasky 	memcpy(&cmd.dst_addr, dst_addr, dst_len);
887d6b92ffaSHans Petter Selasky 	cmd.dst_size = dst_len;
888d6b92ffaSHans Petter Selasky 	cmd.timeout_ms = timeout_ms;
889d6b92ffaSHans Petter Selasky 
890d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
891d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
892d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
893d6b92ffaSHans Petter Selasky 
894d6b92ffaSHans Petter Selasky 	memcpy(&id->route.addr.dst_addr, dst_addr, dst_len);
895d6b92ffaSHans Petter Selasky 	return ucma_complete(id);
896d6b92ffaSHans Petter Selasky }
897d6b92ffaSHans Petter Selasky 
rdma_resolve_addr(struct rdma_cm_id * id,struct sockaddr * src_addr,struct sockaddr * dst_addr,int timeout_ms)898d6b92ffaSHans Petter Selasky int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
899d6b92ffaSHans Petter Selasky 		      struct sockaddr *dst_addr, int timeout_ms)
900d6b92ffaSHans Petter Selasky {
901d6b92ffaSHans Petter Selasky 	struct ucma_abi_resolve_ip cmd;
902d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
903d6b92ffaSHans Petter Selasky 	int ret, dst_len, src_len;
904d6b92ffaSHans Petter Selasky 
905d6b92ffaSHans Petter Selasky 	dst_len = ucma_addrlen(dst_addr);
906d6b92ffaSHans Petter Selasky 	if (!dst_len)
907d6b92ffaSHans Petter Selasky 		return ERR(EINVAL);
908d6b92ffaSHans Petter Selasky 
909d6b92ffaSHans Petter Selasky 	src_len = ucma_addrlen(src_addr);
910d6b92ffaSHans Petter Selasky 	if (src_addr && !src_len)
911d6b92ffaSHans Petter Selasky 		return ERR(EINVAL);
912d6b92ffaSHans Petter Selasky 
913d6b92ffaSHans Petter Selasky 	if (af_ib_support)
914d6b92ffaSHans Petter Selasky 		return rdma_resolve_addr2(id, src_addr, src_len, dst_addr,
915d6b92ffaSHans Petter Selasky 					  dst_len, timeout_ms);
916d6b92ffaSHans Petter Selasky 
917d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD(&cmd, sizeof cmd, RESOLVE_IP);
918d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
919d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
920d6b92ffaSHans Petter Selasky 	if (src_addr)
921d6b92ffaSHans Petter Selasky 		memcpy(&cmd.src_addr, src_addr, src_len);
922d6b92ffaSHans Petter Selasky 	memcpy(&cmd.dst_addr, dst_addr, dst_len);
923d6b92ffaSHans Petter Selasky 	cmd.timeout_ms = timeout_ms;
924d6b92ffaSHans Petter Selasky 
925d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
926d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
927d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
928d6b92ffaSHans Petter Selasky 
929d6b92ffaSHans Petter Selasky 	memcpy(&id->route.addr.dst_addr, dst_addr, dst_len);
930d6b92ffaSHans Petter Selasky 	return ucma_complete(id);
931d6b92ffaSHans Petter Selasky }
932d6b92ffaSHans Petter Selasky 
ucma_set_ib_route(struct rdma_cm_id * id)933d6b92ffaSHans Petter Selasky static int ucma_set_ib_route(struct rdma_cm_id *id)
934d6b92ffaSHans Petter Selasky {
935d6b92ffaSHans Petter Selasky 	struct rdma_addrinfo hint, *rai;
936d6b92ffaSHans Petter Selasky 	int ret;
937d6b92ffaSHans Petter Selasky 
938d6b92ffaSHans Petter Selasky 	memset(&hint, 0, sizeof hint);
939d6b92ffaSHans Petter Selasky 	hint.ai_flags = RAI_ROUTEONLY;
940d6b92ffaSHans Petter Selasky 	hint.ai_family = id->route.addr.src_addr.sa_family;
941d6b92ffaSHans Petter Selasky 	hint.ai_src_len = ucma_addrlen((struct sockaddr *) &id->route.addr.src_addr);
942d6b92ffaSHans Petter Selasky 	hint.ai_src_addr = &id->route.addr.src_addr;
943d6b92ffaSHans Petter Selasky 	hint.ai_dst_len = ucma_addrlen((struct sockaddr *) &id->route.addr.dst_addr);
944d6b92ffaSHans Petter Selasky 	hint.ai_dst_addr = &id->route.addr.dst_addr;
945d6b92ffaSHans Petter Selasky 
946d6b92ffaSHans Petter Selasky 	ret = rdma_getaddrinfo(NULL, NULL, &hint, &rai);
947d6b92ffaSHans Petter Selasky 	if (ret)
948d6b92ffaSHans Petter Selasky 		return ret;
949d6b92ffaSHans Petter Selasky 
950d6b92ffaSHans Petter Selasky 	if (rai->ai_route_len)
951d6b92ffaSHans Petter Selasky 		ret = rdma_set_option(id, RDMA_OPTION_IB, RDMA_OPTION_IB_PATH,
952d6b92ffaSHans Petter Selasky 				      rai->ai_route, rai->ai_route_len);
953d6b92ffaSHans Petter Selasky 	else
954d6b92ffaSHans Petter Selasky 		ret = -1;
955d6b92ffaSHans Petter Selasky 
956d6b92ffaSHans Petter Selasky 	rdma_freeaddrinfo(rai);
957d6b92ffaSHans Petter Selasky 	return ret;
958d6b92ffaSHans Petter Selasky }
959d6b92ffaSHans Petter Selasky 
rdma_resolve_route(struct rdma_cm_id * id,int timeout_ms)960d6b92ffaSHans Petter Selasky int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
961d6b92ffaSHans Petter Selasky {
962d6b92ffaSHans Petter Selasky 	struct ucma_abi_resolve_route cmd;
963d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
964d6b92ffaSHans Petter Selasky 	int ret;
965d6b92ffaSHans Petter Selasky 
966d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
967d6b92ffaSHans Petter Selasky 	if (id->verbs->device->transport_type == IBV_TRANSPORT_IB) {
968d6b92ffaSHans Petter Selasky 		ret = ucma_set_ib_route(id);
969d6b92ffaSHans Petter Selasky 		if (!ret)
970d6b92ffaSHans Petter Selasky 			goto out;
971d6b92ffaSHans Petter Selasky 	}
972d6b92ffaSHans Petter Selasky 
973d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD(&cmd, sizeof cmd, RESOLVE_ROUTE);
974d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
975d6b92ffaSHans Petter Selasky 	cmd.timeout_ms = timeout_ms;
976d6b92ffaSHans Petter Selasky 
977d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
978d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
979d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
980d6b92ffaSHans Petter Selasky 
981d6b92ffaSHans Petter Selasky out:
982d6b92ffaSHans Petter Selasky 	return ucma_complete(id);
983d6b92ffaSHans Petter Selasky }
984d6b92ffaSHans Petter Selasky 
ucma_is_ud_qp(enum ibv_qp_type qp_type)985d6b92ffaSHans Petter Selasky static int ucma_is_ud_qp(enum ibv_qp_type qp_type)
986d6b92ffaSHans Petter Selasky {
987d6b92ffaSHans Petter Selasky 	return (qp_type == IBV_QPT_UD);
988d6b92ffaSHans Petter Selasky }
989d6b92ffaSHans Petter Selasky 
rdma_init_qp_attr(struct rdma_cm_id * id,struct ibv_qp_attr * qp_attr,int * qp_attr_mask)990d6b92ffaSHans Petter Selasky static int rdma_init_qp_attr(struct rdma_cm_id *id, struct ibv_qp_attr *qp_attr,
991d6b92ffaSHans Petter Selasky 			     int *qp_attr_mask)
992d6b92ffaSHans Petter Selasky {
993d6b92ffaSHans Petter Selasky 	struct ucma_abi_init_qp_attr cmd;
994d6b92ffaSHans Petter Selasky 	struct ibv_kern_qp_attr resp;
995d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
996d6b92ffaSHans Petter Selasky 	int ret;
997d6b92ffaSHans Petter Selasky 
998d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD_RESP(&cmd, sizeof cmd, INIT_QP_ATTR, &resp, sizeof resp);
999d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
1000d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
1001d6b92ffaSHans Petter Selasky 	cmd.qp_state = qp_attr->qp_state;
1002d6b92ffaSHans Petter Selasky 
1003d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
1004d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
1005d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
1006d6b92ffaSHans Petter Selasky 
1007d6b92ffaSHans Petter Selasky 	VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
1008d6b92ffaSHans Petter Selasky 
1009d6b92ffaSHans Petter Selasky 	ibv_copy_qp_attr_from_kern(qp_attr, &resp);
1010d6b92ffaSHans Petter Selasky 	*qp_attr_mask = resp.qp_attr_mask;
1011d6b92ffaSHans Petter Selasky 	return 0;
1012d6b92ffaSHans Petter Selasky }
1013d6b92ffaSHans Petter Selasky 
ucma_modify_qp_rtr(struct rdma_cm_id * id,uint8_t resp_res)1014d6b92ffaSHans Petter Selasky static int ucma_modify_qp_rtr(struct rdma_cm_id *id, uint8_t resp_res)
1015d6b92ffaSHans Petter Selasky {
1016d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
1017d6b92ffaSHans Petter Selasky 	struct ibv_qp_attr qp_attr;
1018d6b92ffaSHans Petter Selasky 	int qp_attr_mask, ret;
1019d6b92ffaSHans Petter Selasky 	uint8_t link_layer;
1020d6b92ffaSHans Petter Selasky 
1021d6b92ffaSHans Petter Selasky 	if (!id->qp)
1022d6b92ffaSHans Petter Selasky 		return ERR(EINVAL);
1023d6b92ffaSHans Petter Selasky 
1024d6b92ffaSHans Petter Selasky 	/* Need to update QP attributes from default values. */
1025d6b92ffaSHans Petter Selasky 	qp_attr.qp_state = IBV_QPS_INIT;
1026d6b92ffaSHans Petter Selasky 	ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask);
1027d6b92ffaSHans Petter Selasky 	if (ret)
1028d6b92ffaSHans Petter Selasky 		return ret;
1029d6b92ffaSHans Petter Selasky 
1030d6b92ffaSHans Petter Selasky 	ret = ibv_modify_qp(id->qp, &qp_attr, qp_attr_mask);
1031d6b92ffaSHans Petter Selasky 	if (ret)
1032d6b92ffaSHans Petter Selasky 		return ERR(ret);
1033d6b92ffaSHans Petter Selasky 
1034d6b92ffaSHans Petter Selasky 	qp_attr.qp_state = IBV_QPS_RTR;
1035d6b92ffaSHans Petter Selasky 	ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask);
1036d6b92ffaSHans Petter Selasky 	if (ret)
1037d6b92ffaSHans Petter Selasky 		return ret;
1038d6b92ffaSHans Petter Selasky 
1039d6b92ffaSHans Petter Selasky 	/*
1040d6b92ffaSHans Petter Selasky 	 * Workaround for rdma_ucm kernel bug:
1041d6b92ffaSHans Petter Selasky 	 * mask off qp_attr_mask bits 21-24 which are used for RoCE
1042d6b92ffaSHans Petter Selasky 	 */
1043d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
1044d6b92ffaSHans Petter Selasky 	link_layer = id_priv->cma_dev->port[id->port_num - 1].link_layer;
1045d6b92ffaSHans Petter Selasky 
1046d6b92ffaSHans Petter Selasky 	if (link_layer == IBV_LINK_LAYER_INFINIBAND)
1047d6b92ffaSHans Petter Selasky 		qp_attr_mask &= UINT_MAX ^ 0xe00000;
1048d6b92ffaSHans Petter Selasky 
1049d6b92ffaSHans Petter Selasky 	if (resp_res != RDMA_MAX_RESP_RES)
1050d6b92ffaSHans Petter Selasky 		qp_attr.max_dest_rd_atomic = resp_res;
1051d6b92ffaSHans Petter Selasky 	return rdma_seterrno(ibv_modify_qp(id->qp, &qp_attr, qp_attr_mask));
1052d6b92ffaSHans Petter Selasky }
1053d6b92ffaSHans Petter Selasky 
ucma_modify_qp_rts(struct rdma_cm_id * id,uint8_t init_depth)1054d6b92ffaSHans Petter Selasky static int ucma_modify_qp_rts(struct rdma_cm_id *id, uint8_t init_depth)
1055d6b92ffaSHans Petter Selasky {
1056d6b92ffaSHans Petter Selasky 	struct ibv_qp_attr qp_attr;
1057d6b92ffaSHans Petter Selasky 	int qp_attr_mask, ret;
1058d6b92ffaSHans Petter Selasky 
1059d6b92ffaSHans Petter Selasky 	qp_attr.qp_state = IBV_QPS_RTS;
1060d6b92ffaSHans Petter Selasky 	ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask);
1061d6b92ffaSHans Petter Selasky 	if (ret)
1062d6b92ffaSHans Petter Selasky 		return ret;
1063d6b92ffaSHans Petter Selasky 
1064d6b92ffaSHans Petter Selasky 	if (init_depth != RDMA_MAX_INIT_DEPTH)
1065d6b92ffaSHans Petter Selasky 		qp_attr.max_rd_atomic = init_depth;
1066d6b92ffaSHans Petter Selasky 	return rdma_seterrno(ibv_modify_qp(id->qp, &qp_attr, qp_attr_mask));
1067d6b92ffaSHans Petter Selasky }
1068d6b92ffaSHans Petter Selasky 
ucma_modify_qp_sqd(struct rdma_cm_id * id)1069d6b92ffaSHans Petter Selasky static int ucma_modify_qp_sqd(struct rdma_cm_id *id)
1070d6b92ffaSHans Petter Selasky {
1071d6b92ffaSHans Petter Selasky 	struct ibv_qp_attr qp_attr;
1072d6b92ffaSHans Petter Selasky 
1073d6b92ffaSHans Petter Selasky 	if (!id->qp)
1074d6b92ffaSHans Petter Selasky 		return 0;
1075d6b92ffaSHans Petter Selasky 
1076d6b92ffaSHans Petter Selasky 	qp_attr.qp_state = IBV_QPS_SQD;
1077d6b92ffaSHans Petter Selasky 	return rdma_seterrno(ibv_modify_qp(id->qp, &qp_attr, IBV_QP_STATE));
1078d6b92ffaSHans Petter Selasky }
1079d6b92ffaSHans Petter Selasky 
ucma_modify_qp_err(struct rdma_cm_id * id)1080d6b92ffaSHans Petter Selasky static int ucma_modify_qp_err(struct rdma_cm_id *id)
1081d6b92ffaSHans Petter Selasky {
1082d6b92ffaSHans Petter Selasky 	struct ibv_qp_attr qp_attr;
1083d6b92ffaSHans Petter Selasky 
1084d6b92ffaSHans Petter Selasky 	if (!id->qp)
1085d6b92ffaSHans Petter Selasky 		return 0;
1086d6b92ffaSHans Petter Selasky 
1087d6b92ffaSHans Petter Selasky 	qp_attr.qp_state = IBV_QPS_ERR;
1088d6b92ffaSHans Petter Selasky 	return rdma_seterrno(ibv_modify_qp(id->qp, &qp_attr, IBV_QP_STATE));
1089d6b92ffaSHans Petter Selasky }
1090d6b92ffaSHans Petter Selasky 
ucma_find_pkey(struct cma_device * cma_dev,uint8_t port_num,__be16 pkey,uint16_t * pkey_index)1091d6b92ffaSHans Petter Selasky static int ucma_find_pkey(struct cma_device *cma_dev, uint8_t port_num,
1092d6b92ffaSHans Petter Selasky 			  __be16 pkey, uint16_t *pkey_index)
1093d6b92ffaSHans Petter Selasky {
1094d6b92ffaSHans Petter Selasky 	int ret, i;
1095d6b92ffaSHans Petter Selasky 	__be16 chk_pkey;
1096d6b92ffaSHans Petter Selasky 
1097d6b92ffaSHans Petter Selasky 	for (i = 0, ret = 0; !ret; i++) {
1098d6b92ffaSHans Petter Selasky 		ret = ibv_query_pkey(cma_dev->verbs, port_num, i, &chk_pkey);
1099d6b92ffaSHans Petter Selasky 		if (!ret && pkey == chk_pkey) {
1100d6b92ffaSHans Petter Selasky 			*pkey_index = (uint16_t) i;
1101d6b92ffaSHans Petter Selasky 			return 0;
1102d6b92ffaSHans Petter Selasky 		}
1103d6b92ffaSHans Petter Selasky 	}
1104d6b92ffaSHans Petter Selasky 	return ERR(EINVAL);
1105d6b92ffaSHans Petter Selasky }
1106d6b92ffaSHans Petter Selasky 
ucma_init_conn_qp3(struct cma_id_private * id_priv,struct ibv_qp * qp)1107d6b92ffaSHans Petter Selasky static int ucma_init_conn_qp3(struct cma_id_private *id_priv, struct ibv_qp *qp)
1108d6b92ffaSHans Petter Selasky {
1109d6b92ffaSHans Petter Selasky 	struct ibv_qp_attr qp_attr;
1110d6b92ffaSHans Petter Selasky 	int ret;
1111d6b92ffaSHans Petter Selasky 
1112d6b92ffaSHans Petter Selasky 	ret = ucma_find_pkey(id_priv->cma_dev, id_priv->id.port_num,
1113d6b92ffaSHans Petter Selasky 			     id_priv->id.route.addr.addr.ibaddr.pkey,
1114d6b92ffaSHans Petter Selasky 			     &qp_attr.pkey_index);
1115d6b92ffaSHans Petter Selasky 	if (ret)
1116d6b92ffaSHans Petter Selasky 		return ret;
1117d6b92ffaSHans Petter Selasky 
1118d6b92ffaSHans Petter Selasky 	qp_attr.port_num = id_priv->id.port_num;
1119d6b92ffaSHans Petter Selasky 	qp_attr.qp_state = IBV_QPS_INIT;
1120d6b92ffaSHans Petter Selasky 	qp_attr.qp_access_flags = 0;
1121d6b92ffaSHans Petter Selasky 
1122d6b92ffaSHans Petter Selasky 	ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE | IBV_QP_ACCESS_FLAGS |
1123d6b92ffaSHans Petter Selasky 					  IBV_QP_PKEY_INDEX | IBV_QP_PORT);
1124d6b92ffaSHans Petter Selasky 	return rdma_seterrno(ret);
1125d6b92ffaSHans Petter Selasky }
1126d6b92ffaSHans Petter Selasky 
ucma_init_conn_qp(struct cma_id_private * id_priv,struct ibv_qp * qp)1127d6b92ffaSHans Petter Selasky static int ucma_init_conn_qp(struct cma_id_private *id_priv, struct ibv_qp *qp)
1128d6b92ffaSHans Petter Selasky {
1129d6b92ffaSHans Petter Selasky 	struct ibv_qp_attr qp_attr;
1130d6b92ffaSHans Petter Selasky 	int qp_attr_mask, ret;
1131d6b92ffaSHans Petter Selasky 
1132d6b92ffaSHans Petter Selasky 	if (abi_ver == 3)
1133d6b92ffaSHans Petter Selasky 		return ucma_init_conn_qp3(id_priv, qp);
1134d6b92ffaSHans Petter Selasky 
1135d6b92ffaSHans Petter Selasky 	qp_attr.qp_state = IBV_QPS_INIT;
1136d6b92ffaSHans Petter Selasky 	ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
1137d6b92ffaSHans Petter Selasky 	if (ret)
1138d6b92ffaSHans Petter Selasky 		return ret;
1139d6b92ffaSHans Petter Selasky 
1140d6b92ffaSHans Petter Selasky 	return rdma_seterrno(ibv_modify_qp(qp, &qp_attr, qp_attr_mask));
1141d6b92ffaSHans Petter Selasky }
1142d6b92ffaSHans Petter Selasky 
ucma_init_ud_qp3(struct cma_id_private * id_priv,struct ibv_qp * qp)1143d6b92ffaSHans Petter Selasky static int ucma_init_ud_qp3(struct cma_id_private *id_priv, struct ibv_qp *qp)
1144d6b92ffaSHans Petter Selasky {
1145d6b92ffaSHans Petter Selasky 	struct ibv_qp_attr qp_attr;
1146d6b92ffaSHans Petter Selasky 	int ret;
1147d6b92ffaSHans Petter Selasky 
1148d6b92ffaSHans Petter Selasky 	ret = ucma_find_pkey(id_priv->cma_dev, id_priv->id.port_num,
1149d6b92ffaSHans Petter Selasky 			     id_priv->id.route.addr.addr.ibaddr.pkey,
1150d6b92ffaSHans Petter Selasky 			     &qp_attr.pkey_index);
1151d6b92ffaSHans Petter Selasky 	if (ret)
1152d6b92ffaSHans Petter Selasky 		return ret;
1153d6b92ffaSHans Petter Selasky 
1154d6b92ffaSHans Petter Selasky 	qp_attr.port_num = id_priv->id.port_num;
1155d6b92ffaSHans Petter Selasky 	qp_attr.qp_state = IBV_QPS_INIT;
1156d6b92ffaSHans Petter Selasky 	qp_attr.qkey = RDMA_UDP_QKEY;
1157d6b92ffaSHans Petter Selasky 
1158d6b92ffaSHans Petter Selasky 	ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE | IBV_QP_QKEY |
1159d6b92ffaSHans Petter Selasky 					  IBV_QP_PKEY_INDEX | IBV_QP_PORT);
1160d6b92ffaSHans Petter Selasky 	if (ret)
1161d6b92ffaSHans Petter Selasky 		return ERR(ret);
1162d6b92ffaSHans Petter Selasky 
1163d6b92ffaSHans Petter Selasky 	qp_attr.qp_state = IBV_QPS_RTR;
1164d6b92ffaSHans Petter Selasky 	ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE);
1165d6b92ffaSHans Petter Selasky 	if (ret)
1166d6b92ffaSHans Petter Selasky 		return ERR(ret);
1167d6b92ffaSHans Petter Selasky 
1168d6b92ffaSHans Petter Selasky 	qp_attr.qp_state = IBV_QPS_RTS;
1169d6b92ffaSHans Petter Selasky 	qp_attr.sq_psn = 0;
1170d6b92ffaSHans Petter Selasky 	ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE | IBV_QP_SQ_PSN);
1171d6b92ffaSHans Petter Selasky 	return rdma_seterrno(ret);
1172d6b92ffaSHans Petter Selasky }
1173d6b92ffaSHans Petter Selasky 
ucma_init_ud_qp(struct cma_id_private * id_priv,struct ibv_qp * qp)1174d6b92ffaSHans Petter Selasky static int ucma_init_ud_qp(struct cma_id_private *id_priv, struct ibv_qp *qp)
1175d6b92ffaSHans Petter Selasky {
1176d6b92ffaSHans Petter Selasky 	struct ibv_qp_attr qp_attr;
1177d6b92ffaSHans Petter Selasky 	int qp_attr_mask, ret;
1178d6b92ffaSHans Petter Selasky 
1179d6b92ffaSHans Petter Selasky 	if (abi_ver == 3)
1180d6b92ffaSHans Petter Selasky 		return ucma_init_ud_qp3(id_priv, qp);
1181d6b92ffaSHans Petter Selasky 
1182d6b92ffaSHans Petter Selasky 	qp_attr.qp_state = IBV_QPS_INIT;
1183d6b92ffaSHans Petter Selasky 	ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
1184d6b92ffaSHans Petter Selasky 	if (ret)
1185d6b92ffaSHans Petter Selasky 		return ret;
1186d6b92ffaSHans Petter Selasky 
1187d6b92ffaSHans Petter Selasky 	ret = ibv_modify_qp(qp, &qp_attr, qp_attr_mask);
1188d6b92ffaSHans Petter Selasky 	if (ret)
1189d6b92ffaSHans Petter Selasky 		return ERR(ret);
1190d6b92ffaSHans Petter Selasky 
1191d6b92ffaSHans Petter Selasky 	qp_attr.qp_state = IBV_QPS_RTR;
1192d6b92ffaSHans Petter Selasky 	ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE);
1193d6b92ffaSHans Petter Selasky 	if (ret)
1194d6b92ffaSHans Petter Selasky 		return ERR(ret);
1195d6b92ffaSHans Petter Selasky 
1196d6b92ffaSHans Petter Selasky 	qp_attr.qp_state = IBV_QPS_RTS;
1197d6b92ffaSHans Petter Selasky 	qp_attr.sq_psn = 0;
1198d6b92ffaSHans Petter Selasky 	ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE | IBV_QP_SQ_PSN);
1199d6b92ffaSHans Petter Selasky 	return rdma_seterrno(ret);
1200d6b92ffaSHans Petter Selasky }
1201d6b92ffaSHans Petter Selasky 
ucma_destroy_cqs(struct rdma_cm_id * id)1202d6b92ffaSHans Petter Selasky static void ucma_destroy_cqs(struct rdma_cm_id *id)
1203d6b92ffaSHans Petter Selasky {
1204d6b92ffaSHans Petter Selasky 	if (id->qp_type == IBV_QPT_XRC_RECV && id->srq)
1205d6b92ffaSHans Petter Selasky 		return;
1206d6b92ffaSHans Petter Selasky 
1207d6b92ffaSHans Petter Selasky 	if (id->recv_cq) {
1208d6b92ffaSHans Petter Selasky 		ibv_destroy_cq(id->recv_cq);
1209d6b92ffaSHans Petter Selasky 		if (id->send_cq && (id->send_cq != id->recv_cq)) {
1210d6b92ffaSHans Petter Selasky 			ibv_destroy_cq(id->send_cq);
1211d6b92ffaSHans Petter Selasky 			id->send_cq = NULL;
1212d6b92ffaSHans Petter Selasky 		}
1213d6b92ffaSHans Petter Selasky 		id->recv_cq = NULL;
1214d6b92ffaSHans Petter Selasky 	}
1215d6b92ffaSHans Petter Selasky 
1216d6b92ffaSHans Petter Selasky 	if (id->recv_cq_channel) {
1217d6b92ffaSHans Petter Selasky 		ibv_destroy_comp_channel(id->recv_cq_channel);
1218d6b92ffaSHans Petter Selasky 		if (id->send_cq_channel && (id->send_cq_channel != id->recv_cq_channel)) {
1219d6b92ffaSHans Petter Selasky 			ibv_destroy_comp_channel(id->send_cq_channel);
1220d6b92ffaSHans Petter Selasky 			id->send_cq_channel = NULL;
1221d6b92ffaSHans Petter Selasky 		}
1222d6b92ffaSHans Petter Selasky 		id->recv_cq_channel = NULL;
1223d6b92ffaSHans Petter Selasky 	}
1224d6b92ffaSHans Petter Selasky }
1225d6b92ffaSHans Petter Selasky 
ucma_create_cqs(struct rdma_cm_id * id,uint32_t send_size,uint32_t recv_size)1226d6b92ffaSHans Petter Selasky static int ucma_create_cqs(struct rdma_cm_id *id, uint32_t send_size, uint32_t recv_size)
1227d6b92ffaSHans Petter Selasky {
1228d6b92ffaSHans Petter Selasky 	if (recv_size) {
1229d6b92ffaSHans Petter Selasky 		id->recv_cq_channel = ibv_create_comp_channel(id->verbs);
1230d6b92ffaSHans Petter Selasky 		if (!id->recv_cq_channel)
1231d6b92ffaSHans Petter Selasky 			goto err;
1232d6b92ffaSHans Petter Selasky 
1233d6b92ffaSHans Petter Selasky 		id->recv_cq = ibv_create_cq(id->verbs, recv_size,
1234d6b92ffaSHans Petter Selasky 					    id, id->recv_cq_channel, 0);
1235d6b92ffaSHans Petter Selasky 		if (!id->recv_cq)
1236d6b92ffaSHans Petter Selasky 			goto err;
1237d6b92ffaSHans Petter Selasky 	}
1238d6b92ffaSHans Petter Selasky 
1239d6b92ffaSHans Petter Selasky 	if (send_size) {
1240d6b92ffaSHans Petter Selasky 		id->send_cq_channel = ibv_create_comp_channel(id->verbs);
1241d6b92ffaSHans Petter Selasky 		if (!id->send_cq_channel)
1242d6b92ffaSHans Petter Selasky 			goto err;
1243d6b92ffaSHans Petter Selasky 
1244d6b92ffaSHans Petter Selasky 		id->send_cq = ibv_create_cq(id->verbs, send_size,
1245d6b92ffaSHans Petter Selasky 					    id, id->send_cq_channel, 0);
1246d6b92ffaSHans Petter Selasky 		if (!id->send_cq)
1247d6b92ffaSHans Petter Selasky 			goto err;
1248d6b92ffaSHans Petter Selasky 	}
1249d6b92ffaSHans Petter Selasky 
1250d6b92ffaSHans Petter Selasky 	return 0;
1251d6b92ffaSHans Petter Selasky err:
1252d6b92ffaSHans Petter Selasky 	ucma_destroy_cqs(id);
1253d6b92ffaSHans Petter Selasky 	return ERR(ENOMEM);
1254d6b92ffaSHans Petter Selasky }
1255d6b92ffaSHans Petter Selasky 
rdma_create_srq_ex(struct rdma_cm_id * id,struct ibv_srq_init_attr_ex * attr)1256d6b92ffaSHans Petter Selasky int rdma_create_srq_ex(struct rdma_cm_id *id, struct ibv_srq_init_attr_ex *attr)
1257d6b92ffaSHans Petter Selasky {
1258d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
1259d6b92ffaSHans Petter Selasky 	struct ibv_srq *srq;
1260d6b92ffaSHans Petter Selasky 	int ret;
1261d6b92ffaSHans Petter Selasky 
1262d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
1263d6b92ffaSHans Petter Selasky 	if (!(attr->comp_mask & IBV_SRQ_INIT_ATTR_TYPE))
1264d6b92ffaSHans Petter Selasky 		return ERR(EINVAL);
1265d6b92ffaSHans Petter Selasky 
1266d6b92ffaSHans Petter Selasky 	if (!(attr->comp_mask & IBV_SRQ_INIT_ATTR_PD) || !attr->pd) {
1267d6b92ffaSHans Petter Selasky 		attr->pd = id->pd;
1268d6b92ffaSHans Petter Selasky 		attr->comp_mask |= IBV_SRQ_INIT_ATTR_PD;
1269d6b92ffaSHans Petter Selasky 	}
1270d6b92ffaSHans Petter Selasky 
1271d6b92ffaSHans Petter Selasky 	if (attr->srq_type == IBV_SRQT_XRC) {
1272d6b92ffaSHans Petter Selasky 		if (!(attr->comp_mask & IBV_SRQ_INIT_ATTR_XRCD) || !attr->xrcd) {
1273d6b92ffaSHans Petter Selasky 			attr->xrcd = ucma_get_xrcd(id_priv->cma_dev);
1274d6b92ffaSHans Petter Selasky 			if (!attr->xrcd)
1275d6b92ffaSHans Petter Selasky 				return -1;
1276d6b92ffaSHans Petter Selasky 		}
1277d6b92ffaSHans Petter Selasky 		if (!(attr->comp_mask & IBV_SRQ_INIT_ATTR_CQ) || !attr->cq) {
1278d6b92ffaSHans Petter Selasky 			ret = ucma_create_cqs(id, 0, attr->attr.max_wr);
1279d6b92ffaSHans Petter Selasky 			if (ret)
1280d6b92ffaSHans Petter Selasky 				return ret;
1281d6b92ffaSHans Petter Selasky 			attr->cq = id->recv_cq;
1282d6b92ffaSHans Petter Selasky 		}
1283d6b92ffaSHans Petter Selasky 		attr->comp_mask |= IBV_SRQ_INIT_ATTR_XRCD | IBV_SRQ_INIT_ATTR_CQ;
1284d6b92ffaSHans Petter Selasky 	}
1285d6b92ffaSHans Petter Selasky 
1286d6b92ffaSHans Petter Selasky 	srq = ibv_create_srq_ex(id->verbs, attr);
1287d6b92ffaSHans Petter Selasky 	if (!srq) {
1288d6b92ffaSHans Petter Selasky 		ret = -1;
1289d6b92ffaSHans Petter Selasky 		goto err;
1290d6b92ffaSHans Petter Selasky 	}
1291d6b92ffaSHans Petter Selasky 
1292d6b92ffaSHans Petter Selasky 	if (!id->pd)
1293d6b92ffaSHans Petter Selasky 		id->pd = attr->pd;
1294d6b92ffaSHans Petter Selasky 	id->srq = srq;
1295d6b92ffaSHans Petter Selasky 	return 0;
1296d6b92ffaSHans Petter Selasky err:
1297d6b92ffaSHans Petter Selasky 	ucma_destroy_cqs(id);
1298d6b92ffaSHans Petter Selasky 	return ret;
1299d6b92ffaSHans Petter Selasky }
1300d6b92ffaSHans Petter Selasky 
rdma_create_srq(struct rdma_cm_id * id,struct ibv_pd * pd,struct ibv_srq_init_attr * attr)1301d6b92ffaSHans Petter Selasky int rdma_create_srq(struct rdma_cm_id *id, struct ibv_pd *pd,
1302d6b92ffaSHans Petter Selasky 		    struct ibv_srq_init_attr *attr)
1303d6b92ffaSHans Petter Selasky {
1304d6b92ffaSHans Petter Selasky 	struct ibv_srq_init_attr_ex attr_ex;
1305d6b92ffaSHans Petter Selasky 	int ret;
1306d6b92ffaSHans Petter Selasky 
1307d6b92ffaSHans Petter Selasky 	memcpy(&attr_ex, attr, sizeof(*attr));
1308d6b92ffaSHans Petter Selasky 	attr_ex.comp_mask = IBV_SRQ_INIT_ATTR_TYPE | IBV_SRQ_INIT_ATTR_PD;
1309d6b92ffaSHans Petter Selasky 	if (id->qp_type == IBV_QPT_XRC_RECV) {
1310d6b92ffaSHans Petter Selasky 		attr_ex.srq_type = IBV_SRQT_XRC;
1311d6b92ffaSHans Petter Selasky 	} else {
1312d6b92ffaSHans Petter Selasky 		attr_ex.srq_type = IBV_SRQT_BASIC;
1313d6b92ffaSHans Petter Selasky 	}
1314d6b92ffaSHans Petter Selasky 	attr_ex.pd = pd;
1315d6b92ffaSHans Petter Selasky 	ret = rdma_create_srq_ex(id, &attr_ex);
1316d6b92ffaSHans Petter Selasky 	memcpy(attr, &attr_ex, sizeof(*attr));
1317d6b92ffaSHans Petter Selasky 	return ret;
1318d6b92ffaSHans Petter Selasky }
1319d6b92ffaSHans Petter Selasky 
rdma_destroy_srq(struct rdma_cm_id * id)1320d6b92ffaSHans Petter Selasky void rdma_destroy_srq(struct rdma_cm_id *id)
1321d6b92ffaSHans Petter Selasky {
1322d6b92ffaSHans Petter Selasky 	ibv_destroy_srq(id->srq);
1323d6b92ffaSHans Petter Selasky 	id->srq = NULL;
1324d6b92ffaSHans Petter Selasky 	ucma_destroy_cqs(id);
1325d6b92ffaSHans Petter Selasky }
1326d6b92ffaSHans Petter Selasky 
rdma_create_qp_ex(struct rdma_cm_id * id,struct ibv_qp_init_attr_ex * attr)1327d6b92ffaSHans Petter Selasky int rdma_create_qp_ex(struct rdma_cm_id *id,
1328d6b92ffaSHans Petter Selasky 		      struct ibv_qp_init_attr_ex *attr)
1329d6b92ffaSHans Petter Selasky {
1330d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
1331d6b92ffaSHans Petter Selasky 	struct ibv_qp *qp;
1332d6b92ffaSHans Petter Selasky 	int ret;
1333d6b92ffaSHans Petter Selasky 
1334d6b92ffaSHans Petter Selasky 	if (id->qp)
1335d6b92ffaSHans Petter Selasky 		return ERR(EINVAL);
1336d6b92ffaSHans Petter Selasky 
1337d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
1338d6b92ffaSHans Petter Selasky 	if (!(attr->comp_mask & IBV_QP_INIT_ATTR_PD) || !attr->pd) {
1339d6b92ffaSHans Petter Selasky 		attr->comp_mask |= IBV_QP_INIT_ATTR_PD;
1340d6b92ffaSHans Petter Selasky 		attr->pd = id->pd;
1341d6b92ffaSHans Petter Selasky 	} else if (id->verbs != attr->pd->context)
1342d6b92ffaSHans Petter Selasky 		return ERR(EINVAL);
1343d6b92ffaSHans Petter Selasky 
1344d6b92ffaSHans Petter Selasky 	if ((id->recv_cq && attr->recv_cq && id->recv_cq != attr->recv_cq) ||
1345d6b92ffaSHans Petter Selasky 	    (id->send_cq && attr->send_cq && id->send_cq != attr->send_cq))
1346d6b92ffaSHans Petter Selasky 		return ERR(EINVAL);
1347d6b92ffaSHans Petter Selasky 
1348d6b92ffaSHans Petter Selasky 	if (id->qp_type == IBV_QPT_XRC_RECV) {
1349d6b92ffaSHans Petter Selasky 		if (!(attr->comp_mask & IBV_QP_INIT_ATTR_XRCD) || !attr->xrcd) {
1350d6b92ffaSHans Petter Selasky 			attr->xrcd = ucma_get_xrcd(id_priv->cma_dev);
1351d6b92ffaSHans Petter Selasky 			if (!attr->xrcd)
1352d6b92ffaSHans Petter Selasky 				return -1;
1353d6b92ffaSHans Petter Selasky 			attr->comp_mask |= IBV_QP_INIT_ATTR_XRCD;
1354d6b92ffaSHans Petter Selasky 		}
1355d6b92ffaSHans Petter Selasky 	}
1356d6b92ffaSHans Petter Selasky 
1357d6b92ffaSHans Petter Selasky 	ret = ucma_create_cqs(id, attr->send_cq || id->send_cq ? 0 : attr->cap.max_send_wr,
1358d6b92ffaSHans Petter Selasky 				  attr->recv_cq || id->recv_cq ? 0 : attr->cap.max_recv_wr);
1359d6b92ffaSHans Petter Selasky 	if (ret)
1360d6b92ffaSHans Petter Selasky 		return ret;
1361d6b92ffaSHans Petter Selasky 
1362d6b92ffaSHans Petter Selasky 	if (!attr->send_cq)
1363d6b92ffaSHans Petter Selasky 		attr->send_cq = id->send_cq;
1364d6b92ffaSHans Petter Selasky 	if (!attr->recv_cq)
1365d6b92ffaSHans Petter Selasky 		attr->recv_cq = id->recv_cq;
1366d6b92ffaSHans Petter Selasky 	if (id->srq && !attr->srq)
1367d6b92ffaSHans Petter Selasky 		attr->srq = id->srq;
1368d6b92ffaSHans Petter Selasky 	qp = ibv_create_qp_ex(id->verbs, attr);
1369d6b92ffaSHans Petter Selasky 	if (!qp) {
1370d6b92ffaSHans Petter Selasky 		ret = ERR(ENOMEM);
1371d6b92ffaSHans Petter Selasky 		goto err1;
1372d6b92ffaSHans Petter Selasky 	}
1373d6b92ffaSHans Petter Selasky 
1374d6b92ffaSHans Petter Selasky 	if (ucma_is_ud_qp(id->qp_type))
1375d6b92ffaSHans Petter Selasky 		ret = ucma_init_ud_qp(id_priv, qp);
1376d6b92ffaSHans Petter Selasky 	else
1377d6b92ffaSHans Petter Selasky 		ret = ucma_init_conn_qp(id_priv, qp);
1378d6b92ffaSHans Petter Selasky 	if (ret)
1379d6b92ffaSHans Petter Selasky 		goto err2;
1380d6b92ffaSHans Petter Selasky 
1381d6b92ffaSHans Petter Selasky 	id->pd = qp->pd;
1382d6b92ffaSHans Petter Selasky 	id->qp = qp;
1383d6b92ffaSHans Petter Selasky 	return 0;
1384d6b92ffaSHans Petter Selasky err2:
1385d6b92ffaSHans Petter Selasky 	ibv_destroy_qp(qp);
1386d6b92ffaSHans Petter Selasky err1:
1387d6b92ffaSHans Petter Selasky 	ucma_destroy_cqs(id);
1388d6b92ffaSHans Petter Selasky 	return ret;
1389d6b92ffaSHans Petter Selasky }
1390d6b92ffaSHans Petter Selasky 
rdma_create_qp(struct rdma_cm_id * id,struct ibv_pd * pd,struct ibv_qp_init_attr * qp_init_attr)1391d6b92ffaSHans Petter Selasky int rdma_create_qp(struct rdma_cm_id *id, struct ibv_pd *pd,
1392d6b92ffaSHans Petter Selasky 		   struct ibv_qp_init_attr *qp_init_attr)
1393d6b92ffaSHans Petter Selasky {
1394d6b92ffaSHans Petter Selasky 	struct ibv_qp_init_attr_ex attr_ex;
1395d6b92ffaSHans Petter Selasky 	int ret;
1396d6b92ffaSHans Petter Selasky 
1397d6b92ffaSHans Petter Selasky 	memcpy(&attr_ex, qp_init_attr, sizeof(*qp_init_attr));
1398d6b92ffaSHans Petter Selasky 	attr_ex.comp_mask = IBV_QP_INIT_ATTR_PD;
1399d6b92ffaSHans Petter Selasky 	attr_ex.pd = pd ? pd : id->pd;
1400d6b92ffaSHans Petter Selasky 	ret = rdma_create_qp_ex(id, &attr_ex);
1401d6b92ffaSHans Petter Selasky 	memcpy(qp_init_attr, &attr_ex, sizeof(*qp_init_attr));
1402d6b92ffaSHans Petter Selasky 	return ret;
1403d6b92ffaSHans Petter Selasky }
1404d6b92ffaSHans Petter Selasky 
rdma_destroy_qp(struct rdma_cm_id * id)1405d6b92ffaSHans Petter Selasky void rdma_destroy_qp(struct rdma_cm_id *id)
1406d6b92ffaSHans Petter Selasky {
1407d6b92ffaSHans Petter Selasky 	ibv_destroy_qp(id->qp);
1408d6b92ffaSHans Petter Selasky 	id->qp = NULL;
1409d6b92ffaSHans Petter Selasky 	ucma_destroy_cqs(id);
1410d6b92ffaSHans Petter Selasky }
1411d6b92ffaSHans Petter Selasky 
ucma_valid_param(struct cma_id_private * id_priv,struct rdma_conn_param * param)1412d6b92ffaSHans Petter Selasky static int ucma_valid_param(struct cma_id_private *id_priv,
1413d6b92ffaSHans Petter Selasky 			    struct rdma_conn_param *param)
1414d6b92ffaSHans Petter Selasky {
1415d6b92ffaSHans Petter Selasky 	if (id_priv->id.ps != RDMA_PS_TCP)
1416d6b92ffaSHans Petter Selasky 		return 0;
1417d6b92ffaSHans Petter Selasky 
1418d6b92ffaSHans Petter Selasky 	if (!id_priv->id.qp && !param)
1419d6b92ffaSHans Petter Selasky 		goto err;
1420d6b92ffaSHans Petter Selasky 
1421d6b92ffaSHans Petter Selasky 	if (!param)
1422d6b92ffaSHans Petter Selasky 		return 0;
1423d6b92ffaSHans Petter Selasky 
1424d6b92ffaSHans Petter Selasky 	if ((param->responder_resources != RDMA_MAX_RESP_RES) &&
1425d6b92ffaSHans Petter Selasky 	    (param->responder_resources > id_priv->cma_dev->max_responder_resources))
1426d6b92ffaSHans Petter Selasky 		goto err;
1427d6b92ffaSHans Petter Selasky 
1428d6b92ffaSHans Petter Selasky 	if ((param->initiator_depth != RDMA_MAX_INIT_DEPTH) &&
1429d6b92ffaSHans Petter Selasky 	    (param->initiator_depth > id_priv->cma_dev->max_initiator_depth))
1430d6b92ffaSHans Petter Selasky 		goto err;
1431d6b92ffaSHans Petter Selasky 
1432d6b92ffaSHans Petter Selasky 	return 0;
1433d6b92ffaSHans Petter Selasky err:
1434d6b92ffaSHans Petter Selasky 	return ERR(EINVAL);
1435d6b92ffaSHans Petter Selasky }
1436d6b92ffaSHans Petter Selasky 
ucma_copy_conn_param_to_kern(struct cma_id_private * id_priv,struct ucma_abi_conn_param * dst,struct rdma_conn_param * src,uint32_t qp_num,uint8_t srq)1437d6b92ffaSHans Petter Selasky static void ucma_copy_conn_param_to_kern(struct cma_id_private *id_priv,
1438d6b92ffaSHans Petter Selasky 					 struct ucma_abi_conn_param *dst,
1439d6b92ffaSHans Petter Selasky 					 struct rdma_conn_param *src,
1440d6b92ffaSHans Petter Selasky 					 uint32_t qp_num, uint8_t srq)
1441d6b92ffaSHans Petter Selasky {
1442d6b92ffaSHans Petter Selasky 	dst->qp_num = qp_num;
1443d6b92ffaSHans Petter Selasky 	dst->srq = srq;
1444d6b92ffaSHans Petter Selasky 	dst->responder_resources = id_priv->responder_resources;
1445d6b92ffaSHans Petter Selasky 	dst->initiator_depth = id_priv->initiator_depth;
1446d6b92ffaSHans Petter Selasky 	dst->valid = 1;
1447d6b92ffaSHans Petter Selasky 
1448d6b92ffaSHans Petter Selasky 	if (id_priv->connect_len) {
1449d6b92ffaSHans Petter Selasky 		memcpy(dst->private_data, id_priv->connect, id_priv->connect_len);
1450d6b92ffaSHans Petter Selasky 		dst->private_data_len = id_priv->connect_len;
1451d6b92ffaSHans Petter Selasky 	}
1452d6b92ffaSHans Petter Selasky 
1453d6b92ffaSHans Petter Selasky 	if (src) {
1454d6b92ffaSHans Petter Selasky 		dst->flow_control = src->flow_control;
1455d6b92ffaSHans Petter Selasky 		dst->retry_count = src->retry_count;
1456d6b92ffaSHans Petter Selasky 		dst->rnr_retry_count = src->rnr_retry_count;
1457d6b92ffaSHans Petter Selasky 
1458d6b92ffaSHans Petter Selasky 		if (src->private_data && src->private_data_len) {
1459d6b92ffaSHans Petter Selasky 			memcpy(dst->private_data + dst->private_data_len,
1460d6b92ffaSHans Petter Selasky 			       src->private_data, src->private_data_len);
1461d6b92ffaSHans Petter Selasky 			dst->private_data_len += src->private_data_len;
1462d6b92ffaSHans Petter Selasky 		}
1463d6b92ffaSHans Petter Selasky 	} else {
1464d6b92ffaSHans Petter Selasky 		dst->retry_count = 7;
1465d6b92ffaSHans Petter Selasky 		dst->rnr_retry_count = 7;
1466d6b92ffaSHans Petter Selasky 	}
1467d6b92ffaSHans Petter Selasky }
1468d6b92ffaSHans Petter Selasky 
rdma_connect(struct rdma_cm_id * id,struct rdma_conn_param * conn_param)1469d6b92ffaSHans Petter Selasky int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
1470d6b92ffaSHans Petter Selasky {
1471d6b92ffaSHans Petter Selasky 	struct ucma_abi_connect cmd;
1472d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
1473d6b92ffaSHans Petter Selasky 	int ret;
1474d6b92ffaSHans Petter Selasky 
1475d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
1476d6b92ffaSHans Petter Selasky 	ret = ucma_valid_param(id_priv, conn_param);
1477d6b92ffaSHans Petter Selasky 	if (ret)
1478d6b92ffaSHans Petter Selasky 		return ret;
1479d6b92ffaSHans Petter Selasky 
1480d6b92ffaSHans Petter Selasky 	if (conn_param && conn_param->initiator_depth != RDMA_MAX_INIT_DEPTH)
1481d6b92ffaSHans Petter Selasky 		id_priv->initiator_depth = conn_param->initiator_depth;
1482d6b92ffaSHans Petter Selasky 	else
1483d6b92ffaSHans Petter Selasky 		id_priv->initiator_depth = id_priv->cma_dev->max_initiator_depth;
1484d6b92ffaSHans Petter Selasky 	if (conn_param && conn_param->responder_resources != RDMA_MAX_RESP_RES)
1485d6b92ffaSHans Petter Selasky 		id_priv->responder_resources = conn_param->responder_resources;
1486d6b92ffaSHans Petter Selasky 	else
1487d6b92ffaSHans Petter Selasky 		id_priv->responder_resources = id_priv->cma_dev->max_responder_resources;
1488d6b92ffaSHans Petter Selasky 
1489d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD(&cmd, sizeof cmd, CONNECT);
1490d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
1491d6b92ffaSHans Petter Selasky 	if (id->qp) {
1492d6b92ffaSHans Petter Selasky 		ucma_copy_conn_param_to_kern(id_priv, &cmd.conn_param,
1493d6b92ffaSHans Petter Selasky 					     conn_param, id->qp->qp_num,
1494d6b92ffaSHans Petter Selasky 					     (id->qp->srq != NULL));
1495d6b92ffaSHans Petter Selasky 	} else if (conn_param) {
1496d6b92ffaSHans Petter Selasky 		ucma_copy_conn_param_to_kern(id_priv, &cmd.conn_param,
1497d6b92ffaSHans Petter Selasky 					     conn_param, conn_param->qp_num,
1498d6b92ffaSHans Petter Selasky 					     conn_param->srq);
1499d6b92ffaSHans Petter Selasky 	} else {
1500d6b92ffaSHans Petter Selasky 		ucma_copy_conn_param_to_kern(id_priv, &cmd.conn_param,
1501d6b92ffaSHans Petter Selasky 					     conn_param, 0, 0);
1502d6b92ffaSHans Petter Selasky 	}
1503d6b92ffaSHans Petter Selasky 
1504d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
1505d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
1506d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
1507d6b92ffaSHans Petter Selasky 
1508d6b92ffaSHans Petter Selasky 	if (id_priv->connect_len) {
1509d6b92ffaSHans Petter Selasky 		free(id_priv->connect);
1510d6b92ffaSHans Petter Selasky 		id_priv->connect_len = 0;
1511d6b92ffaSHans Petter Selasky 	}
1512d6b92ffaSHans Petter Selasky 
1513d6b92ffaSHans Petter Selasky 	return ucma_complete(id);
1514d6b92ffaSHans Petter Selasky }
1515d6b92ffaSHans Petter Selasky 
rdma_listen(struct rdma_cm_id * id,int backlog)1516d6b92ffaSHans Petter Selasky int rdma_listen(struct rdma_cm_id *id, int backlog)
1517d6b92ffaSHans Petter Selasky {
1518d6b92ffaSHans Petter Selasky 	struct ucma_abi_listen cmd;
1519d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
1520d6b92ffaSHans Petter Selasky 	int ret;
1521d6b92ffaSHans Petter Selasky 
1522d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD(&cmd, sizeof cmd, LISTEN);
1523d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
1524d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
1525d6b92ffaSHans Petter Selasky 	cmd.backlog = backlog;
1526d6b92ffaSHans Petter Selasky 
1527d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
1528d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
1529d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
1530d6b92ffaSHans Petter Selasky 
1531d6b92ffaSHans Petter Selasky 	if (af_ib_support)
1532d6b92ffaSHans Petter Selasky 		return ucma_query_addr(id);
1533d6b92ffaSHans Petter Selasky 	else
1534d6b92ffaSHans Petter Selasky 		return ucma_query_route(id);
1535d6b92ffaSHans Petter Selasky }
1536d6b92ffaSHans Petter Selasky 
rdma_get_request(struct rdma_cm_id * listen,struct rdma_cm_id ** id)1537d6b92ffaSHans Petter Selasky int rdma_get_request(struct rdma_cm_id *listen, struct rdma_cm_id **id)
1538d6b92ffaSHans Petter Selasky {
1539d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
1540d6b92ffaSHans Petter Selasky 	struct rdma_cm_event *event;
1541d6b92ffaSHans Petter Selasky 	int ret;
1542d6b92ffaSHans Petter Selasky 
1543d6b92ffaSHans Petter Selasky 	id_priv = container_of(listen, struct cma_id_private, id);
1544d6b92ffaSHans Petter Selasky 	if (!id_priv->sync)
1545d6b92ffaSHans Petter Selasky 		return ERR(EINVAL);
1546d6b92ffaSHans Petter Selasky 
1547d6b92ffaSHans Petter Selasky 	if (listen->event) {
1548d6b92ffaSHans Petter Selasky 		rdma_ack_cm_event(listen->event);
1549d6b92ffaSHans Petter Selasky 		listen->event = NULL;
1550d6b92ffaSHans Petter Selasky 	}
1551d6b92ffaSHans Petter Selasky 
1552d6b92ffaSHans Petter Selasky 	ret = rdma_get_cm_event(listen->channel, &event);
1553d6b92ffaSHans Petter Selasky 	if (ret)
1554d6b92ffaSHans Petter Selasky 		return ret;
1555d6b92ffaSHans Petter Selasky 
1556d6b92ffaSHans Petter Selasky 	if (event->status) {
1557d6b92ffaSHans Petter Selasky 		ret = ERR(event->status);
1558d6b92ffaSHans Petter Selasky 		goto err;
1559d6b92ffaSHans Petter Selasky 	}
1560d6b92ffaSHans Petter Selasky 
1561d6b92ffaSHans Petter Selasky 	if (event->event != RDMA_CM_EVENT_CONNECT_REQUEST) {
1562d6b92ffaSHans Petter Selasky 		ret = ERR(EINVAL);
1563d6b92ffaSHans Petter Selasky 		goto err;
1564d6b92ffaSHans Petter Selasky 	}
1565d6b92ffaSHans Petter Selasky 
1566d6b92ffaSHans Petter Selasky 	if (id_priv->qp_init_attr) {
1567d6b92ffaSHans Petter Selasky 		struct ibv_qp_init_attr attr;
1568d6b92ffaSHans Petter Selasky 
1569d6b92ffaSHans Petter Selasky 		attr = *id_priv->qp_init_attr;
1570d6b92ffaSHans Petter Selasky 		ret = rdma_create_qp(event->id, listen->pd, &attr);
1571d6b92ffaSHans Petter Selasky 		if (ret)
1572d6b92ffaSHans Petter Selasky 			goto err;
1573d6b92ffaSHans Petter Selasky 	}
1574d6b92ffaSHans Petter Selasky 
1575d6b92ffaSHans Petter Selasky 	*id = event->id;
1576d6b92ffaSHans Petter Selasky 	(*id)->event = event;
1577d6b92ffaSHans Petter Selasky 	return 0;
1578d6b92ffaSHans Petter Selasky 
1579d6b92ffaSHans Petter Selasky err:
1580d6b92ffaSHans Petter Selasky 	listen->event = event;
1581d6b92ffaSHans Petter Selasky 	return ret;
1582d6b92ffaSHans Petter Selasky }
1583d6b92ffaSHans Petter Selasky 
rdma_accept(struct rdma_cm_id * id,struct rdma_conn_param * conn_param)1584d6b92ffaSHans Petter Selasky int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
1585d6b92ffaSHans Petter Selasky {
1586d6b92ffaSHans Petter Selasky 	struct ucma_abi_accept cmd;
1587d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
1588d6b92ffaSHans Petter Selasky 	int ret;
1589d6b92ffaSHans Petter Selasky 
1590d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
1591d6b92ffaSHans Petter Selasky 	ret = ucma_valid_param(id_priv, conn_param);
1592d6b92ffaSHans Petter Selasky 	if (ret)
1593d6b92ffaSHans Petter Selasky 		return ret;
1594d6b92ffaSHans Petter Selasky 
1595d6b92ffaSHans Petter Selasky 	if (!conn_param || conn_param->initiator_depth == RDMA_MAX_INIT_DEPTH) {
1596d6b92ffaSHans Petter Selasky 		id_priv->initiator_depth = min(id_priv->initiator_depth,
1597d6b92ffaSHans Petter Selasky 					       id_priv->cma_dev->max_initiator_depth);
1598d6b92ffaSHans Petter Selasky 	} else {
1599d6b92ffaSHans Petter Selasky 		id_priv->initiator_depth = conn_param->initiator_depth;
1600d6b92ffaSHans Petter Selasky 	}
1601d6b92ffaSHans Petter Selasky 	if (!conn_param || conn_param->responder_resources == RDMA_MAX_RESP_RES) {
1602d6b92ffaSHans Petter Selasky 		id_priv->responder_resources = min(id_priv->responder_resources,
1603d6b92ffaSHans Petter Selasky 						   id_priv->cma_dev->max_responder_resources);
1604d6b92ffaSHans Petter Selasky 	} else {
1605d6b92ffaSHans Petter Selasky 		id_priv->responder_resources = conn_param->responder_resources;
1606d6b92ffaSHans Petter Selasky 	}
1607d6b92ffaSHans Petter Selasky 
1608d6b92ffaSHans Petter Selasky 	if (!ucma_is_ud_qp(id->qp_type)) {
1609d6b92ffaSHans Petter Selasky 		ret = ucma_modify_qp_rtr(id, id_priv->responder_resources);
1610d6b92ffaSHans Petter Selasky 		if (ret)
1611d6b92ffaSHans Petter Selasky 			return ret;
1612d6b92ffaSHans Petter Selasky 
1613d6b92ffaSHans Petter Selasky 		ret = ucma_modify_qp_rts(id, id_priv->initiator_depth);
1614d6b92ffaSHans Petter Selasky 		if (ret)
1615d6b92ffaSHans Petter Selasky 			return ret;
1616d6b92ffaSHans Petter Selasky 	}
1617d6b92ffaSHans Petter Selasky 
1618d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD(&cmd, sizeof cmd, ACCEPT);
1619d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
1620d6b92ffaSHans Petter Selasky 	cmd.uid = (uintptr_t) id_priv;
1621d6b92ffaSHans Petter Selasky 	if (id->qp)
1622d6b92ffaSHans Petter Selasky 		ucma_copy_conn_param_to_kern(id_priv, &cmd.conn_param,
1623d6b92ffaSHans Petter Selasky 					     conn_param, id->qp->qp_num,
1624d6b92ffaSHans Petter Selasky 					     (id->qp->srq != NULL));
1625d6b92ffaSHans Petter Selasky 	else
1626d6b92ffaSHans Petter Selasky 		ucma_copy_conn_param_to_kern(id_priv, &cmd.conn_param,
1627d6b92ffaSHans Petter Selasky 					     conn_param, conn_param->qp_num,
1628d6b92ffaSHans Petter Selasky 					     conn_param->srq);
1629d6b92ffaSHans Petter Selasky 
1630d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
1631d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd) {
1632d6b92ffaSHans Petter Selasky 		ucma_modify_qp_err(id);
1633d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
1634d6b92ffaSHans Petter Selasky 	}
1635d6b92ffaSHans Petter Selasky 
1636d6b92ffaSHans Petter Selasky 	if (ucma_is_ud_qp(id->qp_type))
1637d6b92ffaSHans Petter Selasky 		return 0;
1638d6b92ffaSHans Petter Selasky 
1639d6b92ffaSHans Petter Selasky 	return ucma_complete(id);
1640d6b92ffaSHans Petter Selasky }
1641d6b92ffaSHans Petter Selasky 
rdma_reject(struct rdma_cm_id * id,const void * private_data,uint8_t private_data_len)1642d6b92ffaSHans Petter Selasky int rdma_reject(struct rdma_cm_id *id, const void *private_data,
1643d6b92ffaSHans Petter Selasky 		uint8_t private_data_len)
1644d6b92ffaSHans Petter Selasky {
1645d6b92ffaSHans Petter Selasky 	struct ucma_abi_reject cmd;
1646d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
1647d6b92ffaSHans Petter Selasky 	int ret;
1648d6b92ffaSHans Petter Selasky 
1649d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD(&cmd, sizeof cmd, REJECT);
1650d6b92ffaSHans Petter Selasky 
1651d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
1652d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
1653d6b92ffaSHans Petter Selasky 	if (private_data && private_data_len) {
1654d6b92ffaSHans Petter Selasky 		memcpy(cmd.private_data, private_data, private_data_len);
1655d6b92ffaSHans Petter Selasky 		cmd.private_data_len = private_data_len;
1656d6b92ffaSHans Petter Selasky 	}
1657d6b92ffaSHans Petter Selasky 
1658d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
1659d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
1660d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
1661d6b92ffaSHans Petter Selasky 
1662d6b92ffaSHans Petter Selasky 	return 0;
1663d6b92ffaSHans Petter Selasky }
1664d6b92ffaSHans Petter Selasky 
rdma_notify(struct rdma_cm_id * id,enum ibv_event_type event)1665d6b92ffaSHans Petter Selasky int rdma_notify(struct rdma_cm_id *id, enum ibv_event_type event)
1666d6b92ffaSHans Petter Selasky {
1667d6b92ffaSHans Petter Selasky 	struct ucma_abi_notify cmd;
1668d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
1669d6b92ffaSHans Petter Selasky 	int ret;
1670d6b92ffaSHans Petter Selasky 
1671d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD(&cmd, sizeof cmd, NOTIFY);
1672d6b92ffaSHans Petter Selasky 
1673d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
1674d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
1675d6b92ffaSHans Petter Selasky 	cmd.event = event;
1676d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
1677d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
1678d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
1679d6b92ffaSHans Petter Selasky 
1680d6b92ffaSHans Petter Selasky 	return 0;
1681d6b92ffaSHans Petter Selasky }
1682d6b92ffaSHans Petter Selasky 
ucma_shutdown(struct rdma_cm_id * id)1683d6b92ffaSHans Petter Selasky int ucma_shutdown(struct rdma_cm_id *id)
1684d6b92ffaSHans Petter Selasky {
1685d6b92ffaSHans Petter Selasky 	switch (id->verbs->device->transport_type) {
1686d6b92ffaSHans Petter Selasky 	case IBV_TRANSPORT_IB:
1687d6b92ffaSHans Petter Selasky 		return ucma_modify_qp_err(id);
1688d6b92ffaSHans Petter Selasky 	case IBV_TRANSPORT_IWARP:
1689d6b92ffaSHans Petter Selasky 		return ucma_modify_qp_sqd(id);
1690d6b92ffaSHans Petter Selasky 	default:
1691d6b92ffaSHans Petter Selasky 		return ERR(EINVAL);
1692d6b92ffaSHans Petter Selasky 	}
1693d6b92ffaSHans Petter Selasky }
1694d6b92ffaSHans Petter Selasky 
rdma_disconnect(struct rdma_cm_id * id)1695d6b92ffaSHans Petter Selasky int rdma_disconnect(struct rdma_cm_id *id)
1696d6b92ffaSHans Petter Selasky {
1697d6b92ffaSHans Petter Selasky 	struct ucma_abi_disconnect cmd;
1698d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
1699d6b92ffaSHans Petter Selasky 	int ret;
1700d6b92ffaSHans Petter Selasky 
1701d6b92ffaSHans Petter Selasky 	ret = ucma_shutdown(id);
1702d6b92ffaSHans Petter Selasky 	if (ret)
1703d6b92ffaSHans Petter Selasky 		return ret;
1704d6b92ffaSHans Petter Selasky 
1705d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD(&cmd, sizeof cmd, DISCONNECT);
1706d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
1707d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
1708d6b92ffaSHans Petter Selasky 
1709d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
1710d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
1711d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
1712d6b92ffaSHans Petter Selasky 
1713d6b92ffaSHans Petter Selasky 	return ucma_complete(id);
1714d6b92ffaSHans Petter Selasky }
1715d6b92ffaSHans Petter Selasky 
rdma_join_multicast2(struct rdma_cm_id * id,struct sockaddr * addr,socklen_t addrlen,void * context)1716d6b92ffaSHans Petter Selasky static int rdma_join_multicast2(struct rdma_cm_id *id, struct sockaddr *addr,
1717d6b92ffaSHans Petter Selasky 				socklen_t addrlen, void *context)
1718d6b92ffaSHans Petter Selasky {
1719d6b92ffaSHans Petter Selasky 	struct ucma_abi_create_id_resp resp;
1720d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
1721d6b92ffaSHans Petter Selasky 	struct cma_multicast *mc, **pos;
1722d6b92ffaSHans Petter Selasky 	int ret;
1723d6b92ffaSHans Petter Selasky 
1724d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
1725d6b92ffaSHans Petter Selasky 	mc = calloc(1, sizeof(*mc));
1726d6b92ffaSHans Petter Selasky 	if (!mc)
1727d6b92ffaSHans Petter Selasky 		return ERR(ENOMEM);
1728d6b92ffaSHans Petter Selasky 
1729d6b92ffaSHans Petter Selasky 	mc->context = context;
1730d6b92ffaSHans Petter Selasky 	mc->id_priv = id_priv;
1731d6b92ffaSHans Petter Selasky 	memcpy(&mc->addr, addr, addrlen);
1732d6b92ffaSHans Petter Selasky 	if (pthread_cond_init(&mc->cond, NULL)) {
1733d6b92ffaSHans Petter Selasky 		ret = -1;
1734d6b92ffaSHans Petter Selasky 		goto err1;
1735d6b92ffaSHans Petter Selasky 	}
1736d6b92ffaSHans Petter Selasky 
1737d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&id_priv->mut);
1738d6b92ffaSHans Petter Selasky 	mc->next = id_priv->mc_list;
1739d6b92ffaSHans Petter Selasky 	id_priv->mc_list = mc;
1740d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&id_priv->mut);
1741d6b92ffaSHans Petter Selasky 
1742d6b92ffaSHans Petter Selasky 	if (af_ib_support) {
1743d6b92ffaSHans Petter Selasky 		struct ucma_abi_join_mcast cmd;
1744d6b92ffaSHans Petter Selasky 
1745d6b92ffaSHans Petter Selasky 		CMA_INIT_CMD_RESP(&cmd, sizeof cmd, JOIN_MCAST, &resp, sizeof resp);
1746d6b92ffaSHans Petter Selasky 		cmd.id = id_priv->handle;
1747d6b92ffaSHans Petter Selasky 		memcpy(&cmd.addr, addr, addrlen);
1748d6b92ffaSHans Petter Selasky 		cmd.addr_size = addrlen;
1749d6b92ffaSHans Petter Selasky 		cmd.uid = (uintptr_t) mc;
1750d6b92ffaSHans Petter Selasky 		cmd.reserved = 0;
1751d6b92ffaSHans Petter Selasky 
1752d6b92ffaSHans Petter Selasky 		ret = write(id->channel->fd, &cmd, sizeof cmd);
1753d6b92ffaSHans Petter Selasky 		if (ret != sizeof cmd) {
1754d6b92ffaSHans Petter Selasky 			ret = (ret >= 0) ? ERR(ENODATA) : -1;
1755d6b92ffaSHans Petter Selasky 			goto err2;
1756d6b92ffaSHans Petter Selasky 		}
1757d6b92ffaSHans Petter Selasky 	} else {
1758d6b92ffaSHans Petter Selasky 		struct ucma_abi_join_ip_mcast cmd;
1759d6b92ffaSHans Petter Selasky 
1760d6b92ffaSHans Petter Selasky 		CMA_INIT_CMD_RESP(&cmd, sizeof cmd, JOIN_IP_MCAST, &resp, sizeof resp);
1761d6b92ffaSHans Petter Selasky 		cmd.id = id_priv->handle;
1762d6b92ffaSHans Petter Selasky 		memcpy(&cmd.addr, addr, addrlen);
1763d6b92ffaSHans Petter Selasky 		cmd.uid = (uintptr_t) mc;
1764d6b92ffaSHans Petter Selasky 
1765d6b92ffaSHans Petter Selasky 		ret = write(id->channel->fd, &cmd, sizeof cmd);
1766d6b92ffaSHans Petter Selasky 		if (ret != sizeof cmd) {
1767d6b92ffaSHans Petter Selasky 			ret = (ret >= 0) ? ERR(ENODATA) : -1;
1768d6b92ffaSHans Petter Selasky 			goto err2;
1769d6b92ffaSHans Petter Selasky 		}
1770d6b92ffaSHans Petter Selasky 	}
1771d6b92ffaSHans Petter Selasky 
1772d6b92ffaSHans Petter Selasky 	VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
1773d6b92ffaSHans Petter Selasky 
1774d6b92ffaSHans Petter Selasky 	mc->handle = resp.id;
1775d6b92ffaSHans Petter Selasky 	return ucma_complete(id);
1776d6b92ffaSHans Petter Selasky 
1777d6b92ffaSHans Petter Selasky err2:
1778d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&id_priv->mut);
1779d6b92ffaSHans Petter Selasky 	for (pos = &id_priv->mc_list; *pos != mc; pos = &(*pos)->next)
1780d6b92ffaSHans Petter Selasky 		;
1781d6b92ffaSHans Petter Selasky 	*pos = mc->next;
1782d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&id_priv->mut);
1783d6b92ffaSHans Petter Selasky err1:
1784d6b92ffaSHans Petter Selasky 	free(mc);
1785d6b92ffaSHans Petter Selasky 	return ret;
1786d6b92ffaSHans Petter Selasky }
1787d6b92ffaSHans Petter Selasky 
rdma_join_multicast(struct rdma_cm_id * id,struct sockaddr * addr,void * context)1788d6b92ffaSHans Petter Selasky int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
1789d6b92ffaSHans Petter Selasky 			void *context)
1790d6b92ffaSHans Petter Selasky {
1791d6b92ffaSHans Petter Selasky 	int addrlen;
1792d6b92ffaSHans Petter Selasky 
1793d6b92ffaSHans Petter Selasky 	addrlen = ucma_addrlen(addr);
1794d6b92ffaSHans Petter Selasky 	if (!addrlen)
1795d6b92ffaSHans Petter Selasky 		return ERR(EINVAL);
1796d6b92ffaSHans Petter Selasky 
1797d6b92ffaSHans Petter Selasky 	return rdma_join_multicast2(id, addr, addrlen, context);
1798d6b92ffaSHans Petter Selasky }
1799d6b92ffaSHans Petter Selasky 
rdma_leave_multicast(struct rdma_cm_id * id,struct sockaddr * addr)1800d6b92ffaSHans Petter Selasky int rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)
1801d6b92ffaSHans Petter Selasky {
1802d6b92ffaSHans Petter Selasky 	struct ucma_abi_destroy_id cmd;
1803d6b92ffaSHans Petter Selasky 	struct ucma_abi_destroy_id_resp resp;
1804d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
1805d6b92ffaSHans Petter Selasky 	struct cma_multicast *mc, **pos;
1806d6b92ffaSHans Petter Selasky 	int ret, addrlen;
1807d6b92ffaSHans Petter Selasky 
1808d6b92ffaSHans Petter Selasky 	addrlen = ucma_addrlen(addr);
1809d6b92ffaSHans Petter Selasky 	if (!addrlen)
1810d6b92ffaSHans Petter Selasky 		return ERR(EINVAL);
1811d6b92ffaSHans Petter Selasky 
1812d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
1813d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&id_priv->mut);
1814d6b92ffaSHans Petter Selasky 	for (pos = &id_priv->mc_list; *pos; pos = &(*pos)->next)
1815d6b92ffaSHans Petter Selasky 		if (!memcmp(&(*pos)->addr, addr, addrlen))
1816d6b92ffaSHans Petter Selasky 			break;
1817d6b92ffaSHans Petter Selasky 
1818d6b92ffaSHans Petter Selasky 	mc = *pos;
1819d6b92ffaSHans Petter Selasky 	if (*pos)
1820d6b92ffaSHans Petter Selasky 		*pos = mc->next;
1821d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&id_priv->mut);
1822d6b92ffaSHans Petter Selasky 	if (!mc)
1823d6b92ffaSHans Petter Selasky 		return ERR(EADDRNOTAVAIL);
1824d6b92ffaSHans Petter Selasky 
1825d6b92ffaSHans Petter Selasky 	if (id->qp)
1826d6b92ffaSHans Petter Selasky 		ibv_detach_mcast(id->qp, &mc->mgid, mc->mlid);
1827d6b92ffaSHans Petter Selasky 
1828d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD_RESP(&cmd, sizeof cmd, LEAVE_MCAST, &resp, sizeof resp);
1829d6b92ffaSHans Petter Selasky 	cmd.id = mc->handle;
1830d6b92ffaSHans Petter Selasky 
1831d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
1832d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd) {
1833d6b92ffaSHans Petter Selasky 		ret = (ret >= 0) ? ERR(ENODATA) : -1;
1834d6b92ffaSHans Petter Selasky 		goto free;
1835d6b92ffaSHans Petter Selasky 	}
1836d6b92ffaSHans Petter Selasky 
1837d6b92ffaSHans Petter Selasky 	VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
1838d6b92ffaSHans Petter Selasky 
1839d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&id_priv->mut);
1840d6b92ffaSHans Petter Selasky 	while (mc->events_completed < resp.events_reported)
1841d6b92ffaSHans Petter Selasky 		pthread_cond_wait(&mc->cond, &id_priv->mut);
1842d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&id_priv->mut);
1843d6b92ffaSHans Petter Selasky 
1844d6b92ffaSHans Petter Selasky 	ret = 0;
1845d6b92ffaSHans Petter Selasky free:
1846d6b92ffaSHans Petter Selasky 	free(mc);
1847d6b92ffaSHans Petter Selasky 	return ret;
1848d6b92ffaSHans Petter Selasky }
1849d6b92ffaSHans Petter Selasky 
ucma_complete_event(struct cma_id_private * id_priv)1850d6b92ffaSHans Petter Selasky static void ucma_complete_event(struct cma_id_private *id_priv)
1851d6b92ffaSHans Petter Selasky {
1852d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&id_priv->mut);
1853d6b92ffaSHans Petter Selasky 	id_priv->events_completed++;
1854d6b92ffaSHans Petter Selasky 	pthread_cond_signal(&id_priv->cond);
1855d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&id_priv->mut);
1856d6b92ffaSHans Petter Selasky }
1857d6b92ffaSHans Petter Selasky 
ucma_complete_mc_event(struct cma_multicast * mc)1858d6b92ffaSHans Petter Selasky static void ucma_complete_mc_event(struct cma_multicast *mc)
1859d6b92ffaSHans Petter Selasky {
1860d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&mc->id_priv->mut);
1861d6b92ffaSHans Petter Selasky 	mc->events_completed++;
1862d6b92ffaSHans Petter Selasky 	pthread_cond_signal(&mc->cond);
1863d6b92ffaSHans Petter Selasky 	mc->id_priv->events_completed++;
1864d6b92ffaSHans Petter Selasky 	pthread_cond_signal(&mc->id_priv->cond);
1865d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&mc->id_priv->mut);
1866d6b92ffaSHans Petter Selasky }
1867d6b92ffaSHans Petter Selasky 
rdma_ack_cm_event(struct rdma_cm_event * event)1868d6b92ffaSHans Petter Selasky int rdma_ack_cm_event(struct rdma_cm_event *event)
1869d6b92ffaSHans Petter Selasky {
1870d6b92ffaSHans Petter Selasky 	struct cma_event *evt;
1871d6b92ffaSHans Petter Selasky 
1872d6b92ffaSHans Petter Selasky 	if (!event)
1873d6b92ffaSHans Petter Selasky 		return ERR(EINVAL);
1874d6b92ffaSHans Petter Selasky 
1875d6b92ffaSHans Petter Selasky 	evt = container_of(event, struct cma_event, event);
1876d6b92ffaSHans Petter Selasky 
1877d6b92ffaSHans Petter Selasky 	if (evt->mc)
1878d6b92ffaSHans Petter Selasky 		ucma_complete_mc_event(evt->mc);
1879d6b92ffaSHans Petter Selasky 	else
1880d6b92ffaSHans Petter Selasky 		ucma_complete_event(evt->id_priv);
1881d6b92ffaSHans Petter Selasky 	free(evt);
1882d6b92ffaSHans Petter Selasky 	return 0;
1883d6b92ffaSHans Petter Selasky }
1884d6b92ffaSHans Petter Selasky 
ucma_process_addr_resolved(struct cma_event * evt)1885d6b92ffaSHans Petter Selasky static void ucma_process_addr_resolved(struct cma_event *evt)
1886d6b92ffaSHans Petter Selasky {
1887d6b92ffaSHans Petter Selasky 	if (af_ib_support) {
1888d6b92ffaSHans Petter Selasky 		evt->event.status = ucma_query_addr(&evt->id_priv->id);
1889d6b92ffaSHans Petter Selasky 		if (!evt->event.status &&
1890d6b92ffaSHans Petter Selasky 		    evt->id_priv->id.verbs->device->transport_type == IBV_TRANSPORT_IB)
1891d6b92ffaSHans Petter Selasky 			evt->event.status = ucma_query_gid(&evt->id_priv->id);
1892d6b92ffaSHans Petter Selasky 	} else {
1893d6b92ffaSHans Petter Selasky 		evt->event.status = ucma_query_route(&evt->id_priv->id);
1894d6b92ffaSHans Petter Selasky 	}
1895d6b92ffaSHans Petter Selasky 
1896d6b92ffaSHans Petter Selasky 	if (evt->event.status)
1897d6b92ffaSHans Petter Selasky 		evt->event.event = RDMA_CM_EVENT_ADDR_ERROR;
1898d6b92ffaSHans Petter Selasky }
1899d6b92ffaSHans Petter Selasky 
ucma_process_route_resolved(struct cma_event * evt)1900d6b92ffaSHans Petter Selasky static void ucma_process_route_resolved(struct cma_event *evt)
1901d6b92ffaSHans Petter Selasky {
1902d6b92ffaSHans Petter Selasky 	if (evt->id_priv->id.verbs->device->transport_type != IBV_TRANSPORT_IB)
1903d6b92ffaSHans Petter Selasky 		return;
1904d6b92ffaSHans Petter Selasky 
1905d6b92ffaSHans Petter Selasky 	if (af_ib_support)
1906d6b92ffaSHans Petter Selasky 		evt->event.status = ucma_query_path(&evt->id_priv->id);
1907d6b92ffaSHans Petter Selasky 	else
1908d6b92ffaSHans Petter Selasky 		evt->event.status = ucma_query_route(&evt->id_priv->id);
1909d6b92ffaSHans Petter Selasky 
1910d6b92ffaSHans Petter Selasky 	if (evt->event.status)
1911d6b92ffaSHans Petter Selasky 		evt->event.event = RDMA_CM_EVENT_ROUTE_ERROR;
1912d6b92ffaSHans Petter Selasky }
1913d6b92ffaSHans Petter Selasky 
ucma_query_req_info(struct rdma_cm_id * id)1914d6b92ffaSHans Petter Selasky static int ucma_query_req_info(struct rdma_cm_id *id)
1915d6b92ffaSHans Petter Selasky {
1916d6b92ffaSHans Petter Selasky 	int ret;
1917d6b92ffaSHans Petter Selasky 
1918d6b92ffaSHans Petter Selasky 	if (!af_ib_support)
1919d6b92ffaSHans Petter Selasky 		return ucma_query_route(id);
1920d6b92ffaSHans Petter Selasky 
1921d6b92ffaSHans Petter Selasky 	ret = ucma_query_addr(id);
1922d6b92ffaSHans Petter Selasky 	if (ret)
1923d6b92ffaSHans Petter Selasky 		return ret;
1924d6b92ffaSHans Petter Selasky 
1925d6b92ffaSHans Petter Selasky 	ret = ucma_query_gid(id);
1926d6b92ffaSHans Petter Selasky 	if (ret)
1927d6b92ffaSHans Petter Selasky 		return ret;
1928d6b92ffaSHans Petter Selasky 
1929d6b92ffaSHans Petter Selasky 	ret = ucma_query_path(id);
1930d6b92ffaSHans Petter Selasky 	if (ret)
1931d6b92ffaSHans Petter Selasky 		return ret;
1932d6b92ffaSHans Petter Selasky 
1933d6b92ffaSHans Petter Selasky 	return 0;
1934d6b92ffaSHans Petter Selasky }
1935d6b92ffaSHans Petter Selasky 
ucma_process_conn_req(struct cma_event * evt,uint32_t handle)1936d6b92ffaSHans Petter Selasky static int ucma_process_conn_req(struct cma_event *evt,
1937d6b92ffaSHans Petter Selasky 				 uint32_t handle)
1938d6b92ffaSHans Petter Selasky {
1939d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
1940d6b92ffaSHans Petter Selasky 	int ret;
1941d6b92ffaSHans Petter Selasky 
1942d6b92ffaSHans Petter Selasky 	id_priv = ucma_alloc_id(evt->id_priv->id.channel,
1943d6b92ffaSHans Petter Selasky 				evt->id_priv->id.context, evt->id_priv->id.ps,
1944d6b92ffaSHans Petter Selasky 				evt->id_priv->id.qp_type);
1945d6b92ffaSHans Petter Selasky 	if (!id_priv) {
1946d6b92ffaSHans Petter Selasky 		ucma_destroy_kern_id(evt->id_priv->id.channel->fd, handle);
1947d6b92ffaSHans Petter Selasky 		ret = ERR(ENOMEM);
1948d6b92ffaSHans Petter Selasky 		goto err1;
1949d6b92ffaSHans Petter Selasky 	}
1950d6b92ffaSHans Petter Selasky 
1951d6b92ffaSHans Petter Selasky 	evt->event.listen_id = &evt->id_priv->id;
1952d6b92ffaSHans Petter Selasky 	evt->event.id = &id_priv->id;
1953d6b92ffaSHans Petter Selasky 	id_priv->handle = handle;
1954d6b92ffaSHans Petter Selasky 	ucma_insert_id(id_priv);
1955d6b92ffaSHans Petter Selasky 	id_priv->initiator_depth = evt->event.param.conn.initiator_depth;
1956d6b92ffaSHans Petter Selasky 	id_priv->responder_resources = evt->event.param.conn.responder_resources;
1957d6b92ffaSHans Petter Selasky 
1958d6b92ffaSHans Petter Selasky 	if (evt->id_priv->sync) {
1959d6b92ffaSHans Petter Selasky 		ret = rdma_migrate_id(&id_priv->id, NULL);
1960d6b92ffaSHans Petter Selasky 		if (ret)
1961d6b92ffaSHans Petter Selasky 			goto err2;
1962d6b92ffaSHans Petter Selasky 	}
1963d6b92ffaSHans Petter Selasky 
1964d6b92ffaSHans Petter Selasky 	ret = ucma_query_req_info(&id_priv->id);
1965d6b92ffaSHans Petter Selasky 	if (ret)
1966d6b92ffaSHans Petter Selasky 		goto err2;
1967d6b92ffaSHans Petter Selasky 
1968d6b92ffaSHans Petter Selasky 	return 0;
1969d6b92ffaSHans Petter Selasky 
1970d6b92ffaSHans Petter Selasky err2:
1971d6b92ffaSHans Petter Selasky 	rdma_destroy_id(&id_priv->id);
1972d6b92ffaSHans Petter Selasky err1:
1973d6b92ffaSHans Petter Selasky 	ucma_complete_event(evt->id_priv);
1974d6b92ffaSHans Petter Selasky 	return ret;
1975d6b92ffaSHans Petter Selasky }
1976d6b92ffaSHans Petter Selasky 
ucma_process_conn_resp(struct cma_id_private * id_priv)1977d6b92ffaSHans Petter Selasky static int ucma_process_conn_resp(struct cma_id_private *id_priv)
1978d6b92ffaSHans Petter Selasky {
1979d6b92ffaSHans Petter Selasky 	struct ucma_abi_accept cmd;
1980d6b92ffaSHans Petter Selasky 	int ret;
1981d6b92ffaSHans Petter Selasky 
1982d6b92ffaSHans Petter Selasky 	ret = ucma_modify_qp_rtr(&id_priv->id, RDMA_MAX_RESP_RES);
1983d6b92ffaSHans Petter Selasky 	if (ret)
1984d6b92ffaSHans Petter Selasky 		goto err;
1985d6b92ffaSHans Petter Selasky 
1986d6b92ffaSHans Petter Selasky 	ret = ucma_modify_qp_rts(&id_priv->id, RDMA_MAX_INIT_DEPTH);
1987d6b92ffaSHans Petter Selasky 	if (ret)
1988d6b92ffaSHans Petter Selasky 		goto err;
1989d6b92ffaSHans Petter Selasky 
1990d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD(&cmd, sizeof cmd, ACCEPT);
1991d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
1992d6b92ffaSHans Petter Selasky 
1993d6b92ffaSHans Petter Selasky 	ret = write(id_priv->id.channel->fd, &cmd, sizeof cmd);
1994d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd) {
1995d6b92ffaSHans Petter Selasky 		ret = (ret >= 0) ? ERR(ENODATA) : -1;
1996d6b92ffaSHans Petter Selasky 		goto err;
1997d6b92ffaSHans Petter Selasky 	}
1998d6b92ffaSHans Petter Selasky 
1999d6b92ffaSHans Petter Selasky 	return 0;
2000d6b92ffaSHans Petter Selasky err:
2001d6b92ffaSHans Petter Selasky 	ucma_modify_qp_err(&id_priv->id);
2002d6b92ffaSHans Petter Selasky 	return ret;
2003d6b92ffaSHans Petter Selasky }
2004d6b92ffaSHans Petter Selasky 
ucma_process_join(struct cma_event * evt)2005d6b92ffaSHans Petter Selasky static int ucma_process_join(struct cma_event *evt)
2006d6b92ffaSHans Petter Selasky {
2007d6b92ffaSHans Petter Selasky 	evt->mc->mgid = evt->event.param.ud.ah_attr.grh.dgid;
2008d6b92ffaSHans Petter Selasky 	evt->mc->mlid = evt->event.param.ud.ah_attr.dlid;
2009d6b92ffaSHans Petter Selasky 
2010d6b92ffaSHans Petter Selasky 	if (!evt->id_priv->id.qp)
2011d6b92ffaSHans Petter Selasky 		return 0;
2012d6b92ffaSHans Petter Selasky 
2013d6b92ffaSHans Petter Selasky 	return rdma_seterrno(ibv_attach_mcast(evt->id_priv->id.qp,
2014d6b92ffaSHans Petter Selasky 					      &evt->mc->mgid, evt->mc->mlid));
2015d6b92ffaSHans Petter Selasky }
2016d6b92ffaSHans Petter Selasky 
ucma_copy_conn_event(struct cma_event * event,struct ucma_abi_conn_param * src)2017d6b92ffaSHans Petter Selasky static void ucma_copy_conn_event(struct cma_event *event,
2018d6b92ffaSHans Petter Selasky 				 struct ucma_abi_conn_param *src)
2019d6b92ffaSHans Petter Selasky {
2020d6b92ffaSHans Petter Selasky 	struct rdma_conn_param *dst = &event->event.param.conn;
2021d6b92ffaSHans Petter Selasky 
2022d6b92ffaSHans Petter Selasky 	dst->private_data_len = src->private_data_len;
2023d6b92ffaSHans Petter Selasky 	if (src->private_data_len) {
2024d6b92ffaSHans Petter Selasky 		dst->private_data = &event->private_data;
2025d6b92ffaSHans Petter Selasky 		memcpy(&event->private_data, src->private_data,
2026d6b92ffaSHans Petter Selasky 		       src->private_data_len);
2027d6b92ffaSHans Petter Selasky 	}
2028d6b92ffaSHans Petter Selasky 
2029d6b92ffaSHans Petter Selasky 	dst->responder_resources = src->responder_resources;
2030d6b92ffaSHans Petter Selasky 	dst->initiator_depth = src->initiator_depth;
2031d6b92ffaSHans Petter Selasky 	dst->flow_control = src->flow_control;
2032d6b92ffaSHans Petter Selasky 	dst->retry_count = src->retry_count;
2033d6b92ffaSHans Petter Selasky 	dst->rnr_retry_count = src->rnr_retry_count;
2034d6b92ffaSHans Petter Selasky 	dst->srq = src->srq;
2035d6b92ffaSHans Petter Selasky 	dst->qp_num = src->qp_num;
2036d6b92ffaSHans Petter Selasky }
2037d6b92ffaSHans Petter Selasky 
ucma_copy_ud_event(struct cma_event * event,struct ucma_abi_ud_param * src)2038d6b92ffaSHans Petter Selasky static void ucma_copy_ud_event(struct cma_event *event,
2039d6b92ffaSHans Petter Selasky 			       struct ucma_abi_ud_param *src)
2040d6b92ffaSHans Petter Selasky {
2041d6b92ffaSHans Petter Selasky 	struct rdma_ud_param *dst = &event->event.param.ud;
2042d6b92ffaSHans Petter Selasky 
2043d6b92ffaSHans Petter Selasky 	dst->private_data_len = src->private_data_len;
2044d6b92ffaSHans Petter Selasky 	if (src->private_data_len) {
2045d6b92ffaSHans Petter Selasky 		dst->private_data = &event->private_data;
2046d6b92ffaSHans Petter Selasky 		memcpy(&event->private_data, src->private_data,
2047d6b92ffaSHans Petter Selasky 		       src->private_data_len);
2048d6b92ffaSHans Petter Selasky 	}
2049d6b92ffaSHans Petter Selasky 
2050d6b92ffaSHans Petter Selasky 	ibv_copy_ah_attr_from_kern(&dst->ah_attr, &src->ah_attr);
2051d6b92ffaSHans Petter Selasky 	dst->qp_num = src->qp_num;
2052d6b92ffaSHans Petter Selasky 	dst->qkey = src->qkey;
2053d6b92ffaSHans Petter Selasky }
2054d6b92ffaSHans Petter Selasky 
rdma_get_cm_event(struct rdma_event_channel * channel,struct rdma_cm_event ** event)2055d6b92ffaSHans Petter Selasky int rdma_get_cm_event(struct rdma_event_channel *channel,
2056d6b92ffaSHans Petter Selasky 		      struct rdma_cm_event **event)
2057d6b92ffaSHans Petter Selasky {
2058d6b92ffaSHans Petter Selasky 	struct ucma_abi_event_resp resp;
2059d6b92ffaSHans Petter Selasky 	struct ucma_abi_get_event cmd;
2060d6b92ffaSHans Petter Selasky 	struct cma_event *evt;
2061d6b92ffaSHans Petter Selasky 	int ret;
2062d6b92ffaSHans Petter Selasky 
2063d6b92ffaSHans Petter Selasky 	ret = ucma_init();
2064d6b92ffaSHans Petter Selasky 	if (ret)
2065d6b92ffaSHans Petter Selasky 		return ret;
2066d6b92ffaSHans Petter Selasky 
2067d6b92ffaSHans Petter Selasky 	if (!event)
2068d6b92ffaSHans Petter Selasky 		return ERR(EINVAL);
2069d6b92ffaSHans Petter Selasky 
2070d6b92ffaSHans Petter Selasky 	evt = malloc(sizeof(*evt));
2071d6b92ffaSHans Petter Selasky 	if (!evt)
2072d6b92ffaSHans Petter Selasky 		return ERR(ENOMEM);
2073d6b92ffaSHans Petter Selasky 
2074d6b92ffaSHans Petter Selasky retry:
2075d6b92ffaSHans Petter Selasky 	memset(evt, 0, sizeof(*evt));
2076d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD_RESP(&cmd, sizeof cmd, GET_EVENT, &resp, sizeof resp);
2077d6b92ffaSHans Petter Selasky 	ret = write(channel->fd, &cmd, sizeof cmd);
2078d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd) {
2079d6b92ffaSHans Petter Selasky 		free(evt);
2080d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
2081d6b92ffaSHans Petter Selasky 	}
2082d6b92ffaSHans Petter Selasky 
2083d6b92ffaSHans Petter Selasky 	VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
2084d6b92ffaSHans Petter Selasky 
2085d6b92ffaSHans Petter Selasky 	evt->event.event = resp.event;
2086d6b92ffaSHans Petter Selasky 	/*
2087d6b92ffaSHans Petter Selasky 	 * We should have a non-zero uid, except for connection requests.
2088d6b92ffaSHans Petter Selasky 	 * But a bug in older kernels can report a uid 0.  Work-around this
2089d6b92ffaSHans Petter Selasky 	 * issue by looking up the cma_id based on the kernel's id when the
2090d6b92ffaSHans Petter Selasky 	 * uid is 0 and we're processing a connection established event.
2091d6b92ffaSHans Petter Selasky 	 * In all other cases, if the uid is 0, we discard the event, like
2092d6b92ffaSHans Petter Selasky 	 * the kernel should have done.
2093d6b92ffaSHans Petter Selasky 	 */
2094d6b92ffaSHans Petter Selasky 	if (resp.uid) {
2095d6b92ffaSHans Petter Selasky 		evt->id_priv = (void *) (uintptr_t) resp.uid;
2096d6b92ffaSHans Petter Selasky 	} else {
2097d6b92ffaSHans Petter Selasky 		evt->id_priv = ucma_lookup_id(resp.id);
2098d6b92ffaSHans Petter Selasky 		if (!evt->id_priv) {
2099d6b92ffaSHans Petter Selasky 			syslog(LOG_WARNING, PFX "Warning: discarding unmatched "
2100d6b92ffaSHans Petter Selasky 				"event - rdma_destroy_id may hang.\n");
2101d6b92ffaSHans Petter Selasky 			goto retry;
2102d6b92ffaSHans Petter Selasky 		}
2103d6b92ffaSHans Petter Selasky 		if (resp.event != RDMA_CM_EVENT_ESTABLISHED) {
2104d6b92ffaSHans Petter Selasky 			ucma_complete_event(evt->id_priv);
2105d6b92ffaSHans Petter Selasky 			goto retry;
2106d6b92ffaSHans Petter Selasky 		}
2107d6b92ffaSHans Petter Selasky 	}
2108d6b92ffaSHans Petter Selasky 	evt->event.id = &evt->id_priv->id;
2109d6b92ffaSHans Petter Selasky 	evt->event.status = resp.status;
2110d6b92ffaSHans Petter Selasky 
2111d6b92ffaSHans Petter Selasky 	switch (resp.event) {
2112d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_ADDR_RESOLVED:
2113d6b92ffaSHans Petter Selasky 		ucma_process_addr_resolved(evt);
2114d6b92ffaSHans Petter Selasky 		break;
2115d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_ROUTE_RESOLVED:
2116d6b92ffaSHans Petter Selasky 		ucma_process_route_resolved(evt);
2117d6b92ffaSHans Petter Selasky 		break;
2118d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_CONNECT_REQUEST:
2119d6b92ffaSHans Petter Selasky 		evt->id_priv = (void *) (uintptr_t) resp.uid;
2120d6b92ffaSHans Petter Selasky 		if (ucma_is_ud_qp(evt->id_priv->id.qp_type))
2121d6b92ffaSHans Petter Selasky 			ucma_copy_ud_event(evt, &resp.param.ud);
2122d6b92ffaSHans Petter Selasky 		else
2123d6b92ffaSHans Petter Selasky 			ucma_copy_conn_event(evt, &resp.param.conn);
2124d6b92ffaSHans Petter Selasky 
2125d6b92ffaSHans Petter Selasky 		ret = ucma_process_conn_req(evt, resp.id);
2126d6b92ffaSHans Petter Selasky 		if (ret)
2127d6b92ffaSHans Petter Selasky 			goto retry;
2128d6b92ffaSHans Petter Selasky 		break;
2129d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_CONNECT_RESPONSE:
2130d6b92ffaSHans Petter Selasky 		ucma_copy_conn_event(evt, &resp.param.conn);
2131d6b92ffaSHans Petter Selasky 		evt->event.status = ucma_process_conn_resp(evt->id_priv);
2132d6b92ffaSHans Petter Selasky 		if (!evt->event.status)
2133d6b92ffaSHans Petter Selasky 			evt->event.event = RDMA_CM_EVENT_ESTABLISHED;
2134d6b92ffaSHans Petter Selasky 		else {
2135d6b92ffaSHans Petter Selasky 			evt->event.event = RDMA_CM_EVENT_CONNECT_ERROR;
2136d6b92ffaSHans Petter Selasky 			evt->id_priv->connect_error = 1;
2137d6b92ffaSHans Petter Selasky 		}
2138d6b92ffaSHans Petter Selasky 		break;
2139d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_ESTABLISHED:
2140d6b92ffaSHans Petter Selasky 		if (ucma_is_ud_qp(evt->id_priv->id.qp_type)) {
2141d6b92ffaSHans Petter Selasky 			ucma_copy_ud_event(evt, &resp.param.ud);
2142d6b92ffaSHans Petter Selasky 			break;
2143d6b92ffaSHans Petter Selasky 		}
2144d6b92ffaSHans Petter Selasky 
2145d6b92ffaSHans Petter Selasky 		ucma_copy_conn_event(evt, &resp.param.conn);
2146d6b92ffaSHans Petter Selasky 		break;
2147d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_REJECTED:
2148d6b92ffaSHans Petter Selasky 		if (evt->id_priv->connect_error) {
2149d6b92ffaSHans Petter Selasky 			ucma_complete_event(evt->id_priv);
2150d6b92ffaSHans Petter Selasky 			goto retry;
2151d6b92ffaSHans Petter Selasky 		}
2152d6b92ffaSHans Petter Selasky 		ucma_copy_conn_event(evt, &resp.param.conn);
2153d6b92ffaSHans Petter Selasky 		ucma_modify_qp_err(evt->event.id);
2154d6b92ffaSHans Petter Selasky 		break;
2155d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_DISCONNECTED:
2156d6b92ffaSHans Petter Selasky 		if (evt->id_priv->connect_error) {
2157d6b92ffaSHans Petter Selasky 			ucma_complete_event(evt->id_priv);
2158d6b92ffaSHans Petter Selasky 			goto retry;
2159d6b92ffaSHans Petter Selasky 		}
2160d6b92ffaSHans Petter Selasky 		ucma_copy_conn_event(evt, &resp.param.conn);
2161d6b92ffaSHans Petter Selasky 		break;
2162d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_MULTICAST_JOIN:
2163d6b92ffaSHans Petter Selasky 		evt->mc = (void *) (uintptr_t) resp.uid;
2164d6b92ffaSHans Petter Selasky 		evt->id_priv = evt->mc->id_priv;
2165d6b92ffaSHans Petter Selasky 		evt->event.id = &evt->id_priv->id;
2166d6b92ffaSHans Petter Selasky 		ucma_copy_ud_event(evt, &resp.param.ud);
2167d6b92ffaSHans Petter Selasky 		evt->event.param.ud.private_data = evt->mc->context;
2168d6b92ffaSHans Petter Selasky 		evt->event.status = ucma_process_join(evt);
2169d6b92ffaSHans Petter Selasky 		if (evt->event.status)
2170d6b92ffaSHans Petter Selasky 			evt->event.event = RDMA_CM_EVENT_MULTICAST_ERROR;
2171d6b92ffaSHans Petter Selasky 		break;
2172d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_MULTICAST_ERROR:
2173d6b92ffaSHans Petter Selasky 		evt->mc = (void *) (uintptr_t) resp.uid;
2174d6b92ffaSHans Petter Selasky 		evt->id_priv = evt->mc->id_priv;
2175d6b92ffaSHans Petter Selasky 		evt->event.id = &evt->id_priv->id;
2176d6b92ffaSHans Petter Selasky 		evt->event.param.ud.private_data = evt->mc->context;
2177d6b92ffaSHans Petter Selasky 		break;
2178d6b92ffaSHans Petter Selasky 	default:
2179d6b92ffaSHans Petter Selasky 		evt->id_priv = (void *) (uintptr_t) resp.uid;
2180d6b92ffaSHans Petter Selasky 		evt->event.id = &evt->id_priv->id;
2181d6b92ffaSHans Petter Selasky 		evt->event.status = resp.status;
2182d6b92ffaSHans Petter Selasky 		if (ucma_is_ud_qp(evt->id_priv->id.qp_type))
2183d6b92ffaSHans Petter Selasky 			ucma_copy_ud_event(evt, &resp.param.ud);
2184d6b92ffaSHans Petter Selasky 		else
2185d6b92ffaSHans Petter Selasky 			ucma_copy_conn_event(evt, &resp.param.conn);
2186d6b92ffaSHans Petter Selasky 		break;
2187d6b92ffaSHans Petter Selasky 	}
2188d6b92ffaSHans Petter Selasky 
2189d6b92ffaSHans Petter Selasky 	*event = &evt->event;
2190d6b92ffaSHans Petter Selasky 	return 0;
2191d6b92ffaSHans Petter Selasky }
2192d6b92ffaSHans Petter Selasky 
rdma_event_str(enum rdma_cm_event_type event)2193d6b92ffaSHans Petter Selasky const char *rdma_event_str(enum rdma_cm_event_type event)
2194d6b92ffaSHans Petter Selasky {
2195d6b92ffaSHans Petter Selasky 	switch (event) {
2196d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_ADDR_RESOLVED:
2197d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_ADDR_RESOLVED";
2198d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_ADDR_ERROR:
2199d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_ADDR_ERROR";
2200d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_ROUTE_RESOLVED:
2201d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_ROUTE_RESOLVED";
2202d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_ROUTE_ERROR:
2203d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_ROUTE_ERROR";
2204d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_CONNECT_REQUEST:
2205d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_CONNECT_REQUEST";
2206d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_CONNECT_RESPONSE:
2207d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_CONNECT_RESPONSE";
2208d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_CONNECT_ERROR:
2209d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_CONNECT_ERROR";
2210d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_UNREACHABLE:
2211d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_UNREACHABLE";
2212d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_REJECTED:
2213d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_REJECTED";
2214d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_ESTABLISHED:
2215d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_ESTABLISHED";
2216d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_DISCONNECTED:
2217d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_DISCONNECTED";
2218d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_DEVICE_REMOVAL:
2219d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_DEVICE_REMOVAL";
2220d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_MULTICAST_JOIN:
2221d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_MULTICAST_JOIN";
2222d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_MULTICAST_ERROR:
2223d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_MULTICAST_ERROR";
2224d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_ADDR_CHANGE:
2225d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_ADDR_CHANGE";
2226d6b92ffaSHans Petter Selasky 	case RDMA_CM_EVENT_TIMEWAIT_EXIT:
2227d6b92ffaSHans Petter Selasky 		return "RDMA_CM_EVENT_TIMEWAIT_EXIT";
2228d6b92ffaSHans Petter Selasky 	default:
2229d6b92ffaSHans Petter Selasky 		return "UNKNOWN EVENT";
2230d6b92ffaSHans Petter Selasky 	}
2231d6b92ffaSHans Petter Selasky }
2232d6b92ffaSHans Petter Selasky 
rdma_set_option(struct rdma_cm_id * id,int level,int optname,void * optval,size_t optlen)2233d6b92ffaSHans Petter Selasky int rdma_set_option(struct rdma_cm_id *id, int level, int optname,
2234d6b92ffaSHans Petter Selasky 		    void *optval, size_t optlen)
2235d6b92ffaSHans Petter Selasky {
2236d6b92ffaSHans Petter Selasky 	struct ucma_abi_set_option cmd;
2237d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
2238d6b92ffaSHans Petter Selasky 	int ret;
2239d6b92ffaSHans Petter Selasky 
2240d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD(&cmd, sizeof cmd, SET_OPTION);
2241d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
2242d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
2243d6b92ffaSHans Petter Selasky 	cmd.optval = (uintptr_t) optval;
2244d6b92ffaSHans Petter Selasky 	cmd.level = level;
2245d6b92ffaSHans Petter Selasky 	cmd.optname = optname;
2246d6b92ffaSHans Petter Selasky 	cmd.optlen = optlen;
2247d6b92ffaSHans Petter Selasky 
2248d6b92ffaSHans Petter Selasky 	ret = write(id->channel->fd, &cmd, sizeof cmd);
2249d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd)
2250d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
2251d6b92ffaSHans Petter Selasky 
2252d6b92ffaSHans Petter Selasky 	return 0;
2253d6b92ffaSHans Petter Selasky }
2254d6b92ffaSHans Petter Selasky 
rdma_migrate_id(struct rdma_cm_id * id,struct rdma_event_channel * channel)2255d6b92ffaSHans Petter Selasky int rdma_migrate_id(struct rdma_cm_id *id, struct rdma_event_channel *channel)
2256d6b92ffaSHans Petter Selasky {
2257d6b92ffaSHans Petter Selasky 	struct ucma_abi_migrate_resp resp;
2258d6b92ffaSHans Petter Selasky 	struct ucma_abi_migrate_id cmd;
2259d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
2260d6b92ffaSHans Petter Selasky 	int ret, sync;
2261d6b92ffaSHans Petter Selasky 
2262d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
2263d6b92ffaSHans Petter Selasky 	if (id_priv->sync && !channel)
2264d6b92ffaSHans Petter Selasky 		return ERR(EINVAL);
2265d6b92ffaSHans Petter Selasky 
2266d6b92ffaSHans Petter Selasky 	if ((sync = (channel == NULL))) {
2267d6b92ffaSHans Petter Selasky 		channel = rdma_create_event_channel();
2268d6b92ffaSHans Petter Selasky 		if (!channel)
2269d6b92ffaSHans Petter Selasky 			return -1;
2270d6b92ffaSHans Petter Selasky 	}
2271d6b92ffaSHans Petter Selasky 
2272d6b92ffaSHans Petter Selasky 	CMA_INIT_CMD_RESP(&cmd, sizeof cmd, MIGRATE_ID, &resp, sizeof resp);
2273d6b92ffaSHans Petter Selasky 	cmd.id = id_priv->handle;
2274d6b92ffaSHans Petter Selasky 	cmd.fd = id->channel->fd;
2275d6b92ffaSHans Petter Selasky 
2276d6b92ffaSHans Petter Selasky 	ret = write(channel->fd, &cmd, sizeof cmd);
2277d6b92ffaSHans Petter Selasky 	if (ret != sizeof cmd) {
2278d6b92ffaSHans Petter Selasky 		if (sync)
2279d6b92ffaSHans Petter Selasky 			rdma_destroy_event_channel(channel);
2280d6b92ffaSHans Petter Selasky 		return (ret >= 0) ? ERR(ENODATA) : -1;
2281d6b92ffaSHans Petter Selasky 	}
2282d6b92ffaSHans Petter Selasky 
2283d6b92ffaSHans Petter Selasky 	VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
2284d6b92ffaSHans Petter Selasky 
2285d6b92ffaSHans Petter Selasky 	if (id_priv->sync) {
2286d6b92ffaSHans Petter Selasky 		if (id->event) {
2287d6b92ffaSHans Petter Selasky 			rdma_ack_cm_event(id->event);
2288d6b92ffaSHans Petter Selasky 			id->event = NULL;
2289d6b92ffaSHans Petter Selasky 		}
2290d6b92ffaSHans Petter Selasky 		rdma_destroy_event_channel(id->channel);
2291d6b92ffaSHans Petter Selasky 	}
2292d6b92ffaSHans Petter Selasky 
2293d6b92ffaSHans Petter Selasky 	/*
2294d6b92ffaSHans Petter Selasky 	 * Eventually if we want to support migrating channels while events are
2295d6b92ffaSHans Petter Selasky 	 * being processed on the current channel, we need to block here while
2296d6b92ffaSHans Petter Selasky 	 * there are any outstanding events on the current channel for this id
2297d6b92ffaSHans Petter Selasky 	 * to prevent the user from processing events for this id on the old
2298d6b92ffaSHans Petter Selasky 	 * channel after this call returns.
2299d6b92ffaSHans Petter Selasky 	 */
2300d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&id_priv->mut);
2301d6b92ffaSHans Petter Selasky 	id_priv->sync = sync;
2302d6b92ffaSHans Petter Selasky 	id->channel = channel;
2303d6b92ffaSHans Petter Selasky 	while (id_priv->events_completed < resp.events_reported)
2304d6b92ffaSHans Petter Selasky 		pthread_cond_wait(&id_priv->cond, &id_priv->mut);
2305d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&id_priv->mut);
2306d6b92ffaSHans Petter Selasky 
2307d6b92ffaSHans Petter Selasky 	return 0;
2308d6b92ffaSHans Petter Selasky }
2309d6b92ffaSHans Petter Selasky 
ucma_passive_ep(struct rdma_cm_id * id,struct rdma_addrinfo * res,struct ibv_pd * pd,struct ibv_qp_init_attr * qp_init_attr)2310d6b92ffaSHans Petter Selasky static int ucma_passive_ep(struct rdma_cm_id *id, struct rdma_addrinfo *res,
2311d6b92ffaSHans Petter Selasky 			   struct ibv_pd *pd, struct ibv_qp_init_attr *qp_init_attr)
2312d6b92ffaSHans Petter Selasky {
2313d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
2314d6b92ffaSHans Petter Selasky 	int ret;
2315d6b92ffaSHans Petter Selasky 
2316d6b92ffaSHans Petter Selasky 	if (af_ib_support)
2317d6b92ffaSHans Petter Selasky 		ret = rdma_bind_addr2(id, res->ai_src_addr, res->ai_src_len);
2318d6b92ffaSHans Petter Selasky 	else
2319d6b92ffaSHans Petter Selasky 		ret = rdma_bind_addr(id, res->ai_src_addr);
2320d6b92ffaSHans Petter Selasky 	if (ret)
2321d6b92ffaSHans Petter Selasky 		return ret;
2322d6b92ffaSHans Petter Selasky 
2323d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
2324d6b92ffaSHans Petter Selasky 	if (pd)
2325d6b92ffaSHans Petter Selasky 		id->pd = pd;
2326d6b92ffaSHans Petter Selasky 
2327d6b92ffaSHans Petter Selasky 	if (qp_init_attr) {
2328d6b92ffaSHans Petter Selasky 		id_priv->qp_init_attr = malloc(sizeof(*qp_init_attr));
2329d6b92ffaSHans Petter Selasky 		if (!id_priv->qp_init_attr)
2330d6b92ffaSHans Petter Selasky 			return ERR(ENOMEM);
2331d6b92ffaSHans Petter Selasky 
2332d6b92ffaSHans Petter Selasky 		*id_priv->qp_init_attr = *qp_init_attr;
2333d6b92ffaSHans Petter Selasky 		id_priv->qp_init_attr->qp_type = res->ai_qp_type;
2334d6b92ffaSHans Petter Selasky 	}
2335d6b92ffaSHans Petter Selasky 
2336d6b92ffaSHans Petter Selasky 	return 0;
2337d6b92ffaSHans Petter Selasky }
2338d6b92ffaSHans Petter Selasky 
rdma_create_ep(struct rdma_cm_id ** id,struct rdma_addrinfo * res,struct ibv_pd * pd,struct ibv_qp_init_attr * qp_init_attr)2339d6b92ffaSHans Petter Selasky int rdma_create_ep(struct rdma_cm_id **id, struct rdma_addrinfo *res,
2340d6b92ffaSHans Petter Selasky 		   struct ibv_pd *pd, struct ibv_qp_init_attr *qp_init_attr)
2341d6b92ffaSHans Petter Selasky {
2342d6b92ffaSHans Petter Selasky 	struct rdma_cm_id *cm_id;
2343d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
2344d6b92ffaSHans Petter Selasky 	int ret;
2345d6b92ffaSHans Petter Selasky 
2346d6b92ffaSHans Petter Selasky 	ret = rdma_create_id2(NULL, &cm_id, NULL, res->ai_port_space, res->ai_qp_type);
2347d6b92ffaSHans Petter Selasky 	if (ret)
2348d6b92ffaSHans Petter Selasky 		return ret;
2349d6b92ffaSHans Petter Selasky 
2350d6b92ffaSHans Petter Selasky 	if (res->ai_flags & RAI_PASSIVE) {
2351d6b92ffaSHans Petter Selasky 		ret = ucma_passive_ep(cm_id, res, pd, qp_init_attr);
2352d6b92ffaSHans Petter Selasky 		if (ret)
2353d6b92ffaSHans Petter Selasky 			goto err;
2354d6b92ffaSHans Petter Selasky 		goto out;
2355d6b92ffaSHans Petter Selasky 	}
2356d6b92ffaSHans Petter Selasky 
2357d6b92ffaSHans Petter Selasky 	if (af_ib_support)
2358d6b92ffaSHans Petter Selasky 		ret = rdma_resolve_addr2(cm_id, res->ai_src_addr, res->ai_src_len,
2359d6b92ffaSHans Petter Selasky 					 res->ai_dst_addr, res->ai_dst_len, 2000);
2360d6b92ffaSHans Petter Selasky 	else
2361d6b92ffaSHans Petter Selasky 		ret = rdma_resolve_addr(cm_id, res->ai_src_addr, res->ai_dst_addr, 2000);
2362d6b92ffaSHans Petter Selasky 	if (ret)
2363d6b92ffaSHans Petter Selasky 		goto err;
2364d6b92ffaSHans Petter Selasky 
2365d6b92ffaSHans Petter Selasky 	if (res->ai_route_len) {
2366d6b92ffaSHans Petter Selasky 		ret = rdma_set_option(cm_id, RDMA_OPTION_IB, RDMA_OPTION_IB_PATH,
2367d6b92ffaSHans Petter Selasky 				      res->ai_route, res->ai_route_len);
2368d6b92ffaSHans Petter Selasky 		if (!ret)
2369d6b92ffaSHans Petter Selasky 			ret = ucma_complete(cm_id);
2370d6b92ffaSHans Petter Selasky 	} else {
2371d6b92ffaSHans Petter Selasky 		ret = rdma_resolve_route(cm_id, 2000);
2372d6b92ffaSHans Petter Selasky 	}
2373d6b92ffaSHans Petter Selasky 	if (ret)
2374d6b92ffaSHans Petter Selasky 		goto err;
2375d6b92ffaSHans Petter Selasky 
2376d6b92ffaSHans Petter Selasky 	if (qp_init_attr) {
2377d6b92ffaSHans Petter Selasky 		qp_init_attr->qp_type = res->ai_qp_type;
2378d6b92ffaSHans Petter Selasky 		ret = rdma_create_qp(cm_id, pd, qp_init_attr);
2379d6b92ffaSHans Petter Selasky 		if (ret)
2380d6b92ffaSHans Petter Selasky 			goto err;
2381d6b92ffaSHans Petter Selasky 	}
2382d6b92ffaSHans Petter Selasky 
2383d6b92ffaSHans Petter Selasky 	if (res->ai_connect_len) {
2384d6b92ffaSHans Petter Selasky 		id_priv = container_of(cm_id, struct cma_id_private, id);
2385d6b92ffaSHans Petter Selasky 		id_priv->connect = malloc(res->ai_connect_len);
2386d6b92ffaSHans Petter Selasky 		if (!id_priv->connect) {
2387d6b92ffaSHans Petter Selasky 			ret = ERR(ENOMEM);
2388d6b92ffaSHans Petter Selasky 			goto err;
2389d6b92ffaSHans Petter Selasky 		}
2390d6b92ffaSHans Petter Selasky 		memcpy(id_priv->connect, res->ai_connect, res->ai_connect_len);
2391d6b92ffaSHans Petter Selasky 		id_priv->connect_len = res->ai_connect_len;
2392d6b92ffaSHans Petter Selasky 	}
2393d6b92ffaSHans Petter Selasky 
2394d6b92ffaSHans Petter Selasky out:
2395d6b92ffaSHans Petter Selasky 	*id = cm_id;
2396d6b92ffaSHans Petter Selasky 	return 0;
2397d6b92ffaSHans Petter Selasky 
2398d6b92ffaSHans Petter Selasky err:
2399d6b92ffaSHans Petter Selasky 	rdma_destroy_ep(cm_id);
2400d6b92ffaSHans Petter Selasky 	return ret;
2401d6b92ffaSHans Petter Selasky }
2402d6b92ffaSHans Petter Selasky 
rdma_destroy_ep(struct rdma_cm_id * id)2403d6b92ffaSHans Petter Selasky void rdma_destroy_ep(struct rdma_cm_id *id)
2404d6b92ffaSHans Petter Selasky {
2405d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
2406d6b92ffaSHans Petter Selasky 
2407d6b92ffaSHans Petter Selasky 	if (id->qp)
2408d6b92ffaSHans Petter Selasky 		rdma_destroy_qp(id);
2409d6b92ffaSHans Petter Selasky 
2410d6b92ffaSHans Petter Selasky 	if (id->srq)
2411d6b92ffaSHans Petter Selasky 		rdma_destroy_srq(id);
2412d6b92ffaSHans Petter Selasky 
2413d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
2414d6b92ffaSHans Petter Selasky 	if (id_priv->qp_init_attr)
2415d6b92ffaSHans Petter Selasky 		free(id_priv->qp_init_attr);
2416d6b92ffaSHans Petter Selasky 
2417d6b92ffaSHans Petter Selasky 	rdma_destroy_id(id);
2418d6b92ffaSHans Petter Selasky }
2419d6b92ffaSHans Petter Selasky 
ucma_max_qpsize(struct rdma_cm_id * id)2420d6b92ffaSHans Petter Selasky int ucma_max_qpsize(struct rdma_cm_id *id)
2421d6b92ffaSHans Petter Selasky {
2422d6b92ffaSHans Petter Selasky 	struct cma_id_private *id_priv;
2423d6b92ffaSHans Petter Selasky 	int i, max_size = 0;
2424d6b92ffaSHans Petter Selasky 
2425d6b92ffaSHans Petter Selasky 	id_priv = container_of(id, struct cma_id_private, id);
2426d6b92ffaSHans Petter Selasky 	if (id && id_priv->cma_dev) {
2427d6b92ffaSHans Petter Selasky 		max_size = id_priv->cma_dev->max_qpsize;
2428d6b92ffaSHans Petter Selasky 	} else {
2429d6b92ffaSHans Petter Selasky 		ucma_init_all();
2430d6b92ffaSHans Petter Selasky 		for (i = 0; i < cma_dev_cnt; i++) {
2431d6b92ffaSHans Petter Selasky 			if (!max_size || max_size > cma_dev_array[i].max_qpsize)
2432d6b92ffaSHans Petter Selasky 				max_size = cma_dev_array[i].max_qpsize;
2433d6b92ffaSHans Petter Selasky 		}
2434d6b92ffaSHans Petter Selasky 	}
2435d6b92ffaSHans Petter Selasky 	return max_size;
2436d6b92ffaSHans Petter Selasky }
2437d6b92ffaSHans Petter Selasky 
ucma_get_port(struct sockaddr * addr)2438d6b92ffaSHans Petter Selasky __be16 ucma_get_port(struct sockaddr *addr)
2439d6b92ffaSHans Petter Selasky {
2440d6b92ffaSHans Petter Selasky 	switch (addr->sa_family) {
2441d6b92ffaSHans Petter Selasky 	case AF_INET:
2442d6b92ffaSHans Petter Selasky 		return ((struct sockaddr_in *) addr)->sin_port;
2443d6b92ffaSHans Petter Selasky 	case AF_INET6:
2444d6b92ffaSHans Petter Selasky 		return ((struct sockaddr_in6 *) addr)->sin6_port;
2445d6b92ffaSHans Petter Selasky 	case AF_IB:
2446d6b92ffaSHans Petter Selasky 		return htobe16((uint16_t) be64toh(((struct sockaddr_ib *) addr)->sib_sid));
2447d6b92ffaSHans Petter Selasky 	default:
2448d6b92ffaSHans Petter Selasky 		return 0;
2449d6b92ffaSHans Petter Selasky 	}
2450d6b92ffaSHans Petter Selasky }
2451d6b92ffaSHans Petter Selasky 
rdma_get_src_port(struct rdma_cm_id * id)2452d6b92ffaSHans Petter Selasky __be16 rdma_get_src_port(struct rdma_cm_id *id)
2453d6b92ffaSHans Petter Selasky {
2454d6b92ffaSHans Petter Selasky 	return ucma_get_port(&id->route.addr.src_addr);
2455d6b92ffaSHans Petter Selasky }
2456d6b92ffaSHans Petter Selasky 
rdma_get_dst_port(struct rdma_cm_id * id)2457d6b92ffaSHans Petter Selasky __be16 rdma_get_dst_port(struct rdma_cm_id *id)
2458d6b92ffaSHans Petter Selasky {
2459d6b92ffaSHans Petter Selasky 	return ucma_get_port(&id->route.addr.dst_addr);
2460d6b92ffaSHans Petter Selasky }
2461d6b92ffaSHans Petter Selasky 
2462