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