1219820Sjeff/*
2219820Sjeff * Copyright (c) 2005-2006 Intel Corporation.  All rights reserved.
3219820Sjeff *
4219820Sjeff * This software is available to you under a choice of one of two
5219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
6219820Sjeff * General Public License (GPL) Version 2, available from the file
7219820Sjeff * COPYING in the main directory of this source tree, or the
8219820Sjeff * OpenIB.org BSD license below:
9219820Sjeff *
10219820Sjeff *     Redistribution and use in source and binary forms, with or
11219820Sjeff *     without modification, are permitted provided that the following
12219820Sjeff *     conditions are met:
13219820Sjeff *
14219820Sjeff *      - Redistributions of source code must retain the above
15219820Sjeff *        copyright notice, this list of conditions and the following
16219820Sjeff *        disclaimer.
17219820Sjeff *
18219820Sjeff *      - Redistributions in binary form must reproduce the above
19219820Sjeff *        copyright notice, this list of conditions and the following
20219820Sjeff *        disclaimer in the documentation and/or other materials
21219820Sjeff *        provided with the distribution.
22219820Sjeff *
23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30219820Sjeff * SOFTWARE.
31219820Sjeff *
32219820Sjeff * $Id: cm.c 3453 2005-09-15 21:43:21Z sean.hefty $
33219820Sjeff */
34219820Sjeff
35219820Sjeff#if HAVE_CONFIG_H
36219820Sjeff#  include <config.h>
37219820Sjeff#endif /* HAVE_CONFIG_H */
38219820Sjeff
39219820Sjeff#include <stdlib.h>
40219820Sjeff#include <string.h>
41219820Sjeff#include <glob.h>
42219820Sjeff#include <stdio.h>
43219820Sjeff#include <fcntl.h>
44219820Sjeff#include <errno.h>
45219820Sjeff#include <stdint.h>
46219820Sjeff#include <poll.h>
47219820Sjeff#include <unistd.h>
48219820Sjeff#include <pthread.h>
49219820Sjeff#include <infiniband/endian.h>
50219820Sjeff#include <infiniband/byteswap.h>
51219820Sjeff#include <stddef.h>
52219820Sjeff
53219820Sjeff#include <infiniband/driver.h>
54219820Sjeff#include <infiniband/marshall.h>
55219820Sjeff#include <rdma/rdma_cma.h>
56219820Sjeff#include <rdma/rdma_cma_abi.h>
57219820Sjeff
58219820Sjeff#ifdef INCLUDE_VALGRIND
59219820Sjeff#   include <valgrind/memcheck.h>
60219820Sjeff#   ifndef VALGRIND_MAKE_MEM_DEFINED
61219820Sjeff#       warning "Valgrind requested, but VALGRIND_MAKE_MEM_DEFINED undefined"
62219820Sjeff#   endif
63219820Sjeff#endif
64219820Sjeff
65219820Sjeff#ifndef VALGRIND_MAKE_MEM_DEFINED
66219820Sjeff#   define VALGRIND_MAKE_MEM_DEFINED(addr,len)
67219820Sjeff#endif
68219820Sjeff
69219820Sjeff#define PFX "librdmacm: "
70219820Sjeff
71219820Sjeff#if __BYTE_ORDER == __LITTLE_ENDIAN
72219820Sjeffstatic inline uint64_t htonll(uint64_t x) { return bswap_64(x); }
73219820Sjeffstatic inline uint64_t ntohll(uint64_t x) { return bswap_64(x); }
74219820Sjeff#else
75219820Sjeffstatic inline uint64_t htonll(uint64_t x) { return x; }
76219820Sjeffstatic inline uint64_t ntohll(uint64_t x) { return x; }
77219820Sjeff#endif
78219820Sjeff
79219820Sjeffstatic inline int ERR(int err)
80219820Sjeff{
81219820Sjeff	errno = err;
82219820Sjeff	return -1;
83219820Sjeff}
84219820Sjeff
85219820Sjeff#define CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, type, size) \
86219820Sjeffdo {                                        \
87219820Sjeff	struct ucma_abi_cmd_hdr *hdr;         \
88219820Sjeff                                            \
89219820Sjeff	size = sizeof(*hdr) + sizeof(*cmd); \
90219820Sjeff	msg = alloca(size);                 \
91219820Sjeff	if (!msg)                           \
92219820Sjeff		return ERR(ENOMEM);         \
93219820Sjeff	hdr = msg;                          \
94219820Sjeff	cmd = msg + sizeof(*hdr);           \
95219820Sjeff	hdr->cmd = type;                    \
96219820Sjeff	hdr->in  = sizeof(*cmd);            \
97219820Sjeff	hdr->out = sizeof(*resp);           \
98219820Sjeff	memset(cmd, 0, sizeof(*cmd));       \
99219820Sjeff	resp = alloca(sizeof(*resp));       \
100219820Sjeff	if (!resp)                          \
101219820Sjeff		return ERR(ENOMEM);         \
102219820Sjeff	cmd->response = (uintptr_t)resp;\
103219820Sjeff} while (0)
104219820Sjeff
105219820Sjeff#define CMA_CREATE_MSG_CMD(msg, cmd, type, size) \
106219820Sjeffdo {                                        \
107219820Sjeff	struct ucma_abi_cmd_hdr *hdr;       \
108219820Sjeff                                            \
109219820Sjeff	size = sizeof(*hdr) + sizeof(*cmd); \
110219820Sjeff	msg = alloca(size);                 \
111219820Sjeff	if (!msg)                           \
112219820Sjeff		return ERR(ENOMEM);         \
113219820Sjeff	hdr = msg;                          \
114219820Sjeff	cmd = msg + sizeof(*hdr);           \
115219820Sjeff	hdr->cmd = type;                    \
116219820Sjeff	hdr->in  = sizeof(*cmd);            \
117219820Sjeff	hdr->out = 0;                       \
118219820Sjeff	memset(cmd, 0, sizeof(*cmd));       \
119219820Sjeff} while (0)
120219820Sjeff
121219820Sjeffstruct cma_device {
122219820Sjeff	struct ibv_context *verbs;
123219820Sjeff	uint64_t	    guid;
124219820Sjeff	int		    port_cnt;
125219820Sjeff	uint8_t		    max_initiator_depth;
126219820Sjeff	uint8_t		    max_responder_resources;
127219820Sjeff};
128219820Sjeff
129219820Sjeffstruct cma_id_private {
130219820Sjeff	struct rdma_cm_id id;
131219820Sjeff	struct cma_device *cma_dev;
132219820Sjeff	int		  events_completed;
133219820Sjeff	int		  connect_error;
134219820Sjeff	pthread_cond_t	  cond;
135219820Sjeff	pthread_mutex_t	  mut;
136219820Sjeff	uint32_t	  handle;
137219820Sjeff	struct cma_multicast *mc_list;
138219820Sjeff};
139219820Sjeff
140219820Sjeffstruct cma_multicast {
141219820Sjeff	struct cma_multicast  *next;
142219820Sjeff	struct cma_id_private *id_priv;
143219820Sjeff	void		*context;
144219820Sjeff	int		events_completed;
145219820Sjeff	pthread_cond_t	cond;
146219820Sjeff	uint32_t	handle;
147219820Sjeff	union ibv_gid	mgid;
148219820Sjeff	uint16_t	mlid;
149219820Sjeff	struct sockaddr_storage addr;
150219820Sjeff};
151219820Sjeff
152219820Sjeffstruct cma_event {
153219820Sjeff	struct rdma_cm_event	event;
154219820Sjeff	uint8_t			private_data[RDMA_MAX_PRIVATE_DATA];
155219820Sjeff	struct cma_id_private	*id_priv;
156219820Sjeff	struct cma_multicast	*mc;
157219820Sjeff};
158219820Sjeff
159219820Sjeffstatic struct cma_device *cma_dev_array;
160219820Sjeffstatic int cma_dev_cnt;
161219820Sjeffstatic pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
162219820Sjeffstatic int abi_ver = RDMA_USER_CM_MAX_ABI_VERSION;
163219820Sjeff
164219820Sjeff#define container_of(ptr, type, field) \
165219820Sjeff	((type *) ((void *)ptr - offsetof(type, field)))
166219820Sjeff
167219820Sjeffstatic void ucma_cleanup(void)
168219820Sjeff{
169219820Sjeff	if (cma_dev_cnt) {
170219820Sjeff		while (cma_dev_cnt)
171219820Sjeff			ibv_close_device(cma_dev_array[--cma_dev_cnt].verbs);
172219820Sjeff
173219820Sjeff		free(cma_dev_array);
174219820Sjeff		cma_dev_cnt = 0;
175219820Sjeff	}
176219820Sjeff}
177219820Sjeff
178219820Sjeffstatic int check_abi_version(void)
179219820Sjeff{
180219820Sjeff	char value[8];
181219820Sjeff
182219820Sjeff	if ((ibv_read_sysfs_file(ibv_get_sysfs_path(),
183219820Sjeff				 "class/misc/rdma_cm/abi_version",
184219820Sjeff				 value, sizeof value) < 0) &&
185219820Sjeff	    (ibv_read_sysfs_file(ibv_get_sysfs_path(),
186219820Sjeff				 "class/infiniband_ucma/abi_version",
187219820Sjeff				 value, sizeof value) < 0)) {
188219820Sjeff		/*
189219820Sjeff		 * Older version of Linux do not have class/misc.  To support
190219820Sjeff		 * backports, assume the most recent version of the ABI.  If
191219820Sjeff		 * we're wrong, we'll simply fail later when calling the ABI.
192219820Sjeff		 */
193219820Sjeff		fprintf(stderr, "librdmacm: couldn't read ABI version.\n");
194219820Sjeff		fprintf(stderr, "librdmacm: assuming: %d\n", abi_ver);
195219820Sjeff		return 0;
196219820Sjeff	}
197219820Sjeff
198219820Sjeff	abi_ver = strtol(value, NULL, 10);
199219820Sjeff	if (abi_ver < RDMA_USER_CM_MIN_ABI_VERSION ||
200219820Sjeff	    abi_ver > RDMA_USER_CM_MAX_ABI_VERSION) {
201219820Sjeff		fprintf(stderr, "librdmacm: kernel ABI version %d "
202219820Sjeff				"doesn't match library version %d.\n",
203219820Sjeff				abi_ver, RDMA_USER_CM_MAX_ABI_VERSION);
204219820Sjeff		return -1;
205219820Sjeff	}
206219820Sjeff	return 0;
207219820Sjeff}
208219820Sjeff
209219820Sjeffstatic int ucma_init(void)
210219820Sjeff{
211219820Sjeff	struct ibv_device **dev_list = NULL;
212219820Sjeff	struct cma_device *cma_dev;
213219820Sjeff	struct ibv_device_attr attr;
214219820Sjeff	int i, ret, dev_cnt;
215219820Sjeff
216219820Sjeff	pthread_mutex_lock(&mut);
217219820Sjeff	if (cma_dev_cnt) {
218219820Sjeff		pthread_mutex_unlock(&mut);
219219820Sjeff		return 0;
220219820Sjeff	}
221219820Sjeff
222219820Sjeff	ret = check_abi_version();
223219820Sjeff	if (ret)
224219820Sjeff		goto err1;
225219820Sjeff
226219820Sjeff	dev_list = ibv_get_device_list(&dev_cnt);
227219820Sjeff	if (!dev_list) {
228219820Sjeff		printf("CMA: unable to get RDMA device list\n");
229219820Sjeff		ret = ERR(ENODEV);
230219820Sjeff		goto err1;
231219820Sjeff	}
232219820Sjeff
233219820Sjeff	cma_dev_array = malloc(sizeof *cma_dev * dev_cnt);
234219820Sjeff	if (!cma_dev_array) {
235219820Sjeff		ret = ERR(ENOMEM);
236219820Sjeff		goto err2;
237219820Sjeff	}
238219820Sjeff
239219820Sjeff	for (i = 0; dev_list[i];) {
240219820Sjeff		cma_dev = &cma_dev_array[i];
241219820Sjeff
242219820Sjeff		cma_dev->guid = ibv_get_device_guid(dev_list[i]);
243219820Sjeff		cma_dev->verbs = ibv_open_device(dev_list[i]);
244219820Sjeff		if (!cma_dev->verbs) {
245219820Sjeff			printf("CMA: unable to open RDMA device\n");
246219820Sjeff			ret = ERR(ENODEV);
247219820Sjeff			goto err3;
248219820Sjeff		}
249219820Sjeff
250219820Sjeff		i++;
251219820Sjeff		ret = ibv_query_device(cma_dev->verbs, &attr);
252219820Sjeff		if (ret) {
253219820Sjeff			printf("CMA: unable to query RDMA device\n");
254219820Sjeff			goto err3;
255219820Sjeff		}
256219820Sjeff
257219820Sjeff		cma_dev->port_cnt = attr.phys_port_cnt;
258219820Sjeff		cma_dev->max_initiator_depth = (uint8_t) attr.max_qp_init_rd_atom;
259219820Sjeff		cma_dev->max_responder_resources = (uint8_t) attr.max_qp_rd_atom;
260219820Sjeff	}
261219820Sjeff
262219820Sjeff	cma_dev_cnt = dev_cnt;
263219820Sjeff	pthread_mutex_unlock(&mut);
264219820Sjeff	ibv_free_device_list(dev_list);
265219820Sjeff	return 0;
266219820Sjeff
267219820Sjefferr3:
268219820Sjeff	while (i--)
269219820Sjeff		ibv_close_device(cma_dev_array[i].verbs);
270219820Sjeff	free(cma_dev_array);
271219820Sjefferr2:
272219820Sjeff	ibv_free_device_list(dev_list);
273219820Sjefferr1:
274219820Sjeff	pthread_mutex_unlock(&mut);
275219820Sjeff	return ret;
276219820Sjeff}
277219820Sjeff
278219820Sjeffstruct ibv_context **rdma_get_devices(int *num_devices)
279219820Sjeff{
280219820Sjeff	struct ibv_context **devs = NULL;
281219820Sjeff	int i;
282219820Sjeff
283219820Sjeff	if (!cma_dev_cnt && ucma_init())
284219820Sjeff		goto out;
285219820Sjeff
286219820Sjeff	devs = malloc(sizeof *devs * (cma_dev_cnt + 1));
287219820Sjeff	if (!devs)
288219820Sjeff		goto out;
289219820Sjeff
290219820Sjeff	for (i = 0; i < cma_dev_cnt; i++)
291219820Sjeff		devs[i] = cma_dev_array[i].verbs;
292219820Sjeff	devs[i] = NULL;
293219820Sjeffout:
294219820Sjeff	if (num_devices)
295219820Sjeff		*num_devices = devs ? cma_dev_cnt : 0;
296219820Sjeff	return devs;
297219820Sjeff}
298219820Sjeff
299219820Sjeffvoid rdma_free_devices(struct ibv_context **list)
300219820Sjeff{
301219820Sjeff	free(list);
302219820Sjeff}
303219820Sjeff
304219820Sjeffstatic void __attribute__((destructor)) rdma_cma_fini(void)
305219820Sjeff{
306219820Sjeff	ucma_cleanup();
307219820Sjeff}
308219820Sjeff
309219820Sjeffstruct rdma_event_channel *rdma_create_event_channel(void)
310219820Sjeff{
311219820Sjeff	struct rdma_event_channel *channel;
312219820Sjeff
313219820Sjeff	if (!cma_dev_cnt && ucma_init())
314219820Sjeff		return NULL;
315219820Sjeff
316219820Sjeff	channel = malloc(sizeof *channel);
317219820Sjeff	if (!channel)
318219820Sjeff		return NULL;
319219820Sjeff
320219820Sjeff	channel->fd = open("/dev/rdma_cm", O_RDWR);
321219820Sjeff	if (channel->fd < 0) {
322219820Sjeff		printf("CMA: unable to open /dev/rdma_cm\n");
323219820Sjeff		goto err;
324219820Sjeff	}
325219820Sjeff	return channel;
326219820Sjefferr:
327219820Sjeff	free(channel);
328219820Sjeff	return NULL;
329219820Sjeff}
330219820Sjeff
331219820Sjeffvoid rdma_destroy_event_channel(struct rdma_event_channel *channel)
332219820Sjeff{
333219820Sjeff	close(channel->fd);
334219820Sjeff	free(channel);
335219820Sjeff}
336219820Sjeff
337219820Sjeffstatic int ucma_get_device(struct cma_id_private *id_priv, uint64_t guid)
338219820Sjeff{
339219820Sjeff	struct cma_device *cma_dev;
340219820Sjeff	int i;
341219820Sjeff
342219820Sjeff	for (i = 0; i < cma_dev_cnt; i++) {
343219820Sjeff		cma_dev = &cma_dev_array[i];
344219820Sjeff		if (cma_dev->guid == guid) {
345219820Sjeff			id_priv->cma_dev = cma_dev;
346219820Sjeff			id_priv->id.verbs = cma_dev->verbs;
347219820Sjeff			return 0;
348219820Sjeff		}
349219820Sjeff	}
350219820Sjeff
351219820Sjeff	return ERR(ENODEV);
352219820Sjeff}
353219820Sjeff
354219820Sjeffstatic void ucma_free_id(struct cma_id_private *id_priv)
355219820Sjeff{
356219820Sjeff	pthread_cond_destroy(&id_priv->cond);
357219820Sjeff	pthread_mutex_destroy(&id_priv->mut);
358219820Sjeff	if (id_priv->id.route.path_rec)
359219820Sjeff		free(id_priv->id.route.path_rec);
360219820Sjeff	free(id_priv);
361219820Sjeff}
362219820Sjeff
363219820Sjeffstatic struct cma_id_private *ucma_alloc_id(struct rdma_event_channel *channel,
364219820Sjeff					    void *context,
365219820Sjeff					    enum rdma_port_space ps)
366219820Sjeff{
367219820Sjeff	struct cma_id_private *id_priv;
368219820Sjeff
369219820Sjeff	id_priv = malloc(sizeof *id_priv);
370219820Sjeff	if (!id_priv)
371219820Sjeff		return NULL;
372219820Sjeff
373219820Sjeff	memset(id_priv, 0, sizeof *id_priv);
374219820Sjeff	id_priv->id.context = context;
375219820Sjeff	id_priv->id.ps = ps;
376219820Sjeff	id_priv->id.channel = channel;
377219820Sjeff	pthread_mutex_init(&id_priv->mut, NULL);
378219820Sjeff	if (pthread_cond_init(&id_priv->cond, NULL))
379219820Sjeff		goto err;
380219820Sjeff
381219820Sjeff	return id_priv;
382219820Sjeff
383219820Sjefferr:	ucma_free_id(id_priv);
384219820Sjeff	return NULL;
385219820Sjeff}
386219820Sjeff
387219820Sjeffint rdma_create_id(struct rdma_event_channel *channel,
388219820Sjeff		   struct rdma_cm_id **id, void *context,
389219820Sjeff		   enum rdma_port_space ps)
390219820Sjeff{
391219820Sjeff	struct ucma_abi_create_id_resp *resp;
392219820Sjeff	struct ucma_abi_create_id *cmd;
393219820Sjeff	struct cma_id_private *id_priv;
394219820Sjeff	void *msg;
395219820Sjeff	int ret, size;
396219820Sjeff
397219820Sjeff	ret = cma_dev_cnt ? 0 : ucma_init();
398219820Sjeff	if (ret)
399219820Sjeff		return ret;
400219820Sjeff
401219820Sjeff	id_priv = ucma_alloc_id(channel, context, ps);
402219820Sjeff	if (!id_priv)
403219820Sjeff		return ERR(ENOMEM);
404219820Sjeff
405219820Sjeff	CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_CREATE_ID, size);
406219820Sjeff	cmd->uid = (uintptr_t) id_priv;
407219820Sjeff	cmd->ps = ps;
408219820Sjeff
409219820Sjeff	ret = write(channel->fd, msg, size);
410219820Sjeff	if (ret != size)
411219820Sjeff		goto err;
412219820Sjeff
413219820Sjeff	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
414219820Sjeff
415219820Sjeff	id_priv->handle = resp->id;
416219820Sjeff	*id = &id_priv->id;
417219820Sjeff	return 0;
418219820Sjeff
419219820Sjefferr:	ucma_free_id(id_priv);
420219820Sjeff	return ret;
421219820Sjeff}
422219820Sjeff
423219820Sjeffstatic int ucma_destroy_kern_id(int fd, uint32_t handle)
424219820Sjeff{
425219820Sjeff	struct ucma_abi_destroy_id_resp *resp;
426219820Sjeff	struct ucma_abi_destroy_id *cmd;
427219820Sjeff	void *msg;
428219820Sjeff	int ret, size;
429219820Sjeff
430219820Sjeff	CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_DESTROY_ID, size);
431219820Sjeff	cmd->id = handle;
432219820Sjeff
433219820Sjeff	ret = write(fd, msg, size);
434219820Sjeff	if (ret != size)
435219820Sjeff		return (ret >= 0) ? ERR(ECONNREFUSED) : -1;
436219820Sjeff
437219820Sjeff	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
438219820Sjeff
439219820Sjeff	return resp->events_reported;
440219820Sjeff}
441219820Sjeff
442219820Sjeffint rdma_destroy_id(struct rdma_cm_id *id)
443219820Sjeff{
444219820Sjeff	struct cma_id_private *id_priv;
445219820Sjeff	int ret;
446219820Sjeff
447219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
448219820Sjeff	ret = ucma_destroy_kern_id(id->channel->fd, id_priv->handle);
449219820Sjeff	if (ret < 0)
450219820Sjeff		return ret;
451219820Sjeff
452219820Sjeff	pthread_mutex_lock(&id_priv->mut);
453219820Sjeff	while (id_priv->events_completed < ret)
454219820Sjeff		pthread_cond_wait(&id_priv->cond, &id_priv->mut);
455219820Sjeff	pthread_mutex_unlock(&id_priv->mut);
456219820Sjeff
457219820Sjeff	ucma_free_id(id_priv);
458219820Sjeff	return 0;
459219820Sjeff}
460219820Sjeff
461219820Sjeffstatic int ucma_addrlen(struct sockaddr *addr)
462219820Sjeff{
463219820Sjeff	if (!addr)
464219820Sjeff		return 0;
465219820Sjeff
466219820Sjeff	switch (addr->sa_family) {
467219820Sjeff	case PF_INET:
468219820Sjeff		return sizeof(struct sockaddr_in);
469219820Sjeff	case PF_INET6:
470219820Sjeff		return sizeof(struct sockaddr_in6);
471219820Sjeff	default:
472219820Sjeff		return 0;
473219820Sjeff	}
474219820Sjeff}
475219820Sjeff
476219820Sjeffstatic int ucma_query_route(struct rdma_cm_id *id)
477219820Sjeff{
478219820Sjeff	struct ucma_abi_query_route_resp *resp;
479219820Sjeff	struct ucma_abi_query_route *cmd;
480219820Sjeff	struct cma_id_private *id_priv;
481219820Sjeff	void *msg;
482219820Sjeff	int ret, size, i;
483219820Sjeff
484219820Sjeff	CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_QUERY_ROUTE, size);
485219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
486219820Sjeff	cmd->id = id_priv->handle;
487219820Sjeff
488219820Sjeff	ret = write(id->channel->fd, msg, size);
489219820Sjeff	if (ret != size)
490219820Sjeff		return (ret >= 0) ? ERR(ECONNREFUSED) : -1;
491219820Sjeff
492219820Sjeff	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
493219820Sjeff
494219820Sjeff	if (resp->num_paths) {
495219820Sjeff		id->route.path_rec = malloc(sizeof *id->route.path_rec *
496219820Sjeff					    resp->num_paths);
497219820Sjeff		if (!id->route.path_rec)
498219820Sjeff			return ERR(ENOMEM);
499219820Sjeff
500219820Sjeff		id->route.num_paths = resp->num_paths;
501219820Sjeff		for (i = 0; i < resp->num_paths; i++)
502219820Sjeff			ibv_copy_path_rec_from_kern(&id->route.path_rec[i],
503219820Sjeff						    &resp->ib_route[i]);
504219820Sjeff	}
505219820Sjeff
506219820Sjeff	memcpy(id->route.addr.addr.ibaddr.sgid.raw, resp->ib_route[0].sgid,
507219820Sjeff	       sizeof id->route.addr.addr.ibaddr.sgid);
508219820Sjeff	memcpy(id->route.addr.addr.ibaddr.dgid.raw, resp->ib_route[0].dgid,
509219820Sjeff	       sizeof id->route.addr.addr.ibaddr.dgid);
510219820Sjeff	id->route.addr.addr.ibaddr.pkey = resp->ib_route[0].pkey;
511219820Sjeff	memcpy(&id->route.addr.src_addr, &resp->src_addr,
512219820Sjeff	       sizeof resp->src_addr);
513219820Sjeff	memcpy(&id->route.addr.dst_addr, &resp->dst_addr,
514219820Sjeff	       sizeof resp->dst_addr);
515219820Sjeff
516219820Sjeff	if (!id_priv->cma_dev && resp->node_guid) {
517219820Sjeff		ret = ucma_get_device(id_priv, resp->node_guid);
518219820Sjeff		if (ret)
519219820Sjeff			return ret;
520219820Sjeff		id_priv->id.port_num = resp->port_num;
521219820Sjeff	}
522219820Sjeff
523219820Sjeff	return 0;
524219820Sjeff}
525219820Sjeff
526219820Sjeffint rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
527219820Sjeff{
528219820Sjeff	struct ucma_abi_bind_addr *cmd;
529219820Sjeff	struct cma_id_private *id_priv;
530219820Sjeff	void *msg;
531219820Sjeff	int ret, size, addrlen;
532219820Sjeff
533219820Sjeff	addrlen = ucma_addrlen(addr);
534219820Sjeff	if (!addrlen)
535219820Sjeff		return ERR(EINVAL);
536219820Sjeff
537219820Sjeff	CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_BIND_ADDR, size);
538219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
539219820Sjeff	cmd->id = id_priv->handle;
540219820Sjeff	memcpy(&cmd->addr, addr, addrlen);
541219820Sjeff
542219820Sjeff	ret = write(id->channel->fd, msg, size);
543219820Sjeff	if (ret != size)
544219820Sjeff		return (ret >= 0) ? ERR(ECONNREFUSED) : -1;
545219820Sjeff
546219820Sjeff	return ucma_query_route(id);
547219820Sjeff}
548219820Sjeff
549219820Sjeffint rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
550219820Sjeff		      struct sockaddr *dst_addr, int timeout_ms)
551219820Sjeff{
552219820Sjeff	struct ucma_abi_resolve_addr *cmd;
553219820Sjeff	struct cma_id_private *id_priv;
554219820Sjeff	void *msg;
555219820Sjeff	int ret, size, daddrlen;
556219820Sjeff
557219820Sjeff	daddrlen = ucma_addrlen(dst_addr);
558219820Sjeff	if (!daddrlen)
559219820Sjeff		return ERR(EINVAL);
560219820Sjeff
561219820Sjeff	CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_RESOLVE_ADDR, size);
562219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
563219820Sjeff	cmd->id = id_priv->handle;
564219820Sjeff	if (src_addr)
565219820Sjeff		memcpy(&cmd->src_addr, src_addr, ucma_addrlen(src_addr));
566219820Sjeff	memcpy(&cmd->dst_addr, dst_addr, daddrlen);
567219820Sjeff	cmd->timeout_ms = timeout_ms;
568219820Sjeff
569219820Sjeff	ret = write(id->channel->fd, msg, size);
570219820Sjeff	if (ret != size)
571219820Sjeff		return (ret >= 0) ? ERR(ECONNREFUSED) : -1;
572219820Sjeff
573219820Sjeff	memcpy(&id->route.addr.dst_addr, dst_addr, daddrlen);
574219820Sjeff	return 0;
575219820Sjeff}
576219820Sjeff
577219820Sjeffint rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
578219820Sjeff{
579219820Sjeff	struct ucma_abi_resolve_route *cmd;
580219820Sjeff	struct cma_id_private *id_priv;
581219820Sjeff	void *msg;
582219820Sjeff	int ret, size;
583219820Sjeff
584219820Sjeff	CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_RESOLVE_ROUTE, size);
585219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
586219820Sjeff	cmd->id = id_priv->handle;
587219820Sjeff	cmd->timeout_ms = timeout_ms;
588219820Sjeff
589219820Sjeff	ret = write(id->channel->fd, msg, size);
590219820Sjeff	if (ret != size)
591219820Sjeff		return (ret >= 0) ? ERR(ECONNREFUSED) : -1;
592219820Sjeff
593219820Sjeff	return 0;
594219820Sjeff}
595219820Sjeff
596219820Sjeffstatic int ucma_is_ud_ps(enum rdma_port_space ps)
597219820Sjeff{
598219820Sjeff	return (ps == RDMA_PS_UDP || ps == RDMA_PS_IPOIB);
599219820Sjeff}
600219820Sjeff
601219820Sjeffstatic int rdma_init_qp_attr(struct rdma_cm_id *id, struct ibv_qp_attr *qp_attr,
602219820Sjeff			     int *qp_attr_mask)
603219820Sjeff{
604219820Sjeff	struct ucma_abi_init_qp_attr *cmd;
605219820Sjeff	struct ibv_kern_qp_attr *resp;
606219820Sjeff	struct cma_id_private *id_priv;
607219820Sjeff	void *msg;
608219820Sjeff	int ret, size;
609219820Sjeff
610219820Sjeff	CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_INIT_QP_ATTR, size);
611219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
612219820Sjeff	cmd->id = id_priv->handle;
613219820Sjeff	cmd->qp_state = qp_attr->qp_state;
614219820Sjeff
615219820Sjeff	ret = write(id->channel->fd, msg, size);
616219820Sjeff	if (ret != size)
617219820Sjeff		return (ret >= 0) ? ERR(ECONNREFUSED) : -1;
618219820Sjeff
619219820Sjeff	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
620219820Sjeff
621219820Sjeff	ibv_copy_qp_attr_from_kern(qp_attr, resp);
622219820Sjeff	*qp_attr_mask = resp->qp_attr_mask;
623219820Sjeff	return 0;
624219820Sjeff}
625219820Sjeff
626219820Sjeffstatic int ucma_modify_qp_rtr(struct rdma_cm_id *id,
627219820Sjeff			      struct rdma_conn_param *conn_param)
628219820Sjeff{
629219820Sjeff	struct ibv_qp_attr qp_attr;
630219820Sjeff	int qp_attr_mask, ret;
631219820Sjeff
632219820Sjeff	if (!id->qp)
633219820Sjeff		return ERR(EINVAL);
634219820Sjeff
635219820Sjeff	/* Need to update QP attributes from default values. */
636219820Sjeff	qp_attr.qp_state = IBV_QPS_INIT;
637219820Sjeff	ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask);
638219820Sjeff	if (ret)
639219820Sjeff		return ret;
640219820Sjeff
641219820Sjeff	ret = ibv_modify_qp(id->qp, &qp_attr, qp_attr_mask);
642219820Sjeff	if (ret)
643219820Sjeff		return ret;
644219820Sjeff
645219820Sjeff	qp_attr.qp_state = IBV_QPS_RTR;
646219820Sjeff	ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask);
647219820Sjeff	if (ret)
648219820Sjeff		return ret;
649219820Sjeff
650219820Sjeff	if (conn_param)
651219820Sjeff		qp_attr.max_dest_rd_atomic = conn_param->responder_resources;
652219820Sjeff	return ibv_modify_qp(id->qp, &qp_attr, qp_attr_mask);
653219820Sjeff}
654219820Sjeff
655219820Sjeffstatic int ucma_modify_qp_rts(struct rdma_cm_id *id)
656219820Sjeff{
657219820Sjeff	struct ibv_qp_attr qp_attr;
658219820Sjeff	int qp_attr_mask, ret;
659219820Sjeff
660219820Sjeff	qp_attr.qp_state = IBV_QPS_RTS;
661219820Sjeff	ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask);
662219820Sjeff	if (ret)
663219820Sjeff		return ret;
664219820Sjeff
665219820Sjeff	return ibv_modify_qp(id->qp, &qp_attr, qp_attr_mask);
666219820Sjeff}
667219820Sjeff
668219820Sjeffstatic int ucma_modify_qp_sqd(struct rdma_cm_id *id)
669219820Sjeff{
670219820Sjeff	struct ibv_qp_attr qp_attr;
671219820Sjeff
672219820Sjeff	if (!id->qp)
673219820Sjeff		return 0;
674219820Sjeff
675219820Sjeff	qp_attr.qp_state = IBV_QPS_SQD;
676219820Sjeff	return ibv_modify_qp(id->qp, &qp_attr, IBV_QP_STATE);
677219820Sjeff}
678219820Sjeff
679219820Sjeffstatic int ucma_modify_qp_err(struct rdma_cm_id *id)
680219820Sjeff{
681219820Sjeff	struct ibv_qp_attr qp_attr;
682219820Sjeff
683219820Sjeff	if (!id->qp)
684219820Sjeff		return 0;
685219820Sjeff
686219820Sjeff	qp_attr.qp_state = IBV_QPS_ERR;
687219820Sjeff	return ibv_modify_qp(id->qp, &qp_attr, IBV_QP_STATE);
688219820Sjeff}
689219820Sjeff
690219820Sjeffstatic int ucma_find_pkey(struct cma_device *cma_dev, uint8_t port_num,
691219820Sjeff			  uint16_t pkey, uint16_t *pkey_index)
692219820Sjeff{
693219820Sjeff	int ret, i;
694219820Sjeff	uint16_t chk_pkey;
695219820Sjeff
696219820Sjeff	for (i = 0, ret = 0; !ret; i++) {
697219820Sjeff		ret = ibv_query_pkey(cma_dev->verbs, port_num, i, &chk_pkey);
698219820Sjeff		if (!ret && pkey == chk_pkey) {
699219820Sjeff			*pkey_index = (uint16_t) i;
700219820Sjeff			return 0;
701219820Sjeff		}
702219820Sjeff	}
703219820Sjeff	return ERR(EINVAL);
704219820Sjeff}
705219820Sjeff
706219820Sjeffstatic int ucma_init_conn_qp3(struct cma_id_private *id_priv, struct ibv_qp *qp)
707219820Sjeff{
708219820Sjeff	struct ibv_qp_attr qp_attr;
709219820Sjeff	int ret;
710219820Sjeff
711219820Sjeff	ret = ucma_find_pkey(id_priv->cma_dev, id_priv->id.port_num,
712219820Sjeff			     id_priv->id.route.addr.addr.ibaddr.pkey,
713219820Sjeff			     &qp_attr.pkey_index);
714219820Sjeff	if (ret)
715219820Sjeff		return ret;
716219820Sjeff
717219820Sjeff	qp_attr.port_num = id_priv->id.port_num;
718219820Sjeff	qp_attr.qp_state = IBV_QPS_INIT;
719219820Sjeff	qp_attr.qp_access_flags = 0;
720219820Sjeff
721219820Sjeff	return ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE | IBV_QP_ACCESS_FLAGS |
722219820Sjeff					   IBV_QP_PKEY_INDEX | IBV_QP_PORT);
723219820Sjeff}
724219820Sjeff
725219820Sjeffstatic int ucma_init_conn_qp(struct cma_id_private *id_priv, struct ibv_qp *qp)
726219820Sjeff{
727219820Sjeff	struct ibv_qp_attr qp_attr;
728219820Sjeff	int qp_attr_mask, ret;
729219820Sjeff
730219820Sjeff	if (abi_ver == 3)
731219820Sjeff		return ucma_init_conn_qp3(id_priv, qp);
732219820Sjeff
733219820Sjeff	qp_attr.qp_state = IBV_QPS_INIT;
734219820Sjeff	ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
735219820Sjeff	if (ret)
736219820Sjeff		return ret;
737219820Sjeff
738219820Sjeff	return ibv_modify_qp(qp, &qp_attr, qp_attr_mask);
739219820Sjeff}
740219820Sjeff
741219820Sjeffstatic int ucma_init_ud_qp3(struct cma_id_private *id_priv, struct ibv_qp *qp)
742219820Sjeff{
743219820Sjeff	struct ibv_qp_attr qp_attr;
744219820Sjeff	int ret;
745219820Sjeff
746219820Sjeff	ret = ucma_find_pkey(id_priv->cma_dev, id_priv->id.port_num,
747219820Sjeff			     id_priv->id.route.addr.addr.ibaddr.pkey,
748219820Sjeff			     &qp_attr.pkey_index);
749219820Sjeff	if (ret)
750219820Sjeff		return ret;
751219820Sjeff
752219820Sjeff	qp_attr.port_num = id_priv->id.port_num;
753219820Sjeff	qp_attr.qp_state = IBV_QPS_INIT;
754219820Sjeff	qp_attr.qkey = RDMA_UDP_QKEY;
755219820Sjeff
756219820Sjeff	ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE | IBV_QP_QKEY |
757219820Sjeff					  IBV_QP_PKEY_INDEX | IBV_QP_PORT);
758219820Sjeff	if (ret)
759219820Sjeff		return ret;
760219820Sjeff
761219820Sjeff	qp_attr.qp_state = IBV_QPS_RTR;
762219820Sjeff	ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE);
763219820Sjeff	if (ret)
764219820Sjeff		return ret;
765219820Sjeff
766219820Sjeff	qp_attr.qp_state = IBV_QPS_RTS;
767219820Sjeff	qp_attr.sq_psn = 0;
768219820Sjeff	return ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE | IBV_QP_SQ_PSN);
769219820Sjeff}
770219820Sjeff
771219820Sjeffstatic int ucma_init_ud_qp(struct cma_id_private *id_priv, struct ibv_qp *qp)
772219820Sjeff{
773219820Sjeff	struct ibv_qp_attr qp_attr;
774219820Sjeff	int qp_attr_mask, ret;
775219820Sjeff
776219820Sjeff	if (abi_ver == 3)
777219820Sjeff		return ucma_init_ud_qp3(id_priv, qp);
778219820Sjeff
779219820Sjeff	qp_attr.qp_state = IBV_QPS_INIT;
780219820Sjeff	ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
781219820Sjeff	if (ret)
782219820Sjeff		return ret;
783219820Sjeff
784219820Sjeff	ret = ibv_modify_qp(qp, &qp_attr, qp_attr_mask);
785219820Sjeff	if (ret)
786219820Sjeff		return ret;
787219820Sjeff
788219820Sjeff	qp_attr.qp_state = IBV_QPS_RTR;
789219820Sjeff	ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE);
790219820Sjeff	if (ret)
791219820Sjeff		return ret;
792219820Sjeff
793219820Sjeff	qp_attr.qp_state = IBV_QPS_RTS;
794219820Sjeff	qp_attr.sq_psn = 0;
795219820Sjeff	return ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE | IBV_QP_SQ_PSN);
796219820Sjeff}
797219820Sjeff
798219820Sjeffint rdma_create_qp(struct rdma_cm_id *id, struct ibv_pd *pd,
799219820Sjeff		   struct ibv_qp_init_attr *qp_init_attr)
800219820Sjeff{
801219820Sjeff	struct cma_id_private *id_priv;
802219820Sjeff	struct ibv_qp *qp;
803219820Sjeff	int ret;
804219820Sjeff
805219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
806219820Sjeff	if (id->verbs != pd->context)
807219820Sjeff		return ERR(EINVAL);
808219820Sjeff
809219820Sjeff	qp = ibv_create_qp(pd, qp_init_attr);
810219820Sjeff	if (!qp)
811219820Sjeff		return ERR(ENOMEM);
812219820Sjeff
813219820Sjeff	if (ucma_is_ud_ps(id->ps))
814219820Sjeff		ret = ucma_init_ud_qp(id_priv, qp);
815219820Sjeff	else
816219820Sjeff		ret = ucma_init_conn_qp(id_priv, qp);
817219820Sjeff	if (ret)
818219820Sjeff		goto err;
819219820Sjeff
820219820Sjeff	id->qp = qp;
821219820Sjeff	return 0;
822219820Sjefferr:
823219820Sjeff	ibv_destroy_qp(qp);
824219820Sjeff	return ret;
825219820Sjeff}
826219820Sjeff
827219820Sjeffvoid rdma_destroy_qp(struct rdma_cm_id *id)
828219820Sjeff{
829219820Sjeff	ibv_destroy_qp(id->qp);
830219820Sjeff}
831219820Sjeff
832219820Sjeffstatic int ucma_valid_param(struct cma_id_private *id_priv,
833219820Sjeff			    struct rdma_conn_param *conn_param)
834219820Sjeff{
835219820Sjeff	if (id_priv->id.ps != RDMA_PS_TCP)
836219820Sjeff		return 0;
837219820Sjeff
838219820Sjeff	if ((conn_param->responder_resources >
839219820Sjeff	     id_priv->cma_dev->max_responder_resources) ||
840219820Sjeff	    (conn_param->initiator_depth >
841219820Sjeff	     id_priv->cma_dev->max_initiator_depth))
842219820Sjeff		return ERR(EINVAL);
843219820Sjeff
844219820Sjeff	return 0;
845219820Sjeff}
846219820Sjeff
847219820Sjeffstatic void ucma_copy_conn_param_to_kern(struct ucma_abi_conn_param *dst,
848219820Sjeff					 struct rdma_conn_param *src,
849219820Sjeff					 uint32_t qp_num, uint8_t srq)
850219820Sjeff{
851219820Sjeff	dst->qp_num = qp_num;
852219820Sjeff	dst->srq = srq;
853219820Sjeff	dst->responder_resources = src->responder_resources;
854219820Sjeff	dst->initiator_depth = src->initiator_depth;
855219820Sjeff	dst->flow_control = src->flow_control;
856219820Sjeff	dst->retry_count = src->retry_count;
857219820Sjeff	dst->rnr_retry_count = src->rnr_retry_count;
858219820Sjeff	dst->valid = 1;
859219820Sjeff
860219820Sjeff	if (src->private_data && src->private_data_len) {
861219820Sjeff		memcpy(dst->private_data, src->private_data,
862219820Sjeff		       src->private_data_len);
863219820Sjeff		dst->private_data_len = src->private_data_len;
864219820Sjeff	}
865219820Sjeff}
866219820Sjeff
867219820Sjeffint rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
868219820Sjeff{
869219820Sjeff	struct ucma_abi_connect *cmd;
870219820Sjeff	struct cma_id_private *id_priv;
871219820Sjeff	void *msg;
872219820Sjeff	int ret, size;
873219820Sjeff
874219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
875219820Sjeff	ret = ucma_valid_param(id_priv, conn_param);
876219820Sjeff	if (ret)
877219820Sjeff		return ret;
878219820Sjeff
879219820Sjeff	CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_CONNECT, size);
880219820Sjeff	cmd->id = id_priv->handle;
881219820Sjeff	if (id->qp)
882219820Sjeff		ucma_copy_conn_param_to_kern(&cmd->conn_param, conn_param,
883219820Sjeff					     id->qp->qp_num,
884219820Sjeff					     (id->qp->srq != NULL));
885219820Sjeff	else
886219820Sjeff		ucma_copy_conn_param_to_kern(&cmd->conn_param, conn_param,
887219820Sjeff					     conn_param->qp_num,
888219820Sjeff					     conn_param->srq);
889219820Sjeff
890219820Sjeff	ret = write(id->channel->fd, msg, size);
891219820Sjeff	if (ret != size)
892219820Sjeff		return (ret >= 0) ? ERR(ECONNREFUSED) : -1;
893219820Sjeff
894219820Sjeff	return 0;
895219820Sjeff}
896219820Sjeff
897219820Sjeffint rdma_listen(struct rdma_cm_id *id, int backlog)
898219820Sjeff{
899219820Sjeff	struct ucma_abi_listen *cmd;
900219820Sjeff	struct cma_id_private *id_priv;
901219820Sjeff	void *msg;
902219820Sjeff	int ret, size;
903219820Sjeff
904219820Sjeff	CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_LISTEN, size);
905219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
906219820Sjeff	cmd->id = id_priv->handle;
907219820Sjeff	cmd->backlog = backlog;
908219820Sjeff
909219820Sjeff	ret = write(id->channel->fd, msg, size);
910219820Sjeff	if (ret != size)
911219820Sjeff		return (ret >= 0) ? ERR(ECONNREFUSED) : -1;
912219820Sjeff
913219820Sjeff	return ucma_query_route(id);
914219820Sjeff}
915219820Sjeff
916219820Sjeffint rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
917219820Sjeff{
918219820Sjeff	struct ucma_abi_accept *cmd;
919219820Sjeff	struct cma_id_private *id_priv;
920219820Sjeff	void *msg;
921219820Sjeff	int ret, size;
922219820Sjeff
923219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
924219820Sjeff	ret = ucma_valid_param(id_priv, conn_param);
925219820Sjeff	if (ret)
926219820Sjeff		return ret;
927219820Sjeff
928219820Sjeff	if (!ucma_is_ud_ps(id->ps)) {
929219820Sjeff		ret = ucma_modify_qp_rtr(id, conn_param);
930219820Sjeff		if (ret)
931219820Sjeff			return ret;
932219820Sjeff	}
933219820Sjeff
934219820Sjeff	CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_ACCEPT, size);
935219820Sjeff	cmd->id = id_priv->handle;
936219820Sjeff	cmd->uid = (uintptr_t) id_priv;
937219820Sjeff	if (id->qp)
938219820Sjeff		ucma_copy_conn_param_to_kern(&cmd->conn_param, conn_param,
939219820Sjeff					     id->qp->qp_num,
940219820Sjeff					     (id->qp->srq != NULL));
941219820Sjeff	else
942219820Sjeff		ucma_copy_conn_param_to_kern(&cmd->conn_param, conn_param,
943219820Sjeff					     conn_param->qp_num,
944219820Sjeff					     conn_param->srq);
945219820Sjeff
946219820Sjeff	ret = write(id->channel->fd, msg, size);
947219820Sjeff	if (ret != size) {
948219820Sjeff		ucma_modify_qp_err(id);
949219820Sjeff		return (ret >= 0) ? ERR(ECONNREFUSED) : -1;
950219820Sjeff	}
951219820Sjeff
952219820Sjeff	return 0;
953219820Sjeff}
954219820Sjeff
955219820Sjeffint rdma_reject(struct rdma_cm_id *id, const void *private_data,
956219820Sjeff		uint8_t private_data_len)
957219820Sjeff{
958219820Sjeff	struct ucma_abi_reject *cmd;
959219820Sjeff	struct cma_id_private *id_priv;
960219820Sjeff	void *msg;
961219820Sjeff	int ret, size;
962219820Sjeff
963219820Sjeff	CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_REJECT, size);
964219820Sjeff
965219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
966219820Sjeff	cmd->id = id_priv->handle;
967219820Sjeff	if (private_data && private_data_len) {
968219820Sjeff		memcpy(cmd->private_data, private_data, private_data_len);
969219820Sjeff		cmd->private_data_len = private_data_len;
970219820Sjeff	} else
971219820Sjeff		cmd->private_data_len = 0;
972219820Sjeff
973219820Sjeff	ret = write(id->channel->fd, msg, size);
974219820Sjeff	if (ret != size)
975219820Sjeff		return (ret >= 0) ? ERR(ECONNREFUSED) : -1;
976219820Sjeff
977219820Sjeff	return 0;
978219820Sjeff}
979219820Sjeff
980219820Sjeffint rdma_notify(struct rdma_cm_id *id, enum ibv_event_type event)
981219820Sjeff{
982219820Sjeff	struct ucma_abi_notify *cmd;
983219820Sjeff	struct cma_id_private *id_priv;
984219820Sjeff	void *msg;
985219820Sjeff	int ret, size;
986219820Sjeff
987219820Sjeff	CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_NOTIFY, size);
988219820Sjeff
989219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
990219820Sjeff	cmd->id = id_priv->handle;
991219820Sjeff	cmd->event = event;
992219820Sjeff	ret = write(id->channel->fd, msg, size);
993219820Sjeff	if (ret != size)
994219820Sjeff		return (ret >= 0) ? ERR(ECONNREFUSED) : -1;
995219820Sjeff
996219820Sjeff	return 0;
997219820Sjeff}
998219820Sjeff
999219820Sjeffint rdma_disconnect(struct rdma_cm_id *id)
1000219820Sjeff{
1001219820Sjeff	struct ucma_abi_disconnect *cmd;
1002219820Sjeff	struct cma_id_private *id_priv;
1003219820Sjeff	void *msg;
1004219820Sjeff	int ret, size;
1005219820Sjeff
1006219820Sjeff	switch (id->verbs->device->transport_type) {
1007219820Sjeff	case IBV_TRANSPORT_IB:
1008219820Sjeff		ret = ucma_modify_qp_err(id);
1009219820Sjeff		break;
1010219820Sjeff	case IBV_TRANSPORT_IWARP:
1011219820Sjeff		ret = ucma_modify_qp_sqd(id);
1012219820Sjeff		break;
1013219820Sjeff	default:
1014219820Sjeff		ret = ERR(EINVAL);
1015219820Sjeff	}
1016219820Sjeff	if (ret)
1017219820Sjeff		return ret;
1018219820Sjeff
1019219820Sjeff	CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_DISCONNECT, size);
1020219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
1021219820Sjeff	cmd->id = id_priv->handle;
1022219820Sjeff
1023219820Sjeff	ret = write(id->channel->fd, msg, size);
1024219820Sjeff	if (ret != size)
1025219820Sjeff		return (ret >= 0) ? ERR(ECONNREFUSED) : -1;
1026219820Sjeff
1027219820Sjeff	return 0;
1028219820Sjeff}
1029219820Sjeff
1030219820Sjeffint rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
1031219820Sjeff			void *context)
1032219820Sjeff{
1033219820Sjeff	struct ucma_abi_join_mcast *cmd;
1034219820Sjeff	struct ucma_abi_create_id_resp *resp;
1035219820Sjeff	struct cma_id_private *id_priv;
1036219820Sjeff	struct cma_multicast *mc, **pos;
1037219820Sjeff	void *msg;
1038219820Sjeff	int ret, size, addrlen;
1039219820Sjeff
1040219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
1041219820Sjeff	addrlen = ucma_addrlen(addr);
1042219820Sjeff	if (!addrlen)
1043219820Sjeff		return ERR(EINVAL);
1044219820Sjeff
1045219820Sjeff	mc = malloc(sizeof *mc);
1046219820Sjeff	if (!mc)
1047219820Sjeff		return ERR(ENOMEM);
1048219820Sjeff
1049219820Sjeff	memset(mc, 0, sizeof *mc);
1050219820Sjeff	mc->context = context;
1051219820Sjeff	mc->id_priv = id_priv;
1052219820Sjeff	memcpy(&mc->addr, addr, addrlen);
1053219820Sjeff	if (pthread_cond_init(&mc->cond, NULL)) {
1054219820Sjeff		ret = -1;
1055219820Sjeff		goto err1;
1056219820Sjeff	}
1057219820Sjeff
1058219820Sjeff	pthread_mutex_lock(&id_priv->mut);
1059219820Sjeff	mc->next = id_priv->mc_list;
1060219820Sjeff	id_priv->mc_list = mc;
1061219820Sjeff	pthread_mutex_unlock(&id_priv->mut);
1062219820Sjeff
1063219820Sjeff	CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_JOIN_MCAST, size);
1064219820Sjeff	cmd->id = id_priv->handle;
1065219820Sjeff	memcpy(&cmd->addr, addr, addrlen);
1066219820Sjeff	cmd->uid = (uintptr_t) mc;
1067219820Sjeff
1068219820Sjeff	ret = write(id->channel->fd, msg, size);
1069219820Sjeff	if (ret != size) {
1070219820Sjeff		ret = (ret >= 0) ? ERR(ECONNREFUSED) : -1;
1071219820Sjeff		goto err2;
1072219820Sjeff	}
1073219820Sjeff
1074219820Sjeff	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
1075219820Sjeff
1076219820Sjeff	mc->handle = resp->id;
1077219820Sjeff	return 0;
1078219820Sjefferr2:
1079219820Sjeff	pthread_mutex_lock(&id_priv->mut);
1080219820Sjeff	for (pos = &id_priv->mc_list; *pos != mc; pos = &(*pos)->next)
1081219820Sjeff		;
1082219820Sjeff	*pos = mc->next;
1083219820Sjeff	pthread_mutex_unlock(&id_priv->mut);
1084219820Sjefferr1:
1085219820Sjeff	free(mc);
1086219820Sjeff	return ret;
1087219820Sjeff}
1088219820Sjeff
1089219820Sjeffint rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)
1090219820Sjeff{
1091219820Sjeff	struct ucma_abi_destroy_id *cmd;
1092219820Sjeff	struct ucma_abi_destroy_id_resp *resp;
1093219820Sjeff	struct cma_id_private *id_priv;
1094219820Sjeff	struct cma_multicast *mc, **pos;
1095219820Sjeff	void *msg;
1096219820Sjeff	int ret, size, addrlen;
1097219820Sjeff
1098219820Sjeff	addrlen = ucma_addrlen(addr);
1099219820Sjeff	if (!addrlen)
1100219820Sjeff		return ERR(EINVAL);
1101219820Sjeff
1102219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
1103219820Sjeff	pthread_mutex_lock(&id_priv->mut);
1104219820Sjeff	for (pos = &id_priv->mc_list; *pos; pos = &(*pos)->next)
1105219820Sjeff		if (!memcmp(&(*pos)->addr, addr, addrlen))
1106219820Sjeff			break;
1107219820Sjeff
1108219820Sjeff	mc = *pos;
1109219820Sjeff	if (*pos)
1110219820Sjeff		*pos = mc->next;
1111219820Sjeff	pthread_mutex_unlock(&id_priv->mut);
1112219820Sjeff	if (!mc)
1113219820Sjeff		return ERR(EADDRNOTAVAIL);
1114219820Sjeff
1115219820Sjeff	if (id->qp)
1116219820Sjeff		ibv_detach_mcast(id->qp, &mc->mgid, mc->mlid);
1117219820Sjeff
1118219820Sjeff	CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_LEAVE_MCAST, size);
1119219820Sjeff	cmd->id = mc->handle;
1120219820Sjeff
1121219820Sjeff	ret = write(id->channel->fd, msg, size);
1122219820Sjeff	if (ret != size) {
1123219820Sjeff		ret = (ret >= 0) ? ERR(ECONNREFUSED) : -1;
1124219820Sjeff		goto free;
1125219820Sjeff	}
1126219820Sjeff
1127219820Sjeff	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
1128219820Sjeff
1129219820Sjeff	pthread_mutex_lock(&id_priv->mut);
1130219820Sjeff	while (mc->events_completed < resp->events_reported)
1131219820Sjeff		pthread_cond_wait(&mc->cond, &id_priv->mut);
1132219820Sjeff	pthread_mutex_unlock(&id_priv->mut);
1133219820Sjeff
1134219820Sjeff	ret = 0;
1135219820Sjefffree:
1136219820Sjeff	free(mc);
1137219820Sjeff	return ret;
1138219820Sjeff}
1139219820Sjeff
1140219820Sjeffstatic void ucma_complete_event(struct cma_id_private *id_priv)
1141219820Sjeff{
1142219820Sjeff	pthread_mutex_lock(&id_priv->mut);
1143219820Sjeff	id_priv->events_completed++;
1144219820Sjeff	pthread_cond_signal(&id_priv->cond);
1145219820Sjeff	pthread_mutex_unlock(&id_priv->mut);
1146219820Sjeff}
1147219820Sjeff
1148219820Sjeffstatic void ucma_complete_mc_event(struct cma_multicast *mc)
1149219820Sjeff{
1150219820Sjeff	pthread_mutex_lock(&mc->id_priv->mut);
1151219820Sjeff	mc->events_completed++;
1152219820Sjeff	pthread_cond_signal(&mc->cond);
1153219820Sjeff	mc->id_priv->events_completed++;
1154219820Sjeff	pthread_cond_signal(&mc->id_priv->cond);
1155219820Sjeff	pthread_mutex_unlock(&mc->id_priv->mut);
1156219820Sjeff}
1157219820Sjeff
1158219820Sjeffint rdma_ack_cm_event(struct rdma_cm_event *event)
1159219820Sjeff{
1160219820Sjeff	struct cma_event *evt;
1161219820Sjeff
1162219820Sjeff	if (!event)
1163219820Sjeff		return ERR(EINVAL);
1164219820Sjeff
1165219820Sjeff	evt = container_of(event, struct cma_event, event);
1166219820Sjeff
1167219820Sjeff	if (evt->mc)
1168219820Sjeff		ucma_complete_mc_event(evt->mc);
1169219820Sjeff	else
1170219820Sjeff		ucma_complete_event(evt->id_priv);
1171219820Sjeff	free(evt);
1172219820Sjeff	return 0;
1173219820Sjeff}
1174219820Sjeff
1175219820Sjeffstatic int ucma_process_conn_req(struct cma_event *evt,
1176219820Sjeff				 uint32_t handle)
1177219820Sjeff{
1178219820Sjeff	struct cma_id_private *id_priv;
1179219820Sjeff	int ret;
1180219820Sjeff
1181219820Sjeff	id_priv = ucma_alloc_id(evt->id_priv->id.channel,
1182219820Sjeff				evt->id_priv->id.context, evt->id_priv->id.ps);
1183219820Sjeff	if (!id_priv) {
1184219820Sjeff		ucma_destroy_kern_id(evt->id_priv->id.channel->fd, handle);
1185219820Sjeff		ret = ERR(ENOMEM);
1186219820Sjeff		goto err;
1187219820Sjeff	}
1188219820Sjeff
1189219820Sjeff	evt->event.listen_id = &evt->id_priv->id;
1190219820Sjeff	evt->event.id = &id_priv->id;
1191219820Sjeff	id_priv->handle = handle;
1192219820Sjeff
1193219820Sjeff	ret = ucma_query_route(&id_priv->id);
1194219820Sjeff	if (ret) {
1195219820Sjeff		rdma_destroy_id(&id_priv->id);
1196219820Sjeff		goto err;
1197219820Sjeff	}
1198219820Sjeff
1199219820Sjeff	return 0;
1200219820Sjefferr:
1201219820Sjeff	ucma_complete_event(evt->id_priv);
1202219820Sjeff	return ret;
1203219820Sjeff}
1204219820Sjeff
1205219820Sjeffstatic int ucma_process_conn_resp(struct cma_id_private *id_priv)
1206219820Sjeff{
1207219820Sjeff	struct ucma_abi_accept *cmd;
1208219820Sjeff	void *msg;
1209219820Sjeff	int ret, size;
1210219820Sjeff
1211219820Sjeff	ret = ucma_modify_qp_rtr(&id_priv->id, NULL);
1212219820Sjeff	if (ret)
1213219820Sjeff		goto err;
1214219820Sjeff
1215219820Sjeff	ret = ucma_modify_qp_rts(&id_priv->id);
1216219820Sjeff	if (ret)
1217219820Sjeff		goto err;
1218219820Sjeff
1219219820Sjeff	CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_ACCEPT, size);
1220219820Sjeff	cmd->id = id_priv->handle;
1221219820Sjeff
1222219820Sjeff	ret = write(id_priv->id.channel->fd, msg, size);
1223219820Sjeff	if (ret != size) {
1224219820Sjeff		ret = (ret >= 0) ? ERR(ECONNREFUSED) : -1;
1225219820Sjeff		goto err;
1226219820Sjeff	}
1227219820Sjeff
1228219820Sjeff	return 0;
1229219820Sjefferr:
1230219820Sjeff	ucma_modify_qp_err(&id_priv->id);
1231219820Sjeff	return ret;
1232219820Sjeff}
1233219820Sjeff
1234219820Sjeffstatic int ucma_process_establish(struct rdma_cm_id *id)
1235219820Sjeff{
1236219820Sjeff	int ret;
1237219820Sjeff
1238219820Sjeff	ret = ucma_modify_qp_rts(id);
1239219820Sjeff	if (ret)
1240219820Sjeff		ucma_modify_qp_err(id);
1241219820Sjeff
1242219820Sjeff	return ret;
1243219820Sjeff}
1244219820Sjeff
1245219820Sjeffstatic int ucma_process_join(struct cma_event *evt)
1246219820Sjeff{
1247219820Sjeff	evt->mc->mgid = evt->event.param.ud.ah_attr.grh.dgid;
1248219820Sjeff	evt->mc->mlid = evt->event.param.ud.ah_attr.dlid;
1249219820Sjeff
1250219820Sjeff	if (!evt->id_priv->id.qp)
1251219820Sjeff		return 0;
1252219820Sjeff
1253219820Sjeff	return ibv_attach_mcast(evt->id_priv->id.qp, &evt->mc->mgid,
1254219820Sjeff				evt->mc->mlid);
1255219820Sjeff}
1256219820Sjeff
1257219820Sjeffstatic void ucma_copy_conn_event(struct cma_event *event,
1258219820Sjeff				 struct ucma_abi_conn_param *src)
1259219820Sjeff{
1260219820Sjeff	struct rdma_conn_param *dst = &event->event.param.conn;
1261219820Sjeff
1262219820Sjeff	dst->private_data_len = src->private_data_len;
1263219820Sjeff	if (src->private_data_len) {
1264219820Sjeff		dst->private_data = &event->private_data;
1265219820Sjeff		memcpy(&event->private_data, src->private_data,
1266219820Sjeff		       src->private_data_len);
1267219820Sjeff	}
1268219820Sjeff
1269219820Sjeff	dst->responder_resources = src->responder_resources;
1270219820Sjeff	dst->initiator_depth = src->initiator_depth;
1271219820Sjeff	dst->flow_control = src->flow_control;
1272219820Sjeff	dst->retry_count = src->retry_count;
1273219820Sjeff	dst->rnr_retry_count = src->rnr_retry_count;
1274219820Sjeff	dst->srq = src->srq;
1275219820Sjeff	dst->qp_num = src->qp_num;
1276219820Sjeff}
1277219820Sjeff
1278219820Sjeffstatic void ucma_copy_ud_event(struct cma_event *event,
1279219820Sjeff			       struct ucma_abi_ud_param *src)
1280219820Sjeff{
1281219820Sjeff	struct rdma_ud_param *dst = &event->event.param.ud;
1282219820Sjeff
1283219820Sjeff	dst->private_data_len = src->private_data_len;
1284219820Sjeff	if (src->private_data_len) {
1285219820Sjeff		dst->private_data = &event->private_data;
1286219820Sjeff		memcpy(&event->private_data, src->private_data,
1287219820Sjeff		       src->private_data_len);
1288219820Sjeff	}
1289219820Sjeff
1290219820Sjeff	ibv_copy_ah_attr_from_kern(&dst->ah_attr, &src->ah_attr);
1291219820Sjeff	dst->qp_num = src->qp_num;
1292219820Sjeff	dst->qkey = src->qkey;
1293219820Sjeff}
1294219820Sjeff
1295219820Sjeffint rdma_get_cm_event(struct rdma_event_channel *channel,
1296219820Sjeff		      struct rdma_cm_event **event)
1297219820Sjeff{
1298219820Sjeff	struct ucma_abi_event_resp *resp;
1299219820Sjeff	struct ucma_abi_get_event *cmd;
1300219820Sjeff	struct cma_event *evt;
1301219820Sjeff	void *msg;
1302219820Sjeff	int ret, size;
1303219820Sjeff
1304219820Sjeff	ret = cma_dev_cnt ? 0 : ucma_init();
1305219820Sjeff	if (ret)
1306219820Sjeff		return ret;
1307219820Sjeff
1308219820Sjeff	if (!event)
1309219820Sjeff		return ERR(EINVAL);
1310219820Sjeff
1311219820Sjeff	evt = malloc(sizeof *evt);
1312219820Sjeff	if (!evt)
1313219820Sjeff		return ERR(ENOMEM);
1314219820Sjeff
1315219820Sjeffretry:
1316219820Sjeff	memset(evt, 0, sizeof *evt);
1317219820Sjeff	CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_GET_EVENT, size);
1318219820Sjeff	ret = write(channel->fd, msg, size);
1319219820Sjeff	if (ret != size) {
1320219820Sjeff		free(evt);
1321219820Sjeff		return (ret >= 0) ? ERR(ECONNREFUSED) : -1;
1322219820Sjeff	}
1323219820Sjeff
1324219820Sjeff	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
1325219820Sjeff
1326219820Sjeff	evt->event.event = resp->event;
1327219820Sjeff	evt->id_priv = (void *) (uintptr_t) resp->uid;
1328219820Sjeff	evt->event.id = &evt->id_priv->id;
1329219820Sjeff	evt->event.status = resp->status;
1330219820Sjeff
1331219820Sjeff	switch (resp->event) {
1332219820Sjeff	case RDMA_CM_EVENT_ADDR_RESOLVED:
1333219820Sjeff		evt->event.status = ucma_query_route(&evt->id_priv->id);
1334219820Sjeff		if (evt->event.status)
1335219820Sjeff			evt->event.event = RDMA_CM_EVENT_ADDR_ERROR;
1336219820Sjeff		break;
1337219820Sjeff	case RDMA_CM_EVENT_ROUTE_RESOLVED:
1338219820Sjeff		evt->event.status = ucma_query_route(&evt->id_priv->id);
1339219820Sjeff		if (evt->event.status)
1340219820Sjeff			evt->event.event = RDMA_CM_EVENT_ROUTE_ERROR;
1341219820Sjeff		break;
1342219820Sjeff	case RDMA_CM_EVENT_CONNECT_REQUEST:
1343219820Sjeff		evt->id_priv = (void *) (uintptr_t) resp->uid;
1344219820Sjeff		if (ucma_is_ud_ps(evt->id_priv->id.ps))
1345219820Sjeff			ucma_copy_ud_event(evt, &resp->param.ud);
1346219820Sjeff		else
1347219820Sjeff			ucma_copy_conn_event(evt, &resp->param.conn);
1348219820Sjeff
1349219820Sjeff		ret = ucma_process_conn_req(evt, resp->id);
1350219820Sjeff		if (ret)
1351219820Sjeff			goto retry;
1352219820Sjeff		break;
1353219820Sjeff	case RDMA_CM_EVENT_CONNECT_RESPONSE:
1354219820Sjeff		ucma_copy_conn_event(evt, &resp->param.conn);
1355219820Sjeff		evt->event.status = ucma_process_conn_resp(evt->id_priv);
1356219820Sjeff		if (!evt->event.status)
1357219820Sjeff			evt->event.event = RDMA_CM_EVENT_ESTABLISHED;
1358219820Sjeff		else {
1359219820Sjeff			evt->event.event = RDMA_CM_EVENT_CONNECT_ERROR;
1360219820Sjeff			evt->id_priv->connect_error = 1;
1361219820Sjeff		}
1362219820Sjeff		break;
1363219820Sjeff	case RDMA_CM_EVENT_ESTABLISHED:
1364219820Sjeff		if (ucma_is_ud_ps(evt->id_priv->id.ps)) {
1365219820Sjeff			ucma_copy_ud_event(evt, &resp->param.ud);
1366219820Sjeff			break;
1367219820Sjeff		}
1368219820Sjeff
1369219820Sjeff		ucma_copy_conn_event(evt, &resp->param.conn);
1370219820Sjeff		evt->event.status = ucma_process_establish(&evt->id_priv->id);
1371219820Sjeff		if (evt->event.status) {
1372219820Sjeff			evt->event.event = RDMA_CM_EVENT_CONNECT_ERROR;
1373219820Sjeff			evt->id_priv->connect_error = 1;
1374219820Sjeff		}
1375219820Sjeff		break;
1376219820Sjeff	case RDMA_CM_EVENT_REJECTED:
1377219820Sjeff		if (evt->id_priv->connect_error) {
1378219820Sjeff			ucma_complete_event(evt->id_priv);
1379219820Sjeff			goto retry;
1380219820Sjeff		}
1381219820Sjeff		ucma_copy_conn_event(evt, &resp->param.conn);
1382219820Sjeff		ucma_modify_qp_err(evt->event.id);
1383219820Sjeff		break;
1384219820Sjeff	case RDMA_CM_EVENT_DISCONNECTED:
1385219820Sjeff		if (evt->id_priv->connect_error) {
1386219820Sjeff			ucma_complete_event(evt->id_priv);
1387219820Sjeff			goto retry;
1388219820Sjeff		}
1389219820Sjeff		ucma_copy_conn_event(evt, &resp->param.conn);
1390219820Sjeff		break;
1391219820Sjeff	case RDMA_CM_EVENT_MULTICAST_JOIN:
1392219820Sjeff		evt->mc = (void *) (uintptr_t) resp->uid;
1393219820Sjeff		evt->id_priv = evt->mc->id_priv;
1394219820Sjeff		evt->event.id = &evt->id_priv->id;
1395219820Sjeff		ucma_copy_ud_event(evt, &resp->param.ud);
1396219820Sjeff		evt->event.param.ud.private_data = evt->mc->context;
1397219820Sjeff		evt->event.status = ucma_process_join(evt);
1398219820Sjeff		if (evt->event.status)
1399219820Sjeff			evt->event.event = RDMA_CM_EVENT_MULTICAST_ERROR;
1400219820Sjeff		break;
1401219820Sjeff	case RDMA_CM_EVENT_MULTICAST_ERROR:
1402219820Sjeff		evt->mc = (void *) (uintptr_t) resp->uid;
1403219820Sjeff		evt->id_priv = evt->mc->id_priv;
1404219820Sjeff		evt->event.id = &evt->id_priv->id;
1405219820Sjeff		evt->event.param.ud.private_data = evt->mc->context;
1406219820Sjeff		break;
1407219820Sjeff	default:
1408219820Sjeff		evt->id_priv = (void *) (uintptr_t) resp->uid;
1409219820Sjeff		evt->event.id = &evt->id_priv->id;
1410219820Sjeff		evt->event.status = resp->status;
1411219820Sjeff		if (ucma_is_ud_ps(evt->id_priv->id.ps))
1412219820Sjeff			ucma_copy_ud_event(evt, &resp->param.ud);
1413219820Sjeff		else
1414219820Sjeff			ucma_copy_conn_event(evt, &resp->param.conn);
1415219820Sjeff		break;
1416219820Sjeff	}
1417219820Sjeff
1418219820Sjeff	*event = &evt->event;
1419219820Sjeff	return 0;
1420219820Sjeff}
1421219820Sjeff
1422219820Sjeffconst char *rdma_event_str(enum rdma_cm_event_type event)
1423219820Sjeff{
1424219820Sjeff	switch (event) {
1425219820Sjeff	case RDMA_CM_EVENT_ADDR_RESOLVED:
1426219820Sjeff		return "RDMA_CM_EVENT_ADDR_RESOLVED";
1427219820Sjeff	case RDMA_CM_EVENT_ADDR_ERROR:
1428219820Sjeff		return "RDMA_CM_EVENT_ADDR_ERROR";
1429219820Sjeff	case RDMA_CM_EVENT_ROUTE_RESOLVED:
1430219820Sjeff		return "RDMA_CM_EVENT_ROUTE_RESOLVED";
1431219820Sjeff	case RDMA_CM_EVENT_ROUTE_ERROR:
1432219820Sjeff		return "RDMA_CM_EVENT_ROUTE_ERROR";
1433219820Sjeff	case RDMA_CM_EVENT_CONNECT_REQUEST:
1434219820Sjeff		return "RDMA_CM_EVENT_CONNECT_REQUEST";
1435219820Sjeff	case RDMA_CM_EVENT_CONNECT_RESPONSE:
1436219820Sjeff		return "RDMA_CM_EVENT_CONNECT_RESPONSE";
1437219820Sjeff	case RDMA_CM_EVENT_CONNECT_ERROR:
1438219820Sjeff		return "RDMA_CM_EVENT_CONNECT_ERROR";
1439219820Sjeff	case RDMA_CM_EVENT_UNREACHABLE:
1440219820Sjeff		return "RDMA_CM_EVENT_UNREACHABLE";
1441219820Sjeff	case RDMA_CM_EVENT_REJECTED:
1442219820Sjeff		return "RDMA_CM_EVENT_REJECTED";
1443219820Sjeff	case RDMA_CM_EVENT_ESTABLISHED:
1444219820Sjeff		return "RDMA_CM_EVENT_ESTABLISHED";
1445219820Sjeff	case RDMA_CM_EVENT_DISCONNECTED:
1446219820Sjeff		return "RDMA_CM_EVENT_DISCONNECTED";
1447219820Sjeff	case RDMA_CM_EVENT_DEVICE_REMOVAL:
1448219820Sjeff		return "RDMA_CM_EVENT_DEVICE_REMOVAL";
1449219820Sjeff	case RDMA_CM_EVENT_MULTICAST_JOIN:
1450219820Sjeff		return "RDMA_CM_EVENT_MULTICAST_JOIN";
1451219820Sjeff	case RDMA_CM_EVENT_MULTICAST_ERROR:
1452219820Sjeff		return "RDMA_CM_EVENT_MULTICAST_ERROR";
1453219820Sjeff	case RDMA_CM_EVENT_ADDR_CHANGE:
1454219820Sjeff		return "RDMA_CM_EVENT_ADDR_CHANGE";
1455219820Sjeff	case RDMA_CM_EVENT_TIMEWAIT_EXIT:
1456219820Sjeff		return "RDMA_CM_EVENT_TIMEWAIT_EXIT";
1457219820Sjeff	default:
1458219820Sjeff		return "UNKNOWN EVENT";
1459219820Sjeff	}
1460219820Sjeff}
1461219820Sjeff
1462219820Sjeffint rdma_set_option(struct rdma_cm_id *id, int level, int optname,
1463219820Sjeff		    void *optval, size_t optlen)
1464219820Sjeff{
1465219820Sjeff	struct ucma_abi_set_option *cmd;
1466219820Sjeff	struct cma_id_private *id_priv;
1467219820Sjeff	void *msg;
1468219820Sjeff	int ret, size;
1469219820Sjeff
1470219820Sjeff	CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_SET_OPTION, size);
1471219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
1472219820Sjeff	cmd->id = id_priv->handle;
1473219820Sjeff	cmd->optval = (uintptr_t) optval;
1474219820Sjeff	cmd->level = level;
1475219820Sjeff	cmd->optname = optname;
1476219820Sjeff	cmd->optlen = optlen;
1477219820Sjeff
1478219820Sjeff	ret = write(id->channel->fd, msg, size);
1479219820Sjeff	if (ret != size)
1480219820Sjeff		return (ret >= 0) ? ERR(ECONNREFUSED) : -1;
1481219820Sjeff
1482219820Sjeff	return 0;
1483219820Sjeff}
1484219820Sjeff
1485219820Sjeffint rdma_migrate_id(struct rdma_cm_id *id, struct rdma_event_channel *channel)
1486219820Sjeff{
1487219820Sjeff	struct ucma_abi_migrate_resp *resp;
1488219820Sjeff	struct ucma_abi_migrate_id *cmd;
1489219820Sjeff	struct cma_id_private *id_priv;
1490219820Sjeff	void *msg;
1491219820Sjeff	int ret, size;
1492219820Sjeff
1493219820Sjeff	id_priv = container_of(id, struct cma_id_private, id);
1494219820Sjeff	CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_MIGRATE_ID, size);
1495219820Sjeff	cmd->id = id_priv->handle;
1496219820Sjeff	cmd->fd = id->channel->fd;
1497219820Sjeff
1498219820Sjeff	ret = write(channel->fd, msg, size);
1499219820Sjeff	if (ret != size)
1500219820Sjeff		return (ret >= 0) ? ERR(ECONNREFUSED) : -1;
1501219820Sjeff
1502219820Sjeff	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
1503219820Sjeff
1504219820Sjeff	/*
1505219820Sjeff	 * Eventually if we want to support migrating channels while events are
1506219820Sjeff	 * being processed on the current channel, we need to block here while
1507219820Sjeff	 * there are any outstanding events on the current channel for this id
1508219820Sjeff	 * to prevent the user from processing events for this id on the old
1509219820Sjeff	 * channel after this call returns.
1510219820Sjeff	 */
1511219820Sjeff	pthread_mutex_lock(&id_priv->mut);
1512219820Sjeff	id->channel = channel;
1513219820Sjeff	while (id_priv->events_completed < resp->events_reported)
1514219820Sjeff		pthread_cond_wait(&id_priv->cond, &id_priv->mut);
1515219820Sjeff	pthread_mutex_unlock(&id_priv->mut);
1516219820Sjeff
1517219820Sjeff	return 0;
1518219820Sjeff}
1519