xref: /freebsd/contrib/ofed/libibcm/cm.c (revision 4b9d6057)
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 	if (pthread_mutex_init(&cm_id_priv->mut, NULL))
236 		goto err;
237 	if (pthread_cond_init(&cm_id_priv->cond, NULL))
238 		goto err;
239 
240 	return cm_id_priv;
241 
242 err:	ib_cm_free_id(cm_id_priv);
243 	return NULL;
244 }
245 
246 int ib_cm_create_id(struct ib_cm_device *device,
247 		    struct ib_cm_id **cm_id, void *context)
248 {
249 	struct ib_ucm_create_id_resp *resp;
250 	struct ib_ucm_create_id *cmd;
251 	struct cm_id_private *cm_id_priv;
252 	void *msg;
253 	int result;
254 	int size;
255 
256 	cm_id_priv = ib_cm_alloc_id(device, context);
257 	if (!cm_id_priv)
258 		return ERR(ENOMEM);
259 
260 	CM_CREATE_MSG_CMD_RESP(msg, cmd, resp, IB_USER_CM_CMD_CREATE_ID, size);
261 	cmd->uid = (uintptr_t) cm_id_priv;
262 
263 	result = write(device->fd, msg, size);
264 	if (result != size)
265 		goto err;
266 
267 	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
268 
269 	cm_id_priv->id.handle = resp->id;
270 	*cm_id = &cm_id_priv->id;
271 	return 0;
272 
273 err:	ib_cm_free_id(cm_id_priv);
274 	return result;
275 }
276 
277 int ib_cm_destroy_id(struct ib_cm_id *cm_id)
278 {
279 	struct ib_ucm_destroy_id_resp *resp;
280 	struct ib_ucm_destroy_id *cmd;
281 	struct cm_id_private *cm_id_priv;
282 	void *msg;
283 	int result;
284 	int size;
285 
286 	CM_CREATE_MSG_CMD_RESP(msg, cmd, resp, IB_USER_CM_CMD_DESTROY_ID, size);
287 	cmd->id = cm_id->handle;
288 
289 	result = write(cm_id->device->fd, msg, size);
290 	if (result != size)
291 		return (result >= 0) ? ERR(ENODATA) : -1;
292 
293 	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
294 
295 	cm_id_priv = container_of(cm_id, struct cm_id_private, id);
296 
297 	pthread_mutex_lock(&cm_id_priv->mut);
298 	while (cm_id_priv->events_completed < resp->events_reported)
299 		pthread_cond_wait(&cm_id_priv->cond, &cm_id_priv->mut);
300 	pthread_mutex_unlock(&cm_id_priv->mut);
301 
302 	ib_cm_free_id(cm_id_priv);
303 	return 0;
304 }
305 
306 int ib_cm_attr_id(struct ib_cm_id *cm_id, struct ib_cm_attr_param *param)
307 {
308 	struct ib_ucm_attr_id_resp *resp;
309 	struct ib_ucm_attr_id *cmd;
310 	void *msg;
311 	int result;
312 	int size;
313 
314 	if (!param)
315 		return ERR(EINVAL);
316 
317 	CM_CREATE_MSG_CMD_RESP(msg, cmd, resp, IB_USER_CM_CMD_ATTR_ID, size);
318 	cmd->id = cm_id->handle;
319 
320 	result = write(cm_id->device->fd, msg, size);
321 	if (result != size)
322 		return (result >= 0) ? ERR(ENODATA) : -1;
323 
324 	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
325 
326 	param->service_id   = resp->service_id;
327 	param->service_mask = resp->service_mask;
328 	param->local_id     = resp->local_id;
329 	param->remote_id    = resp->remote_id;
330 	return 0;
331 }
332 
333 int ib_cm_init_qp_attr(struct ib_cm_id *cm_id,
334 		       struct ibv_qp_attr *qp_attr,
335 		       int *qp_attr_mask)
336 {
337 	struct ibv_kern_qp_attr *resp;
338 	struct ib_ucm_init_qp_attr *cmd;
339 	void *msg;
340 	int result;
341 	int size;
342 
343 	if (!qp_attr || !qp_attr_mask)
344 		return ERR(EINVAL);
345 
346 	CM_CREATE_MSG_CMD_RESP(msg, cmd, resp, IB_USER_CM_CMD_INIT_QP_ATTR, size);
347 	cmd->id = cm_id->handle;
348 	cmd->qp_state = qp_attr->qp_state;
349 
350 	result = write(cm_id->device->fd, msg, size);
351 	if (result != size)
352 		return (result >= 0) ? ERR(ENODATA) : result;
353 
354 	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
355 
356 	*qp_attr_mask = resp->qp_attr_mask;
357 	ibv_copy_qp_attr_from_kern(qp_attr, resp);
358 
359 	return 0;
360 }
361 
362 int ib_cm_listen(struct ib_cm_id *cm_id,
363 		 __be64 service_id,
364 		 __be64 service_mask)
365 {
366 	struct ib_ucm_listen *cmd;
367 	void *msg;
368 	int result;
369 	int size;
370 
371 	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_LISTEN, size);
372 	cmd->id           = cm_id->handle;
373 	cmd->service_id   = service_id;
374 	cmd->service_mask = service_mask;
375 
376 	result = write(cm_id->device->fd, msg, size);
377 	if (result != size)
378 		return (result >= 0) ? ERR(ENODATA) : -1;
379 
380 	return 0;
381 }
382 
383 int ib_cm_send_req(struct ib_cm_id *cm_id, struct ib_cm_req_param *param)
384 {
385 	struct ib_user_path_rec p_path;
386 	struct ib_user_path_rec *a_path;
387 	struct ib_ucm_req *cmd;
388 	void *msg;
389 	int result;
390 	int size;
391 
392 	if (!param || !param->primary_path)
393 		return ERR(EINVAL);
394 
395 	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_REQ, size);
396 	cmd->id				= cm_id->handle;
397 	cmd->qpn			= param->qp_num;
398 	cmd->qp_type			= param->qp_type;
399 	cmd->psn			= param->starting_psn;
400         cmd->sid			= param->service_id;
401         cmd->peer_to_peer               = param->peer_to_peer;
402         cmd->responder_resources        = param->responder_resources;
403         cmd->initiator_depth            = param->initiator_depth;
404         cmd->remote_cm_response_timeout = param->remote_cm_response_timeout;
405         cmd->flow_control               = param->flow_control;
406         cmd->local_cm_response_timeout  = param->local_cm_response_timeout;
407         cmd->retry_count                = param->retry_count;
408         cmd->rnr_retry_count            = param->rnr_retry_count;
409         cmd->max_cm_retries             = param->max_cm_retries;
410         cmd->srq                        = param->srq;
411 
412 	ibv_copy_path_rec_to_kern(&p_path, param->primary_path);
413 	cmd->primary_path = (uintptr_t) &p_path;
414 
415 	if (param->alternate_path) {
416 		a_path = alloca(sizeof(*a_path));
417 		if (!a_path)
418 			return ERR(ENOMEM);
419 
420 		ibv_copy_path_rec_to_kern(a_path, param->alternate_path);
421 		cmd->alternate_path = (uintptr_t) a_path;
422 	}
423 
424 	if (param->private_data && param->private_data_len) {
425 		cmd->data = (uintptr_t) param->private_data;
426 		cmd->len  = param->private_data_len;
427 	}
428 
429 	result = write(cm_id->device->fd, msg, size);
430 	if (result != size)
431 		return (result >= 0) ? ERR(ENODATA) : -1;
432 
433 	return 0;
434 }
435 
436 int ib_cm_send_rep(struct ib_cm_id *cm_id, struct ib_cm_rep_param *param)
437 {
438 	struct ib_ucm_rep *cmd;
439 	void *msg;
440 	int result;
441 	int size;
442 
443 	if (!param)
444 		return ERR(EINVAL);
445 
446 	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_REP, size);
447 	cmd->uid = (uintptr_t) container_of(cm_id, struct cm_id_private, id);
448 	cmd->id			 = cm_id->handle;
449 	cmd->qpn		 = param->qp_num;
450 	cmd->psn		 = param->starting_psn;
451         cmd->responder_resources = param->responder_resources;
452         cmd->initiator_depth     = param->initiator_depth;
453 	cmd->target_ack_delay    = param->target_ack_delay;
454 	cmd->failover_accepted   = param->failover_accepted;
455         cmd->flow_control        = param->flow_control;
456         cmd->rnr_retry_count     = param->rnr_retry_count;
457         cmd->srq                 = param->srq;
458 
459 	if (param->private_data && param->private_data_len) {
460 		cmd->data = (uintptr_t) param->private_data;
461 		cmd->len  = param->private_data_len;
462 	}
463 
464 	result = write(cm_id->device->fd, msg, size);
465 	if (result != size)
466 		return (result >= 0) ? ERR(ENODATA) : -1;
467 
468 	return 0;
469 }
470 
471 static inline int cm_send_private_data(struct ib_cm_id *cm_id,
472 				       uint32_t type,
473 				       void *private_data,
474 				       uint8_t private_data_len)
475 {
476 	struct ib_ucm_private_data *cmd;
477 	void *msg;
478 	int result;
479 	int size;
480 
481 	CM_CREATE_MSG_CMD(msg, cmd, type, size);
482 	cmd->id = cm_id->handle;
483 
484 	if (private_data && private_data_len) {
485 		cmd->data = (uintptr_t) private_data;
486 		cmd->len  = private_data_len;
487 	}
488 
489 	result = write(cm_id->device->fd, msg, size);
490 	if (result != size)
491 		return (result >= 0) ? ERR(ENODATA) : -1;
492 
493 	return 0;
494 }
495 
496 int ib_cm_send_rtu(struct ib_cm_id *cm_id,
497 		   void *private_data,
498 		   uint8_t private_data_len)
499 {
500 	return cm_send_private_data(cm_id, IB_USER_CM_CMD_SEND_RTU,
501 				    private_data, private_data_len);
502 }
503 
504 int ib_cm_send_dreq(struct ib_cm_id *cm_id,
505 		    void *private_data,
506 		    uint8_t private_data_len)
507 {
508 	return cm_send_private_data(cm_id, IB_USER_CM_CMD_SEND_DREQ,
509 				    private_data, private_data_len);
510 }
511 
512 int ib_cm_send_drep(struct ib_cm_id *cm_id,
513 		    void *private_data,
514 		    uint8_t private_data_len)
515 {
516 	return cm_send_private_data(cm_id, IB_USER_CM_CMD_SEND_DREP,
517 				    private_data, private_data_len);
518 }
519 
520 static int cm_establish(struct ib_cm_id *cm_id)
521 {
522 	/* In kernel ABI 4 ESTABLISH was repurposed as NOTIFY and gained an
523 	   extra field. For some reason the compat definitions were deleted
524 	   from the uapi headers :( */
525 #define IB_USER_CM_CMD_ESTABLISH IB_USER_CM_CMD_NOTIFY
526 	struct cm_abi_establish { /* ABI 4 support */
527 		__u32 id;
528 	};
529 
530 	struct cm_abi_establish *cmd;
531 	void *msg;
532 	int result;
533 	int size;
534 
535 	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_ESTABLISH, size);
536 	cmd->id = cm_id->handle;
537 
538 	result = write(cm_id->device->fd, msg, size);
539 	if (result != size)
540 		return (result >= 0) ? ERR(ENODATA) : -1;
541 
542 	return 0;
543 }
544 
545 int ib_cm_notify(struct ib_cm_id *cm_id, enum ibv_event_type event)
546 {
547 	struct ib_ucm_notify *cmd;
548 	void *msg;
549 	int result;
550 	int size;
551 
552 	if (abi_ver == 4) {
553 		if (event == IBV_EVENT_COMM_EST)
554 			return cm_establish(cm_id);
555 		else
556 			return ERR(EINVAL);
557 	}
558 
559 	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_NOTIFY, size);
560 	cmd->id = cm_id->handle;
561 	cmd->event = event;
562 
563 	result = write(cm_id->device->fd, msg, size);
564 	if (result != size)
565 		return (result >= 0) ? ERR(ENODATA) : -1;
566 
567 	return 0;
568 }
569 
570 static inline int cm_send_status(struct ib_cm_id *cm_id,
571 				 uint32_t type,
572 				 int status,
573 				 void *info,
574 				 uint8_t info_length,
575 				 void *private_data,
576 				 uint8_t private_data_len)
577 {
578 	struct ib_ucm_info *cmd;
579 	void *msg;
580 	int result;
581 	int size;
582 
583 	CM_CREATE_MSG_CMD(msg, cmd, type, size);
584 	cmd->id     = cm_id->handle;
585 	cmd->status = status;
586 
587 	if (private_data && private_data_len) {
588 		cmd->data     = (uintptr_t) private_data;
589 		cmd->data_len = private_data_len;
590 	}
591 
592 	if (info && info_length) {
593 		cmd->info     = (uintptr_t) info;
594 		cmd->info_len = info_length;
595 	}
596 
597 	result = write(cm_id->device->fd, msg, size);
598 	if (result != size)
599 		return (result >= 0) ? ERR(ENODATA) : -1;
600 
601 	return 0;
602 }
603 
604 int ib_cm_send_rej(struct ib_cm_id *cm_id,
605 		   enum ib_cm_rej_reason reason,
606 		   void *ari,
607 		   uint8_t ari_length,
608 		   void *private_data,
609 		   uint8_t private_data_len)
610 {
611 	return cm_send_status(cm_id, IB_USER_CM_CMD_SEND_REJ, reason,
612 			      ari, ari_length,
613 			      private_data, private_data_len);
614 }
615 
616 int ib_cm_send_apr(struct ib_cm_id *cm_id,
617 		   enum ib_cm_apr_status status,
618 		   void *info,
619 		   uint8_t info_length,
620 		   void *private_data,
621 		   uint8_t private_data_len)
622 {
623 	return cm_send_status(cm_id, IB_USER_CM_CMD_SEND_APR, status,
624 			      info, info_length,
625 			      private_data, private_data_len);
626 }
627 
628 int ib_cm_send_mra(struct ib_cm_id *cm_id,
629 		   uint8_t service_timeout,
630 		   void *private_data,
631 		   uint8_t private_data_len)
632 {
633 	struct ib_ucm_mra *cmd;
634 	void *msg;
635 	int result;
636 	int size;
637 
638 	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_MRA, size);
639 	cmd->id      = cm_id->handle;
640 	cmd->timeout = service_timeout;
641 
642 	if (private_data && private_data_len) {
643 		cmd->data = (uintptr_t) private_data;
644 		cmd->len  = private_data_len;
645 	}
646 
647 	result = write(cm_id->device->fd, msg, size);
648 	if (result != size)
649 		return (result >= 0) ? ERR(ENODATA) : result;
650 
651 	return 0;
652 }
653 
654 int ib_cm_send_lap(struct ib_cm_id *cm_id,
655 		   struct ibv_sa_path_rec *alternate_path,
656 		   void *private_data,
657 		   uint8_t private_data_len)
658 {
659 	struct ib_user_path_rec abi_path;
660 	struct ib_ucm_lap *cmd;
661 	void *msg;
662 	int result;
663 	int size;
664 
665 	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_LAP, size);
666 	cmd->id = cm_id->handle;
667 
668 	ibv_copy_path_rec_to_kern(&abi_path, alternate_path);
669 	cmd->path = (uintptr_t) &abi_path;
670 
671 	if (private_data && private_data_len) {
672 		cmd->data = (uintptr_t) private_data;
673 		cmd->len  = private_data_len;
674 	}
675 
676 	result = write(cm_id->device->fd, msg, size);
677 	if (result != size)
678 		return (result >= 0) ? ERR(ENODATA) : -1;
679 
680 	return 0;
681 }
682 
683 int ib_cm_send_sidr_req(struct ib_cm_id *cm_id,
684 			struct ib_cm_sidr_req_param *param)
685 {
686 	struct ib_user_path_rec abi_path;
687 	struct ib_ucm_sidr_req *cmd;
688 	void *msg;
689 	int result;
690 	int size;
691 
692 	if (!param || !param->path)
693 		return ERR(EINVAL);
694 
695 	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_SIDR_REQ, size);
696 	cmd->id             = cm_id->handle;
697 	cmd->sid            = param->service_id;
698 	cmd->timeout        = param->timeout_ms;
699 	cmd->max_cm_retries = param->max_cm_retries;
700 
701 	ibv_copy_path_rec_to_kern(&abi_path, param->path);
702 	cmd->path = (uintptr_t) &abi_path;
703 
704 	if (param->private_data && param->private_data_len) {
705 		cmd->data = (uintptr_t) param->private_data;
706 		cmd->len  = param->private_data_len;
707 	}
708 
709 	result = write(cm_id->device->fd, msg, size);
710 	if (result != size)
711 		return (result >= 0) ? ERR(ENODATA) : result;
712 
713 	return 0;
714 }
715 
716 int ib_cm_send_sidr_rep(struct ib_cm_id *cm_id,
717 			struct ib_cm_sidr_rep_param *param)
718 {
719 	struct ib_ucm_sidr_rep *cmd;
720 	void *msg;
721 	int result;
722 	int size;
723 
724 	if (!param)
725 		return ERR(EINVAL);
726 
727 	CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_SIDR_REP, size);
728 	cmd->id     = cm_id->handle;
729 	cmd->qpn    = param->qp_num;
730 	cmd->qkey   = param->qkey;
731 	cmd->status = param->status;
732 
733 	if (param->private_data && param->private_data_len) {
734 		cmd->data     = (uintptr_t) param->private_data;
735 		cmd->data_len = param->private_data_len;
736 	}
737 
738 	if (param->info && param->info_length) {
739 		cmd->info     = (uintptr_t) param->info;
740 		cmd->info_len = param->info_length;
741 	}
742 
743 	result = write(cm_id->device->fd, msg, size);
744 	if (result != size)
745 		return (result >= 0) ? ERR(ENODATA) : -1;
746 
747 	return 0;
748 }
749 
750 static void cm_event_req_get(struct ib_cm_req_event_param *ureq,
751 			     struct ib_ucm_req_event_resp *kreq)
752 {
753 	ureq->remote_ca_guid             = kreq->remote_ca_guid;
754 	ureq->remote_qkey                = kreq->remote_qkey;
755 	ureq->remote_qpn                 = kreq->remote_qpn;
756 	ureq->qp_type                    = kreq->qp_type;
757 	ureq->starting_psn               = kreq->starting_psn;
758 	ureq->responder_resources        = kreq->responder_resources;
759 	ureq->initiator_depth            = kreq->initiator_depth;
760 	ureq->local_cm_response_timeout  = kreq->local_cm_response_timeout;
761 	ureq->flow_control               = kreq->flow_control;
762 	ureq->remote_cm_response_timeout = kreq->remote_cm_response_timeout;
763 	ureq->retry_count                = kreq->retry_count;
764 	ureq->rnr_retry_count            = kreq->rnr_retry_count;
765 	ureq->srq                        = kreq->srq;
766 	ureq->port			 = kreq->port;
767 
768 	ibv_copy_path_rec_from_kern(ureq->primary_path, &kreq->primary_path);
769 	if (ureq->alternate_path)
770 		ibv_copy_path_rec_from_kern(ureq->alternate_path,
771 					    &kreq->alternate_path);
772 }
773 
774 static void cm_event_rep_get(struct ib_cm_rep_event_param *urep,
775 			     struct ib_ucm_rep_event_resp *krep)
776 {
777 	urep->remote_ca_guid      = krep->remote_ca_guid;
778 	urep->remote_qkey         = krep->remote_qkey;
779 	urep->remote_qpn          = krep->remote_qpn;
780 	urep->starting_psn        = krep->starting_psn;
781 	urep->responder_resources = krep->responder_resources;
782 	urep->initiator_depth     = krep->initiator_depth;
783 	urep->target_ack_delay    = krep->target_ack_delay;
784 	urep->failover_accepted   = krep->failover_accepted;
785 	urep->flow_control        = krep->flow_control;
786 	urep->rnr_retry_count     = krep->rnr_retry_count;
787 	urep->srq                 = krep->srq;
788 }
789 
790 static void cm_event_sidr_rep_get(struct ib_cm_sidr_rep_event_param *urep,
791 				  struct ib_ucm_sidr_rep_event_resp *krep)
792 {
793 	urep->status = krep->status;
794 	urep->qkey   = krep->qkey;
795 	urep->qpn    = krep->qpn;
796 };
797 
798 int ib_cm_get_event(struct ib_cm_device *device, struct ib_cm_event **event)
799 {
800 	struct cm_id_private *cm_id_priv;
801 	struct ib_ucm_cmd_hdr *hdr;
802 	struct ib_ucm_event_get *cmd;
803 	struct ib_ucm_event_resp *resp;
804 	struct ib_cm_event *evt = NULL;
805 	struct ibv_sa_path_rec *path_a = NULL;
806 	struct ibv_sa_path_rec *path_b = NULL;
807 	void *data = NULL;
808 	void *info = NULL;
809 	void *msg;
810 	int result = 0;
811 	int size;
812 
813 	if (!event)
814 		return ERR(EINVAL);
815 
816 	size = sizeof(*hdr) + sizeof(*cmd);
817 	msg = alloca(size);
818 	if (!msg)
819 		return ERR(ENOMEM);
820 
821 	hdr = msg;
822 	cmd = msg + sizeof(*hdr);
823 
824 	hdr->cmd = IB_USER_CM_CMD_EVENT;
825 	hdr->in  = sizeof(*cmd);
826 	hdr->out = sizeof(*resp);
827 
828 	memset(cmd, 0, sizeof(*cmd));
829 
830 	resp = alloca(sizeof(*resp));
831 	if (!resp)
832 		return ERR(ENOMEM);
833 
834 	cmd->response = (uintptr_t) resp;
835 	cmd->data_len = (uint8_t)(~0U);
836 	cmd->info_len = (uint8_t)(~0U);
837 
838 	data = malloc(cmd->data_len);
839 	if (!data) {
840 		result = ERR(ENOMEM);
841 		goto done;
842 	}
843 
844 	info = malloc(cmd->info_len);
845 	if (!info) {
846 		result = ERR(ENOMEM);
847 		goto done;
848 	}
849 
850 	cmd->data = (uintptr_t) data;
851 	cmd->info = (uintptr_t) info;
852 
853 	result = write(device->fd, msg, size);
854 	if (result != size) {
855 		result = (result >= 0) ? ERR(ENODATA) : -1;
856 		goto done;
857 	}
858 
859 	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
860 
861 	/*
862 	 * decode event.
863 	 */
864 	evt = malloc(sizeof(*evt));
865 	if (!evt) {
866 		result = ERR(ENOMEM);
867 		goto done;
868 	}
869 	memset(evt, 0, sizeof(*evt));
870 	evt->cm_id = (void *) (uintptr_t) resp->uid;
871 	evt->event = resp->event;
872 
873 	if (resp->present & IB_UCM_PRES_PRIMARY) {
874 		path_a = malloc(sizeof(*path_a));
875 		if (!path_a) {
876 			result = ERR(ENOMEM);
877 			goto done;
878 		}
879 	}
880 
881 	if (resp->present & IB_UCM_PRES_ALTERNATE) {
882 		path_b = malloc(sizeof(*path_b));
883 		if (!path_b) {
884 			result = ERR(ENOMEM);
885 			goto done;
886 		}
887 	}
888 
889 	switch (evt->event) {
890 	case IB_CM_REQ_RECEIVED:
891 		evt->param.req_rcvd.listen_id = evt->cm_id;
892 		cm_id_priv = ib_cm_alloc_id(evt->cm_id->device,
893 					    evt->cm_id->context);
894 		if (!cm_id_priv) {
895 			result = ERR(ENOMEM);
896 			goto done;
897 		}
898 		cm_id_priv->id.handle = resp->id;
899 		evt->cm_id = &cm_id_priv->id;
900 		evt->param.req_rcvd.primary_path   = path_a;
901 		evt->param.req_rcvd.alternate_path = path_b;
902 		path_a = NULL;
903 		path_b = NULL;
904 		cm_event_req_get(&evt->param.req_rcvd, &resp->u.req_resp);
905 		break;
906 	case IB_CM_REP_RECEIVED:
907 		cm_event_rep_get(&evt->param.rep_rcvd, &resp->u.rep_resp);
908 		break;
909 	case IB_CM_MRA_RECEIVED:
910 		evt->param.mra_rcvd.service_timeout = resp->u.mra_resp.timeout;
911 		break;
912 	case IB_CM_REJ_RECEIVED:
913 		evt->param.rej_rcvd.reason = resp->u.rej_resp.reason;
914 		evt->param.rej_rcvd.ari = info;
915 		info = NULL;
916 		break;
917 	case IB_CM_LAP_RECEIVED:
918 		evt->param.lap_rcvd.alternate_path = path_b;
919 		path_b = NULL;
920 		ibv_copy_path_rec_from_kern(evt->param.lap_rcvd.alternate_path,
921 					    &resp->u.lap_resp.path);
922 		break;
923 	case IB_CM_APR_RECEIVED:
924 		evt->param.apr_rcvd.ap_status = resp->u.apr_resp.status;
925 		evt->param.apr_rcvd.apr_info = info;
926 		info = NULL;
927 		break;
928 	case IB_CM_SIDR_REQ_RECEIVED:
929 		evt->param.sidr_req_rcvd.listen_id = evt->cm_id;
930 		cm_id_priv = ib_cm_alloc_id(evt->cm_id->device,
931 					    evt->cm_id->context);
932 		if (!cm_id_priv) {
933 			result = ERR(ENOMEM);
934 			goto done;
935 		}
936 		cm_id_priv->id.handle = resp->id;
937 		evt->cm_id = &cm_id_priv->id;
938 		evt->param.sidr_req_rcvd.pkey = resp->u.sidr_req_resp.pkey;
939 		evt->param.sidr_req_rcvd.port = resp->u.sidr_req_resp.port;
940 		break;
941 	case IB_CM_SIDR_REP_RECEIVED:
942 		cm_event_sidr_rep_get(&evt->param.sidr_rep_rcvd,
943 				      &resp->u.sidr_rep_resp);
944 		evt->param.sidr_rep_rcvd.info = info;
945 		info = NULL;
946 		break;
947 	default:
948 		evt->param.send_status = resp->u.send_status;
949 		break;
950 	}
951 
952 	if (resp->present & IB_UCM_PRES_DATA) {
953 		evt->private_data = data;
954 		data = NULL;
955 	}
956 
957 	*event = evt;
958 	evt    = NULL;
959 	result = 0;
960 done:
961 	if (data)
962 		free(data);
963 	if (info)
964 		free(info);
965 	if (path_a)
966 		free(path_a);
967 	if (path_b)
968 		free(path_b);
969 	if (evt)
970 		free(evt);
971 
972 	return result;
973 }
974 
975 int ib_cm_ack_event(struct ib_cm_event *event)
976 {
977 	struct cm_id_private *cm_id_priv;
978 
979 	if (!event)
980 		return ERR(EINVAL);
981 
982 	if (event->private_data)
983 		free(event->private_data);
984 
985 	cm_id_priv = container_of(event->cm_id, struct cm_id_private, id);
986 
987 	switch (event->event) {
988 	case IB_CM_REQ_RECEIVED:
989 		cm_id_priv = container_of(event->param.req_rcvd.listen_id,
990 					  struct cm_id_private, id);
991 		free(event->param.req_rcvd.primary_path);
992 		if (event->param.req_rcvd.alternate_path)
993 			free(event->param.req_rcvd.alternate_path);
994 		break;
995 	case IB_CM_REJ_RECEIVED:
996 		if (event->param.rej_rcvd.ari)
997 			free(event->param.rej_rcvd.ari);
998 		break;
999 	case IB_CM_LAP_RECEIVED:
1000 		free(event->param.lap_rcvd.alternate_path);
1001 		break;
1002 	case IB_CM_APR_RECEIVED:
1003 		if (event->param.apr_rcvd.apr_info)
1004 			free(event->param.apr_rcvd.apr_info);
1005 		break;
1006 	case IB_CM_SIDR_REQ_RECEIVED:
1007 		cm_id_priv = container_of(event->param.sidr_req_rcvd.listen_id,
1008 					  struct cm_id_private, id);
1009 		break;
1010 	case IB_CM_SIDR_REP_RECEIVED:
1011 		if (event->param.sidr_rep_rcvd.info)
1012 			free(event->param.sidr_rep_rcvd.info);
1013 	default:
1014 		break;
1015 	}
1016 
1017 	pthread_mutex_lock(&cm_id_priv->mut);
1018 	cm_id_priv->events_completed++;
1019 	pthread_cond_signal(&cm_id_priv->cond);
1020 	pthread_mutex_unlock(&cm_id_priv->mut);
1021 
1022 	free(event);
1023 	return 0;
1024 }
1025