xref: /NextBSD/contrib/ofed/libibcm/src/cm.c (revision eb1a5f8de9f7ea602c373a710f531abbf81141c4)
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 
67 static int abi_ver;
68 static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
69 
70 enum {
71 	IB_UCM_MAX_DEVICES = 32
72 };
73 
ERR(int err)74 static 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) \
82 do {                                        \
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) \
102 do {                                        \
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 
117 struct 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 
check_abi_version(void)127 static 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 
ucm_init(void)149 static 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 
ucm_get_dev_index(char * dev_name)161 static 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 
ib_cm_open_device(struct ibv_context * device_context)186 struct 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 
216 err2:
217 	free(dev_path);
218 err1:
219 	free(dev);
220 	return NULL;
221 }
222 
ib_cm_close_device(struct ib_cm_device * device)223 void ib_cm_close_device(struct ib_cm_device *device)
224 {
225 	close(device->fd);
226 	free(device);
227 }
228 
ib_cm_free_id(struct cm_id_private * cm_id_priv)229 static 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 
ib_cm_alloc_id(struct ib_cm_device * device,void * context)236 static 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 
254 err:	ib_cm_free_id(cm_id_priv);
255 	return NULL;
256 }
257 
ib_cm_create_id(struct ib_cm_device * device,struct ib_cm_id ** cm_id,void * context)258 int 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 
285 err:	ib_cm_free_id(cm_id_priv);
286 	return result;
287 }
288 
ib_cm_destroy_id(struct ib_cm_id * cm_id)289 int 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 
ib_cm_attr_id(struct ib_cm_id * cm_id,struct ib_cm_attr_param * param)318 int 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 
ib_cm_init_qp_attr(struct ib_cm_id * cm_id,struct ibv_qp_attr * qp_attr,int * qp_attr_mask)345 int 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 
ib_cm_listen(struct ib_cm_id * cm_id,uint64_t service_id,uint64_t service_mask)374 int 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 
ib_cm_send_req(struct ib_cm_id * cm_id,struct ib_cm_req_param * param)395 int 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 
ib_cm_send_rep(struct ib_cm_id * cm_id,struct ib_cm_rep_param * param)454 int 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 
cm_send_private_data(struct ib_cm_id * cm_id,uint32_t type,void * private_data,uint8_t private_data_len)489 static 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 
ib_cm_send_rtu(struct ib_cm_id * cm_id,void * private_data,uint8_t private_data_len)514 int 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 
ib_cm_send_dreq(struct ib_cm_id * cm_id,void * private_data,uint8_t private_data_len)522 int 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 
ib_cm_send_drep(struct ib_cm_id * cm_id,void * private_data,uint8_t private_data_len)530 int 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 
cm_establish(struct ib_cm_id * cm_id)538 static 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 
ib_cm_notify(struct ib_cm_id * cm_id,enum ibv_event_type event)555 int 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 
cm_send_status(struct ib_cm_id * cm_id,uint32_t type,int status,void * info,uint8_t info_length,void * private_data,uint8_t private_data_len)580 static 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 
ib_cm_send_rej(struct ib_cm_id * cm_id,enum ib_cm_rej_reason reason,void * ari,uint8_t ari_length,void * private_data,uint8_t private_data_len)614 int 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 
ib_cm_send_apr(struct ib_cm_id * cm_id,enum ib_cm_apr_status status,void * info,uint8_t info_length,void * private_data,uint8_t private_data_len)626 int 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 
ib_cm_send_mra(struct ib_cm_id * cm_id,uint8_t service_timeout,void * private_data,uint8_t private_data_len)638 int 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 
ib_cm_send_lap(struct ib_cm_id * cm_id,struct ibv_sa_path_rec * alternate_path,void * private_data,uint8_t private_data_len)664 int 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 
ib_cm_send_sidr_req(struct ib_cm_id * cm_id,struct ib_cm_sidr_req_param * param)699 int 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 
ib_cm_send_sidr_rep(struct ib_cm_id * cm_id,struct ib_cm_sidr_rep_param * param)739 int 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 
cm_event_req_get(struct ib_cm_req_event_param * ureq,struct cm_abi_req_event_resp * kreq)773 static 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 
cm_event_rep_get(struct ib_cm_rep_event_param * urep,struct cm_abi_rep_event_resp * krep)797 static 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 
cm_event_sidr_rep_get(struct ib_cm_sidr_rep_event_param * urep,struct cm_abi_sidr_rep_event_resp * krep)813 static 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 
ib_cm_get_event(struct ib_cm_device * device,struct ib_cm_event ** event)821 int 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;
983 done:
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 
ib_cm_ack_event(struct ib_cm_event * event)998 int 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