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