xref: /freebsd/contrib/ofed/libibcm/cm.c (revision e6bfd18d21b225af6a0ed67ceeaf1293b7b9eba5)
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 
57 static int abi_ver;
58 static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
59 
60 enum {
61 	IB_UCM_MAX_DEVICES = 32
62 };
63 
64 static 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) \
72 do {                                        \
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) \
92 do {                                        \
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 
107 struct 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 
114 static 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 
136 static 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 
148 static 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 
173 struct 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 
203 err2:
204 	free(dev_path);
205 err1:
206 	free(dev);
207 	return NULL;
208 }
209 
210 void ib_cm_close_device(struct ib_cm_device *device)
211 {
212 	close(device->fd);
213 	free(device);
214 }
215 
216 static 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 
223 static 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 
241 err:	ib_cm_free_id(cm_id_priv);
242 	return NULL;
243 }
244 
245 int 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 
272 err:	ib_cm_free_id(cm_id_priv);
273 	return result;
274 }
275 
276 int 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 
305 int 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 
332 int 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 
361 int 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 
382 int 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 
435 int 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 
470 static 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 
495 int 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 
503 int 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 
511 int 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 
519 static 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 
544 int 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 
569 static 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 
603 int 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 
615 int 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 
627 int 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 
653 int 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 
682 int 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 
715 int 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 
749 static 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 
773 static 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 
789 static 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 
797 int 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;
959 done:
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 
974 int 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