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