cm.c revision 331769
1/*
2 * Copyright (c) 2005 Topspin Communications.  All rights reserved.
3 * Copyright (c) 2005-2006 Intel Corporation.  All rights reserved.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses.  You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * OpenIB.org BSD license below:
10 *
11 *     Redistribution and use in source and binary forms, with or
12 *     without modification, are permitted provided that the following
13 *     conditions are met:
14 *
15 *      - Redistributions of source code must retain the above
16 *        copyright notice, this list of conditions and the following
17 *        disclaimer.
18 *
19 *      - Redistributions in binary form must reproduce the above
20 *        copyright notice, this list of conditions and the following
21 *        disclaimer in the documentation and/or other materials
22 *        provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 *
33 * $Id$
34 */
35#define _GNU_SOURCE
36#include <config.h>
37
38#include <stdlib.h>
39#include <string.h>
40#include <stdio.h>
41#include <fcntl.h>
42#include <errno.h>
43#include <unistd.h>
44#include <pthread.h>
45#include <stddef.h>
46
47#include <infiniband/cm.h>
48#include <rdma/ib_user_cm.h>
49#include <infiniband/driver.h>
50#include <infiniband/marshall.h>
51
52#define PFX "libibcm: "
53
54#define IB_USER_CM_MIN_ABI_VERSION     4
55#define IB_USER_CM_MAX_ABI_VERSION     5
56
57static int abi_ver;
58static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
59
60enum {
61	IB_UCM_MAX_DEVICES = 32
62};
63
64static inline int ERR(int err)
65{
66	errno = err;
67	return -1;
68}
69
70
71#define CM_CREATE_MSG_CMD_RESP(msg, cmd, resp, type, size) \
72do {                                        \
73	struct ib_ucm_cmd_hdr *hdr;         \
74                                            \
75	size = sizeof(*hdr) + sizeof(*cmd); \
76	msg = alloca(size);                 \
77	if (!msg)                           \
78		return ERR(ENOMEM);         \
79	hdr = msg;                          \
80	cmd = msg + sizeof(*hdr);           \
81	hdr->cmd = type;                    \
82	hdr->in  = sizeof(*cmd);            \
83	hdr->out = sizeof(*resp);           \
84	memset(cmd, 0, sizeof(*cmd));       \
85	resp = alloca(sizeof(*resp));       \
86	if (!resp)                          \
87		return ERR(ENOMEM);         \
88	cmd->response = (uintptr_t)resp;\
89} while (0)
90
91#define CM_CREATE_MSG_CMD(msg, cmd, type, size) \
92do {                                        \
93	struct ib_ucm_cmd_hdr *hdr;         \
94                                            \
95	size = sizeof(*hdr) + sizeof(*cmd); \
96	msg = alloca(size);                 \
97	if (!msg)                           \
98		return ERR(ENOMEM);         \
99	hdr = msg;                          \
100	cmd = msg + sizeof(*hdr);           \
101	hdr->cmd = type;                    \
102	hdr->in  = sizeof(*cmd);            \
103	hdr->out = 0;                       \
104	memset(cmd, 0, sizeof(*cmd));       \
105} while (0)
106
107struct cm_id_private {
108	struct ib_cm_id id;
109	int events_completed;
110	pthread_cond_t cond;
111	pthread_mutex_t mut;
112};
113
114static int check_abi_version(void)
115{
116	char value[8];
117
118	if (ibv_read_sysfs_file(ibv_get_sysfs_path(),
119				"class/infiniband_cm/abi_version",
120				value, sizeof value) < 0) {
121		fprintf(stderr, PFX "couldn't read ABI version\n");
122		return 0;
123	}
124
125	abi_ver = strtol(value, NULL, 10);
126	if (abi_ver < IB_USER_CM_MIN_ABI_VERSION ||
127	    abi_ver > IB_USER_CM_MAX_ABI_VERSION) {
128		fprintf(stderr, PFX "kernel ABI version %d "
129				"doesn't match library version %d.\n",
130				abi_ver, IB_USER_CM_MAX_ABI_VERSION);
131		return -1;
132	}
133	return 0;
134}
135
136static int ucm_init(void)
137{
138	int ret = 0;
139
140	pthread_mutex_lock(&mut);
141	if (!abi_ver)
142		ret = check_abi_version();
143	pthread_mutex_unlock(&mut);
144
145	return ret;
146}
147
148static int ucm_get_dev_index(char *dev_name)
149{
150	char *dev_path;
151	char ibdev[IBV_SYSFS_NAME_MAX];
152	int i, ret;
153
154	for (i = 0; i < IB_UCM_MAX_DEVICES; i++) {
155		ret = asprintf(&dev_path, "/sys/class/infiniband_cm/ucm%d", i);
156		if (ret < 0)
157			return -1;
158
159		ret = ibv_read_sysfs_file(dev_path, "ibdev", ibdev, sizeof ibdev);
160		if (ret < 0)
161			continue;
162
163		if (!strcmp(dev_name, ibdev)) {
164			free(dev_path);
165			return i;
166		}
167
168		free(dev_path);
169	}
170	return -1;
171}
172
173struct ib_cm_device* ib_cm_open_device(struct ibv_context *device_context)
174{
175	struct ib_cm_device *dev;
176	char *dev_path;
177	int index, ret;
178
179	if (ucm_init())
180		return NULL;
181
182	index = ucm_get_dev_index(device_context->device->name);
183	if (index < 0)
184		return NULL;
185
186	dev = malloc(sizeof *dev);
187	if (!dev)
188		return NULL;
189
190	dev->device_context = device_context;
191
192	ret = asprintf(&dev_path, "/dev/ucm%d", index);
193	if (ret < 0)
194		goto err1;
195
196	dev->fd = open(dev_path, O_RDWR);
197	if (dev->fd < 0)
198		goto err2;
199
200	free(dev_path);
201	return dev;
202
203err2:
204	free(dev_path);
205err1:
206	free(dev);
207	return NULL;
208}
209
210void ib_cm_close_device(struct ib_cm_device *device)
211{
212	close(device->fd);
213	free(device);
214}
215
216static void ib_cm_free_id(struct cm_id_private *cm_id_priv)
217{
218	pthread_cond_destroy(&cm_id_priv->cond);
219	pthread_mutex_destroy(&cm_id_priv->mut);
220	free(cm_id_priv);
221}
222
223static struct cm_id_private *ib_cm_alloc_id(struct ib_cm_device *device,
224					    void *context)
225{
226	struct cm_id_private *cm_id_priv;
227
228	cm_id_priv = malloc(sizeof *cm_id_priv);
229	if (!cm_id_priv)
230		return NULL;
231
232	memset(cm_id_priv, 0, sizeof *cm_id_priv);
233	cm_id_priv->id.device = device;
234	cm_id_priv->id.context = context;
235	pthread_mutex_init(&cm_id_priv->mut, NULL);
236	if (pthread_cond_init(&cm_id_priv->cond, NULL))
237		goto err;
238
239	return cm_id_priv;
240
241err:	ib_cm_free_id(cm_id_priv);
242	return NULL;
243}
244
245int ib_cm_create_id(struct ib_cm_device *device,
246		    struct ib_cm_id **cm_id, void *context)
247{
248	struct ib_ucm_create_id_resp *resp;
249	struct ib_ucm_create_id *cmd;
250	struct cm_id_private *cm_id_priv;
251	void *msg;
252	int result;
253	int size;
254
255	cm_id_priv = ib_cm_alloc_id(device, context);
256	if (!cm_id_priv)
257		return ERR(ENOMEM);
258
259	CM_CREATE_MSG_CMD_RESP(msg, cmd, resp, IB_USER_CM_CMD_CREATE_ID, size);
260	cmd->uid = (uintptr_t) cm_id_priv;
261
262	result = write(device->fd, msg, size);
263	if (result != size)
264		goto err;
265
266	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
267
268	cm_id_priv->id.handle = resp->id;
269	*cm_id = &cm_id_priv->id;
270	return 0;
271
272err:	ib_cm_free_id(cm_id_priv);
273	return result;
274}
275
276int ib_cm_destroy_id(struct ib_cm_id *cm_id)
277{
278	struct ib_ucm_destroy_id_resp *resp;
279	struct ib_ucm_destroy_id *cmd;
280	struct cm_id_private *cm_id_priv;
281	void *msg;
282	int result;
283	int size;
284
285	CM_CREATE_MSG_CMD_RESP(msg, cmd, resp, IB_USER_CM_CMD_DESTROY_ID, size);
286	cmd->id = cm_id->handle;
287
288	result = write(cm_id->device->fd, msg, size);
289	if (result != size)
290		return (result >= 0) ? ERR(ENODATA) : -1;
291
292	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
293
294	cm_id_priv = container_of(cm_id, struct cm_id_private, id);
295
296	pthread_mutex_lock(&cm_id_priv->mut);
297	while (cm_id_priv->events_completed < resp->events_reported)
298		pthread_cond_wait(&cm_id_priv->cond, &cm_id_priv->mut);
299	pthread_mutex_unlock(&cm_id_priv->mut);
300
301	ib_cm_free_id(cm_id_priv);
302	return 0;
303}
304
305int ib_cm_attr_id(struct ib_cm_id *cm_id, struct ib_cm_attr_param *param)
306{
307	struct ib_ucm_attr_id_resp *resp;
308	struct ib_ucm_attr_id *cmd;
309	void *msg;
310	int result;
311	int size;
312
313	if (!param)
314		return ERR(EINVAL);
315
316	CM_CREATE_MSG_CMD_RESP(msg, cmd, resp, IB_USER_CM_CMD_ATTR_ID, size);
317	cmd->id = cm_id->handle;
318
319	result = write(cm_id->device->fd, msg, size);
320	if (result != size)
321		return (result >= 0) ? ERR(ENODATA) : -1;
322
323	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
324
325	param->service_id   = resp->service_id;
326	param->service_mask = resp->service_mask;
327	param->local_id     = resp->local_id;
328	param->remote_id    = resp->remote_id;
329	return 0;
330}
331
332int ib_cm_init_qp_attr(struct ib_cm_id *cm_id,
333		       struct ibv_qp_attr *qp_attr,
334		       int *qp_attr_mask)
335{
336	struct ibv_kern_qp_attr *resp;
337	struct ib_ucm_init_qp_attr *cmd;
338	void *msg;
339	int result;
340	int size;
341
342	if (!qp_attr || !qp_attr_mask)
343		return ERR(EINVAL);
344
345	CM_CREATE_MSG_CMD_RESP(msg, cmd, resp, IB_USER_CM_CMD_INIT_QP_ATTR, size);
346	cmd->id = cm_id->handle;
347	cmd->qp_state = qp_attr->qp_state;
348
349	result = write(cm_id->device->fd, msg, size);
350	if (result != size)
351		return (result >= 0) ? ERR(ENODATA) : result;
352
353	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
354
355	*qp_attr_mask = resp->qp_attr_mask;
356	ibv_copy_qp_attr_from_kern(qp_attr, resp);
357
358	return 0;
359}
360
361int ib_cm_listen(struct ib_cm_id *cm_id,
362		 __be64 service_id,
363		 __be64 service_mask)
364{
365	struct ib_ucm_listen *cmd;
366	void *msg;
367	int result;
368	int size;
369
370	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_LISTEN, size);
371	cmd->id           = cm_id->handle;
372	cmd->service_id   = service_id;
373	cmd->service_mask = service_mask;
374
375	result = write(cm_id->device->fd, msg, size);
376	if (result != size)
377		return (result >= 0) ? ERR(ENODATA) : -1;
378
379	return 0;
380}
381
382int ib_cm_send_req(struct ib_cm_id *cm_id, struct ib_cm_req_param *param)
383{
384	struct ib_user_path_rec p_path;
385	struct ib_user_path_rec *a_path;
386	struct ib_ucm_req *cmd;
387	void *msg;
388	int result;
389	int size;
390
391	if (!param || !param->primary_path)
392		return ERR(EINVAL);
393
394	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_REQ, size);
395	cmd->id				= cm_id->handle;
396	cmd->qpn			= param->qp_num;
397	cmd->qp_type			= param->qp_type;
398	cmd->psn			= param->starting_psn;
399        cmd->sid			= param->service_id;
400        cmd->peer_to_peer               = param->peer_to_peer;
401        cmd->responder_resources        = param->responder_resources;
402        cmd->initiator_depth            = param->initiator_depth;
403        cmd->remote_cm_response_timeout = param->remote_cm_response_timeout;
404        cmd->flow_control               = param->flow_control;
405        cmd->local_cm_response_timeout  = param->local_cm_response_timeout;
406        cmd->retry_count                = param->retry_count;
407        cmd->rnr_retry_count            = param->rnr_retry_count;
408        cmd->max_cm_retries             = param->max_cm_retries;
409        cmd->srq                        = param->srq;
410
411	ibv_copy_path_rec_to_kern(&p_path, param->primary_path);
412	cmd->primary_path = (uintptr_t) &p_path;
413
414	if (param->alternate_path) {
415		a_path = alloca(sizeof(*a_path));
416		if (!a_path)
417			return ERR(ENOMEM);
418
419		ibv_copy_path_rec_to_kern(a_path, param->alternate_path);
420		cmd->alternate_path = (uintptr_t) a_path;
421	}
422
423	if (param->private_data && param->private_data_len) {
424		cmd->data = (uintptr_t) param->private_data;
425		cmd->len  = param->private_data_len;
426	}
427
428	result = write(cm_id->device->fd, msg, size);
429	if (result != size)
430		return (result >= 0) ? ERR(ENODATA) : -1;
431
432	return 0;
433}
434
435int ib_cm_send_rep(struct ib_cm_id *cm_id, struct ib_cm_rep_param *param)
436{
437	struct ib_ucm_rep *cmd;
438	void *msg;
439	int result;
440	int size;
441
442	if (!param)
443		return ERR(EINVAL);
444
445	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_REP, size);
446	cmd->uid = (uintptr_t) container_of(cm_id, struct cm_id_private, id);
447	cmd->id			 = cm_id->handle;
448	cmd->qpn		 = param->qp_num;
449	cmd->psn		 = param->starting_psn;
450        cmd->responder_resources = param->responder_resources;
451        cmd->initiator_depth     = param->initiator_depth;
452	cmd->target_ack_delay    = param->target_ack_delay;
453	cmd->failover_accepted   = param->failover_accepted;
454        cmd->flow_control        = param->flow_control;
455        cmd->rnr_retry_count     = param->rnr_retry_count;
456        cmd->srq                 = param->srq;
457
458	if (param->private_data && param->private_data_len) {
459		cmd->data = (uintptr_t) param->private_data;
460		cmd->len  = param->private_data_len;
461	}
462
463	result = write(cm_id->device->fd, msg, size);
464	if (result != size)
465		return (result >= 0) ? ERR(ENODATA) : -1;
466
467	return 0;
468}
469
470static inline int cm_send_private_data(struct ib_cm_id *cm_id,
471				       uint32_t type,
472				       void *private_data,
473				       uint8_t private_data_len)
474{
475	struct ib_ucm_private_data *cmd;
476	void *msg;
477	int result;
478	int size;
479
480	CM_CREATE_MSG_CMD(msg, cmd, type, size);
481	cmd->id = cm_id->handle;
482
483	if (private_data && private_data_len) {
484		cmd->data = (uintptr_t) private_data;
485		cmd->len  = private_data_len;
486	}
487
488	result = write(cm_id->device->fd, msg, size);
489	if (result != size)
490		return (result >= 0) ? ERR(ENODATA) : -1;
491
492	return 0;
493}
494
495int ib_cm_send_rtu(struct ib_cm_id *cm_id,
496		   void *private_data,
497		   uint8_t private_data_len)
498{
499	return cm_send_private_data(cm_id, IB_USER_CM_CMD_SEND_RTU,
500				    private_data, private_data_len);
501}
502
503int ib_cm_send_dreq(struct ib_cm_id *cm_id,
504		    void *private_data,
505		    uint8_t private_data_len)
506{
507	return cm_send_private_data(cm_id, IB_USER_CM_CMD_SEND_DREQ,
508				    private_data, private_data_len);
509}
510
511int ib_cm_send_drep(struct ib_cm_id *cm_id,
512		    void *private_data,
513		    uint8_t private_data_len)
514{
515	return cm_send_private_data(cm_id, IB_USER_CM_CMD_SEND_DREP,
516				    private_data, private_data_len);
517}
518
519static int cm_establish(struct ib_cm_id *cm_id)
520{
521	/* In kernel ABI 4 ESTABLISH was repurposed as NOTIFY and gained an
522	   extra field. For some reason the compat definitions were deleted
523	   from the uapi headers :( */
524#define IB_USER_CM_CMD_ESTABLISH IB_USER_CM_CMD_NOTIFY
525	struct cm_abi_establish { /* ABI 4 support */
526		__u32 id;
527	};
528
529	struct cm_abi_establish *cmd;
530	void *msg;
531	int result;
532	int size;
533
534	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_ESTABLISH, size);
535	cmd->id = cm_id->handle;
536
537	result = write(cm_id->device->fd, msg, size);
538	if (result != size)
539		return (result >= 0) ? ERR(ENODATA) : -1;
540
541	return 0;
542}
543
544int ib_cm_notify(struct ib_cm_id *cm_id, enum ibv_event_type event)
545{
546	struct ib_ucm_notify *cmd;
547	void *msg;
548	int result;
549	int size;
550
551	if (abi_ver == 4) {
552		if (event == IBV_EVENT_COMM_EST)
553			return cm_establish(cm_id);
554		else
555			return ERR(EINVAL);
556	}
557
558	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_NOTIFY, size);
559	cmd->id = cm_id->handle;
560	cmd->event = event;
561
562	result = write(cm_id->device->fd, msg, size);
563	if (result != size)
564		return (result >= 0) ? ERR(ENODATA) : -1;
565
566	return 0;
567}
568
569static inline int cm_send_status(struct ib_cm_id *cm_id,
570				 uint32_t type,
571				 int status,
572				 void *info,
573				 uint8_t info_length,
574				 void *private_data,
575				 uint8_t private_data_len)
576{
577	struct ib_ucm_info *cmd;
578	void *msg;
579	int result;
580	int size;
581
582	CM_CREATE_MSG_CMD(msg, cmd, type, size);
583	cmd->id     = cm_id->handle;
584	cmd->status = status;
585
586	if (private_data && private_data_len) {
587		cmd->data     = (uintptr_t) private_data;
588		cmd->data_len = private_data_len;
589	}
590
591	if (info && info_length) {
592		cmd->info     = (uintptr_t) info;
593		cmd->info_len = info_length;
594	}
595
596	result = write(cm_id->device->fd, msg, size);
597	if (result != size)
598		return (result >= 0) ? ERR(ENODATA) : -1;
599
600	return 0;
601}
602
603int ib_cm_send_rej(struct ib_cm_id *cm_id,
604		   enum ib_cm_rej_reason reason,
605		   void *ari,
606		   uint8_t ari_length,
607		   void *private_data,
608		   uint8_t private_data_len)
609{
610	return cm_send_status(cm_id, IB_USER_CM_CMD_SEND_REJ, reason,
611			      ari, ari_length,
612			      private_data, private_data_len);
613}
614
615int ib_cm_send_apr(struct ib_cm_id *cm_id,
616		   enum ib_cm_apr_status status,
617		   void *info,
618		   uint8_t info_length,
619		   void *private_data,
620		   uint8_t private_data_len)
621{
622	return cm_send_status(cm_id, IB_USER_CM_CMD_SEND_APR, status,
623			      info, info_length,
624			      private_data, private_data_len);
625}
626
627int ib_cm_send_mra(struct ib_cm_id *cm_id,
628		   uint8_t service_timeout,
629		   void *private_data,
630		   uint8_t private_data_len)
631{
632	struct ib_ucm_mra *cmd;
633	void *msg;
634	int result;
635	int size;
636
637	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_MRA, size);
638	cmd->id      = cm_id->handle;
639	cmd->timeout = service_timeout;
640
641	if (private_data && private_data_len) {
642		cmd->data = (uintptr_t) private_data;
643		cmd->len  = private_data_len;
644	}
645
646	result = write(cm_id->device->fd, msg, size);
647	if (result != size)
648		return (result >= 0) ? ERR(ENODATA) : result;
649
650	return 0;
651}
652
653int ib_cm_send_lap(struct ib_cm_id *cm_id,
654		   struct ibv_sa_path_rec *alternate_path,
655		   void *private_data,
656		   uint8_t private_data_len)
657{
658	struct ib_user_path_rec abi_path;
659	struct ib_ucm_lap *cmd;
660	void *msg;
661	int result;
662	int size;
663
664	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_LAP, size);
665	cmd->id = cm_id->handle;
666
667	ibv_copy_path_rec_to_kern(&abi_path, alternate_path);
668	cmd->path = (uintptr_t) &abi_path;
669
670	if (private_data && private_data_len) {
671		cmd->data = (uintptr_t) private_data;
672		cmd->len  = private_data_len;
673	}
674
675	result = write(cm_id->device->fd, msg, size);
676	if (result != size)
677		return (result >= 0) ? ERR(ENODATA) : -1;
678
679	return 0;
680}
681
682int ib_cm_send_sidr_req(struct ib_cm_id *cm_id,
683			struct ib_cm_sidr_req_param *param)
684{
685	struct ib_user_path_rec abi_path;
686	struct ib_ucm_sidr_req *cmd;
687	void *msg;
688	int result;
689	int size;
690
691	if (!param || !param->path)
692		return ERR(EINVAL);
693
694	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_SIDR_REQ, size);
695	cmd->id             = cm_id->handle;
696	cmd->sid            = param->service_id;
697	cmd->timeout        = param->timeout_ms;
698	cmd->max_cm_retries = param->max_cm_retries;
699
700	ibv_copy_path_rec_to_kern(&abi_path, param->path);
701	cmd->path = (uintptr_t) &abi_path;
702
703	if (param->private_data && param->private_data_len) {
704		cmd->data = (uintptr_t) param->private_data;
705		cmd->len  = param->private_data_len;
706	}
707
708	result = write(cm_id->device->fd, msg, size);
709	if (result != size)
710		return (result >= 0) ? ERR(ENODATA) : result;
711
712	return 0;
713}
714
715int ib_cm_send_sidr_rep(struct ib_cm_id *cm_id,
716			struct ib_cm_sidr_rep_param *param)
717{
718	struct ib_ucm_sidr_rep *cmd;
719	void *msg;
720	int result;
721	int size;
722
723	if (!param)
724		return ERR(EINVAL);
725
726	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_SIDR_REP, size);
727	cmd->id     = cm_id->handle;
728	cmd->qpn    = param->qp_num;
729	cmd->qkey   = param->qkey;
730	cmd->status = param->status;
731
732	if (param->private_data && param->private_data_len) {
733		cmd->data     = (uintptr_t) param->private_data;
734		cmd->data_len = param->private_data_len;
735	}
736
737	if (param->info && param->info_length) {
738		cmd->info     = (uintptr_t) param->info;
739		cmd->info_len = param->info_length;
740	}
741
742	result = write(cm_id->device->fd, msg, size);
743	if (result != size)
744		return (result >= 0) ? ERR(ENODATA) : -1;
745
746	return 0;
747}
748
749static void cm_event_req_get(struct ib_cm_req_event_param *ureq,
750			     struct ib_ucm_req_event_resp *kreq)
751{
752	ureq->remote_ca_guid             = kreq->remote_ca_guid;
753	ureq->remote_qkey                = kreq->remote_qkey;
754	ureq->remote_qpn                 = kreq->remote_qpn;
755	ureq->qp_type                    = kreq->qp_type;
756	ureq->starting_psn               = kreq->starting_psn;
757	ureq->responder_resources        = kreq->responder_resources;
758	ureq->initiator_depth            = kreq->initiator_depth;
759	ureq->local_cm_response_timeout  = kreq->local_cm_response_timeout;
760	ureq->flow_control               = kreq->flow_control;
761	ureq->remote_cm_response_timeout = kreq->remote_cm_response_timeout;
762	ureq->retry_count                = kreq->retry_count;
763	ureq->rnr_retry_count            = kreq->rnr_retry_count;
764	ureq->srq                        = kreq->srq;
765	ureq->port			 = kreq->port;
766
767	ibv_copy_path_rec_from_kern(ureq->primary_path, &kreq->primary_path);
768	if (ureq->alternate_path)
769		ibv_copy_path_rec_from_kern(ureq->alternate_path,
770					    &kreq->alternate_path);
771}
772
773static void cm_event_rep_get(struct ib_cm_rep_event_param *urep,
774			     struct ib_ucm_rep_event_resp *krep)
775{
776	urep->remote_ca_guid      = krep->remote_ca_guid;
777	urep->remote_qkey         = krep->remote_qkey;
778	urep->remote_qpn          = krep->remote_qpn;
779	urep->starting_psn        = krep->starting_psn;
780	urep->responder_resources = krep->responder_resources;
781	urep->initiator_depth     = krep->initiator_depth;
782	urep->target_ack_delay    = krep->target_ack_delay;
783	urep->failover_accepted   = krep->failover_accepted;
784	urep->flow_control        = krep->flow_control;
785	urep->rnr_retry_count     = krep->rnr_retry_count;
786	urep->srq                 = krep->srq;
787}
788
789static void cm_event_sidr_rep_get(struct ib_cm_sidr_rep_event_param *urep,
790				  struct ib_ucm_sidr_rep_event_resp *krep)
791{
792	urep->status = krep->status;
793	urep->qkey   = krep->qkey;
794	urep->qpn    = krep->qpn;
795};
796
797int ib_cm_get_event(struct ib_cm_device *device, struct ib_cm_event **event)
798{
799	struct cm_id_private *cm_id_priv;
800	struct ib_ucm_cmd_hdr *hdr;
801	struct ib_ucm_event_get *cmd;
802	struct ib_ucm_event_resp *resp;
803	struct ib_cm_event *evt = NULL;
804	struct ibv_sa_path_rec *path_a = NULL;
805	struct ibv_sa_path_rec *path_b = NULL;
806	void *data = NULL;
807	void *info = NULL;
808	void *msg;
809	int result = 0;
810	int size;
811
812	if (!event)
813		return ERR(EINVAL);
814
815	size = sizeof(*hdr) + sizeof(*cmd);
816	msg = alloca(size);
817	if (!msg)
818		return ERR(ENOMEM);
819
820	hdr = msg;
821	cmd = msg + sizeof(*hdr);
822
823	hdr->cmd = IB_USER_CM_CMD_EVENT;
824	hdr->in  = sizeof(*cmd);
825	hdr->out = sizeof(*resp);
826
827	memset(cmd, 0, sizeof(*cmd));
828
829	resp = alloca(sizeof(*resp));
830	if (!resp)
831		return ERR(ENOMEM);
832
833	cmd->response = (uintptr_t) resp;
834	cmd->data_len = (uint8_t)(~0U);
835	cmd->info_len = (uint8_t)(~0U);
836
837	data = malloc(cmd->data_len);
838	if (!data) {
839		result = ERR(ENOMEM);
840		goto done;
841	}
842
843	info = malloc(cmd->info_len);
844	if (!info) {
845		result = ERR(ENOMEM);
846		goto done;
847	}
848
849	cmd->data = (uintptr_t) data;
850	cmd->info = (uintptr_t) info;
851
852	result = write(device->fd, msg, size);
853	if (result != size) {
854		result = (result >= 0) ? ERR(ENODATA) : -1;
855		goto done;
856	}
857
858	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
859
860	/*
861	 * decode event.
862	 */
863	evt = malloc(sizeof(*evt));
864	if (!evt) {
865		result = ERR(ENOMEM);
866		goto done;
867	}
868	memset(evt, 0, sizeof(*evt));
869	evt->cm_id = (void *) (uintptr_t) resp->uid;
870	evt->event = resp->event;
871
872	if (resp->present & IB_UCM_PRES_PRIMARY) {
873		path_a = malloc(sizeof(*path_a));
874		if (!path_a) {
875			result = ERR(ENOMEM);
876			goto done;
877		}
878	}
879
880	if (resp->present & IB_UCM_PRES_ALTERNATE) {
881		path_b = malloc(sizeof(*path_b));
882		if (!path_b) {
883			result = ERR(ENOMEM);
884			goto done;
885		}
886	}
887
888	switch (evt->event) {
889	case IB_CM_REQ_RECEIVED:
890		evt->param.req_rcvd.listen_id = evt->cm_id;
891		cm_id_priv = ib_cm_alloc_id(evt->cm_id->device,
892					    evt->cm_id->context);
893		if (!cm_id_priv) {
894			result = ERR(ENOMEM);
895			goto done;
896		}
897		cm_id_priv->id.handle = resp->id;
898		evt->cm_id = &cm_id_priv->id;
899		evt->param.req_rcvd.primary_path   = path_a;
900		evt->param.req_rcvd.alternate_path = path_b;
901		path_a = NULL;
902		path_b = NULL;
903		cm_event_req_get(&evt->param.req_rcvd, &resp->u.req_resp);
904		break;
905	case IB_CM_REP_RECEIVED:
906		cm_event_rep_get(&evt->param.rep_rcvd, &resp->u.rep_resp);
907		break;
908	case IB_CM_MRA_RECEIVED:
909		evt->param.mra_rcvd.service_timeout = resp->u.mra_resp.timeout;
910		break;
911	case IB_CM_REJ_RECEIVED:
912		evt->param.rej_rcvd.reason = resp->u.rej_resp.reason;
913		evt->param.rej_rcvd.ari = info;
914		info = NULL;
915		break;
916	case IB_CM_LAP_RECEIVED:
917		evt->param.lap_rcvd.alternate_path = path_b;
918		path_b = NULL;
919		ibv_copy_path_rec_from_kern(evt->param.lap_rcvd.alternate_path,
920					    &resp->u.lap_resp.path);
921		break;
922	case IB_CM_APR_RECEIVED:
923		evt->param.apr_rcvd.ap_status = resp->u.apr_resp.status;
924		evt->param.apr_rcvd.apr_info = info;
925		info = NULL;
926		break;
927	case IB_CM_SIDR_REQ_RECEIVED:
928		evt->param.sidr_req_rcvd.listen_id = evt->cm_id;
929		cm_id_priv = ib_cm_alloc_id(evt->cm_id->device,
930					    evt->cm_id->context);
931		if (!cm_id_priv) {
932			result = ERR(ENOMEM);
933			goto done;
934		}
935		cm_id_priv->id.handle = resp->id;
936		evt->cm_id = &cm_id_priv->id;
937		evt->param.sidr_req_rcvd.pkey = resp->u.sidr_req_resp.pkey;
938		evt->param.sidr_req_rcvd.port = resp->u.sidr_req_resp.port;
939		break;
940	case IB_CM_SIDR_REP_RECEIVED:
941		cm_event_sidr_rep_get(&evt->param.sidr_rep_rcvd,
942				      &resp->u.sidr_rep_resp);
943		evt->param.sidr_rep_rcvd.info = info;
944		info = NULL;
945		break;
946	default:
947		evt->param.send_status = resp->u.send_status;
948		break;
949	}
950
951	if (resp->present & IB_UCM_PRES_DATA) {
952		evt->private_data = data;
953		data = NULL;
954	}
955
956	*event = evt;
957	evt    = NULL;
958	result = 0;
959done:
960	if (data)
961		free(data);
962	if (info)
963		free(info);
964	if (path_a)
965		free(path_a);
966	if (path_b)
967		free(path_b);
968	if (evt)
969		free(evt);
970
971	return result;
972}
973
974int ib_cm_ack_event(struct ib_cm_event *event)
975{
976	struct cm_id_private *cm_id_priv;
977
978	if (!event)
979		return ERR(EINVAL);
980
981	if (event->private_data)
982		free(event->private_data);
983
984	cm_id_priv = container_of(event->cm_id, struct cm_id_private, id);
985
986	switch (event->event) {
987	case IB_CM_REQ_RECEIVED:
988		cm_id_priv = container_of(event->param.req_rcvd.listen_id,
989					  struct cm_id_private, id);
990		free(event->param.req_rcvd.primary_path);
991		if (event->param.req_rcvd.alternate_path)
992			free(event->param.req_rcvd.alternate_path);
993		break;
994	case IB_CM_REJ_RECEIVED:
995		if (event->param.rej_rcvd.ari)
996			free(event->param.rej_rcvd.ari);
997		break;
998	case IB_CM_LAP_RECEIVED:
999		free(event->param.lap_rcvd.alternate_path);
1000		break;
1001	case IB_CM_APR_RECEIVED:
1002		if (event->param.apr_rcvd.apr_info)
1003			free(event->param.apr_rcvd.apr_info);
1004		break;
1005	case IB_CM_SIDR_REQ_RECEIVED:
1006		cm_id_priv = container_of(event->param.sidr_req_rcvd.listen_id,
1007					  struct cm_id_private, id);
1008		break;
1009	case IB_CM_SIDR_REP_RECEIVED:
1010		if (event->param.sidr_rep_rcvd.info)
1011			free(event->param.sidr_rep_rcvd.info);
1012	default:
1013		break;
1014	}
1015
1016	pthread_mutex_lock(&cm_id_priv->mut);
1017	cm_id_priv->events_completed++;
1018	pthread_cond_signal(&cm_id_priv->cond);
1019	pthread_mutex_unlock(&cm_id_priv->mut);
1020
1021	free(event);
1022	return 0;
1023}
1024