RDMA/ucma: Support querying for AF_IB addresses
[cascardo/linux.git] / drivers / infiniband / core / ucma.c
index 5ca44cd..18bdccc 100644 (file)
@@ -47,6 +47,7 @@
 #include <rdma/ib_marshall.h>
 #include <rdma/rdma_cm.h>
 #include <rdma/rdma_cm_ib.h>
+#include <rdma/ib_addr.h>
 
 MODULE_AUTHOR("Sean Hefty");
 MODULE_DESCRIPTION("RDMA Userspace Connection Manager Access");
@@ -649,7 +650,7 @@ static ssize_t ucma_query_route(struct ucma_file *file,
                                const char __user *inbuf,
                                int in_len, int out_len)
 {
-       struct rdma_ucm_query_route cmd;
+       struct rdma_ucm_query cmd;
        struct rdma_ucm_query_route_resp resp;
        struct ucma_context *ctx;
        struct sockaddr *addr;
@@ -709,7 +710,78 @@ out:
        return ret;
 }
 
-static void ucma_copy_conn_param(struct rdma_conn_param *dst,
+static void ucma_query_device_addr(struct rdma_cm_id *cm_id,
+                                  struct rdma_ucm_query_addr_resp *resp)
+{
+       if (!cm_id->device)
+               return;
+
+       resp->node_guid = (__force __u64) cm_id->device->node_guid;
+       resp->port_num = cm_id->port_num;
+       resp->pkey = (__force __u16) cpu_to_be16(
+                    ib_addr_get_pkey(&cm_id->route.addr.dev_addr));
+}
+
+static ssize_t ucma_query_addr(struct ucma_context *ctx,
+                              void __user *response, int out_len)
+{
+       struct rdma_ucm_query_addr_resp resp;
+       struct sockaddr *addr;
+       int ret = 0;
+
+       if (out_len < sizeof(resp))
+               return -ENOSPC;
+
+       memset(&resp, 0, sizeof resp);
+
+       addr = (struct sockaddr *) &ctx->cm_id->route.addr.src_addr;
+       resp.src_size = rdma_addr_size(addr);
+       memcpy(&resp.src_addr, addr, resp.src_size);
+
+       addr = (struct sockaddr *) &ctx->cm_id->route.addr.dst_addr;
+       resp.dst_size = rdma_addr_size(addr);
+       memcpy(&resp.dst_addr, addr, resp.dst_size);
+
+       ucma_query_device_addr(ctx->cm_id, &resp);
+
+       if (copy_to_user(response, &resp, sizeof(resp)))
+               ret = -EFAULT;
+
+       return ret;
+}
+
+static ssize_t ucma_query(struct ucma_file *file,
+                         const char __user *inbuf,
+                         int in_len, int out_len)
+{
+       struct rdma_ucm_query cmd;
+       struct ucma_context *ctx;
+       void __user *response;
+       int ret;
+
+       if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+               return -EFAULT;
+
+       response = (void __user *)(unsigned long) cmd.response;
+       ctx = ucma_get_ctx(file, cmd.id);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
+
+       switch (cmd.option) {
+       case RDMA_USER_CM_QUERY_ADDR:
+               ret = ucma_query_addr(ctx, response, out_len);
+               break;
+       default:
+               ret = -ENOSYS;
+               break;
+       }
+
+       ucma_put_ctx(ctx);
+       return ret;
+}
+
+static void ucma_copy_conn_param(struct rdma_cm_id *id,
+                                struct rdma_conn_param *dst,
                                 struct rdma_ucm_conn_param *src)
 {
        dst->private_data = src->private_data;
@@ -721,6 +793,7 @@ static void ucma_copy_conn_param(struct rdma_conn_param *dst,
        dst->rnr_retry_count = src->rnr_retry_count;
        dst->srq = src->srq;
        dst->qp_num = src->qp_num;
+       dst->qkey = (id->route.addr.src_addr.ss_family == AF_IB) ? src->qkey : 0;
 }
 
 static ssize_t ucma_connect(struct ucma_file *file, const char __user *inbuf,
@@ -741,7 +814,7 @@ static ssize_t ucma_connect(struct ucma_file *file, const char __user *inbuf,
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
-       ucma_copy_conn_param(&conn_param, &cmd.conn_param);
+       ucma_copy_conn_param(ctx->cm_id, &conn_param, &cmd.conn_param);
        ret = rdma_connect(ctx->cm_id, &conn_param);
        ucma_put_ctx(ctx);
        return ret;
@@ -784,7 +857,7 @@ static ssize_t ucma_accept(struct ucma_file *file, const char __user *inbuf,
                return PTR_ERR(ctx);
 
        if (cmd.conn_param.valid) {
-               ucma_copy_conn_param(&conn_param, &cmd.conn_param);
+               ucma_copy_conn_param(ctx->cm_id, &conn_param, &cmd.conn_param);
                mutex_lock(&file->mut);
                ret = rdma_accept(ctx->cm_id, &conn_param);
                if (!ret)
@@ -1239,7 +1312,8 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
        [RDMA_USER_CM_CMD_NOTIFY]       = ucma_notify,
        [RDMA_USER_CM_CMD_JOIN_MCAST]   = ucma_join_multicast,
        [RDMA_USER_CM_CMD_LEAVE_MCAST]  = ucma_leave_multicast,
-       [RDMA_USER_CM_CMD_MIGRATE_ID]   = ucma_migrate_id
+       [RDMA_USER_CM_CMD_MIGRATE_ID]   = ucma_migrate_id,
+       [RDMA_USER_CM_CMD_QUERY]        = ucma_query
 };
 
 static ssize_t ucma_write(struct file *filp, const char __user *buf,