IB/qib: Move COUNTER_MASK definition within qib_mad.h header guards
[firefly-linux-kernel-4.4.55.git] / drivers / infiniband / core / ucma.c
index 5ca44cd9b00cc5113968077783400c59912503b9..b0f189be543bf61749bdcf37d6fd7a17f3d57fcc 100644 (file)
@@ -47,6 +47,8 @@
 #include <rdma/ib_marshall.h>
 #include <rdma/rdma_cm.h>
 #include <rdma/rdma_cm_ib.h>
+#include <rdma/ib_addr.h>
+#include <rdma/ib.h>
 
 MODULE_AUTHOR("Sean Hefty");
 MODULE_DESCRIPTION("RDMA Userspace Connection Manager Access");
@@ -510,10 +512,10 @@ static ssize_t ucma_destroy_id(struct ucma_file *file, const char __user *inbuf,
        return ret;
 }
 
-static ssize_t ucma_bind_addr(struct ucma_file *file, const char __user *inbuf,
+static ssize_t ucma_bind_ip(struct ucma_file *file, const char __user *inbuf,
                              int in_len, int out_len)
 {
-       struct rdma_ucm_bind_addr cmd;
+       struct rdma_ucm_bind_ip cmd;
        struct ucma_context *ctx;
        int ret;
 
@@ -529,24 +531,75 @@ static ssize_t ucma_bind_addr(struct ucma_file *file, const char __user *inbuf,
        return ret;
 }
 
+static ssize_t ucma_bind(struct ucma_file *file, const char __user *inbuf,
+                        int in_len, int out_len)
+{
+       struct rdma_ucm_bind cmd;
+       struct sockaddr *addr;
+       struct ucma_context *ctx;
+       int ret;
+
+       if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+               return -EFAULT;
+
+       addr = (struct sockaddr *) &cmd.addr;
+       if (cmd.reserved || !cmd.addr_size || (cmd.addr_size != rdma_addr_size(addr)))
+               return -EINVAL;
+
+       ctx = ucma_get_ctx(file, cmd.id);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
+
+       ret = rdma_bind_addr(ctx->cm_id, addr);
+       ucma_put_ctx(ctx);
+       return ret;
+}
+
+static ssize_t ucma_resolve_ip(struct ucma_file *file,
+                              const char __user *inbuf,
+                              int in_len, int out_len)
+{
+       struct rdma_ucm_resolve_ip cmd;
+       struct ucma_context *ctx;
+       int ret;
+
+       if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+               return -EFAULT;
+
+       ctx = ucma_get_ctx(file, cmd.id);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
+
+       ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
+                               (struct sockaddr *) &cmd.dst_addr,
+                               cmd.timeout_ms);
+       ucma_put_ctx(ctx);
+       return ret;
+}
+
 static ssize_t ucma_resolve_addr(struct ucma_file *file,
                                 const char __user *inbuf,
                                 int in_len, int out_len)
 {
        struct rdma_ucm_resolve_addr cmd;
+       struct sockaddr *src, *dst;
        struct ucma_context *ctx;
        int ret;
 
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
+       src = (struct sockaddr *) &cmd.src_addr;
+       dst = (struct sockaddr *) &cmd.dst_addr;
+       if (cmd.reserved || (cmd.src_size && (cmd.src_size != rdma_addr_size(src))) ||
+           !cmd.dst_size || (cmd.dst_size != rdma_addr_size(dst)))
+               return -EINVAL;
+
        ctx = ucma_get_ctx(file, cmd.id);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
-       ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
-                               (struct sockaddr *) &cmd.dst_addr,
-                               cmd.timeout_ms);
+       ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms);
        ucma_put_ctx(ctx);
        return ret;
 }
@@ -649,7 +702,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 +762,162 @@ 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_path(struct ucma_context *ctx,
+                              void __user *response, int out_len)
+{
+       struct rdma_ucm_query_path_resp *resp;
+       int i, ret = 0;
+
+       if (out_len < sizeof(*resp))
+               return -ENOSPC;
+
+       resp = kzalloc(out_len, GFP_KERNEL);
+       if (!resp)
+               return -ENOMEM;
+
+       resp->num_paths = ctx->cm_id->route.num_paths;
+       for (i = 0, out_len -= sizeof(*resp);
+            i < resp->num_paths && out_len > sizeof(struct ib_path_rec_data);
+            i++, out_len -= sizeof(struct ib_path_rec_data)) {
+
+               resp->path_data[i].flags = IB_PATH_GMP | IB_PATH_PRIMARY |
+                                          IB_PATH_BIDIRECTIONAL;
+               ib_sa_pack_path(&ctx->cm_id->route.path_rec[i],
+                               &resp->path_data[i].path_rec);
+       }
+
+       if (copy_to_user(response, resp,
+                        sizeof(*resp) + (i * sizeof(struct ib_path_rec_data))))
+               ret = -EFAULT;
+
+       kfree(resp);
+       return ret;
+}
+
+static ssize_t ucma_query_gid(struct ucma_context *ctx,
+                             void __user *response, int out_len)
+{
+       struct rdma_ucm_query_addr_resp resp;
+       struct sockaddr_ib *addr;
+       int ret = 0;
+
+       if (out_len < sizeof(resp))
+               return -ENOSPC;
+
+       memset(&resp, 0, sizeof resp);
+
+       ucma_query_device_addr(ctx->cm_id, &resp);
+
+       addr = (struct sockaddr_ib *) &resp.src_addr;
+       resp.src_size = sizeof(*addr);
+       if (ctx->cm_id->route.addr.src_addr.ss_family == AF_IB) {
+               memcpy(addr, &ctx->cm_id->route.addr.src_addr, resp.src_size);
+       } else {
+               addr->sib_family = AF_IB;
+               addr->sib_pkey = (__force __be16) resp.pkey;
+               rdma_addr_get_sgid(&ctx->cm_id->route.addr.dev_addr,
+                                  (union ib_gid *) &addr->sib_addr);
+               addr->sib_sid = rdma_get_service_id(ctx->cm_id, (struct sockaddr *)
+                                                   &ctx->cm_id->route.addr.src_addr);
+       }
+
+       addr = (struct sockaddr_ib *) &resp.dst_addr;
+       resp.dst_size = sizeof(*addr);
+       if (ctx->cm_id->route.addr.dst_addr.ss_family == AF_IB) {
+               memcpy(addr, &ctx->cm_id->route.addr.dst_addr, resp.dst_size);
+       } else {
+               addr->sib_family = AF_IB;
+               addr->sib_pkey = (__force __be16) resp.pkey;
+               rdma_addr_get_dgid(&ctx->cm_id->route.addr.dev_addr,
+                                  (union ib_gid *) &addr->sib_addr);
+               addr->sib_sid = rdma_get_service_id(ctx->cm_id, (struct sockaddr *)
+                                                   &ctx->cm_id->route.addr.dst_addr);
+       }
+
+       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;
+       case RDMA_USER_CM_QUERY_PATH:
+               ret = ucma_query_path(ctx, response, out_len);
+               break;
+       case RDMA_USER_CM_QUERY_GID:
+               ret = ucma_query_gid(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 +929,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 +950,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 +993,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)
@@ -1020,23 +1229,23 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
        return ret;
 }
 
-static ssize_t ucma_join_multicast(struct ucma_file *file,
-                                  const char __user *inbuf,
-                                  int in_len, int out_len)
+static ssize_t ucma_process_join(struct ucma_file *file,
+                                struct rdma_ucm_join_mcast *cmd,  int out_len)
 {
-       struct rdma_ucm_join_mcast cmd;
        struct rdma_ucm_create_id_resp resp;
        struct ucma_context *ctx;
        struct ucma_multicast *mc;
+       struct sockaddr *addr;
        int ret;
 
        if (out_len < sizeof(resp))
                return -ENOSPC;
 
-       if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
-               return -EFAULT;
+       addr = (struct sockaddr *) &cmd->addr;
+       if (cmd->reserved || !cmd->addr_size || (cmd->addr_size != rdma_addr_size(addr)))
+               return -EINVAL;
 
-       ctx = ucma_get_ctx(file, cmd.id);
+       ctx = ucma_get_ctx(file, cmd->id);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
@@ -1047,14 +1256,14 @@ static ssize_t ucma_join_multicast(struct ucma_file *file,
                goto err1;
        }
 
-       mc->uid = cmd.uid;
-       memcpy(&mc->addr, &cmd.addr, sizeof cmd.addr);
+       mc->uid = cmd->uid;
+       memcpy(&mc->addr, addr, cmd->addr_size);
        ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr, mc);
        if (ret)
                goto err2;
 
        resp.id = mc->id;
-       if (copy_to_user((void __user *)(unsigned long)cmd.response,
+       if (copy_to_user((void __user *)(unsigned long) cmd->response,
                         &resp, sizeof(resp))) {
                ret = -EFAULT;
                goto err3;
@@ -1079,6 +1288,38 @@ err1:
        return ret;
 }
 
+static ssize_t ucma_join_ip_multicast(struct ucma_file *file,
+                                     const char __user *inbuf,
+                                     int in_len, int out_len)
+{
+       struct rdma_ucm_join_ip_mcast cmd;
+       struct rdma_ucm_join_mcast join_cmd;
+
+       if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+               return -EFAULT;
+
+       join_cmd.response = cmd.response;
+       join_cmd.uid = cmd.uid;
+       join_cmd.id = cmd.id;
+       join_cmd.addr_size = rdma_addr_size((struct sockaddr *) &cmd.addr);
+       join_cmd.reserved = 0;
+       memcpy(&join_cmd.addr, &cmd.addr, join_cmd.addr_size);
+
+       return ucma_process_join(file, &join_cmd, out_len);
+}
+
+static ssize_t ucma_join_multicast(struct ucma_file *file,
+                                  const char __user *inbuf,
+                                  int in_len, int out_len)
+{
+       struct rdma_ucm_join_mcast cmd;
+
+       if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+               return -EFAULT;
+
+       return ucma_process_join(file, &cmd, out_len);
+}
+
 static ssize_t ucma_leave_multicast(struct ucma_file *file,
                                    const char __user *inbuf,
                                    int in_len, int out_len)
@@ -1221,25 +1462,29 @@ file_put:
 static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
                                   const char __user *inbuf,
                                   int in_len, int out_len) = {
-       [RDMA_USER_CM_CMD_CREATE_ID]    = ucma_create_id,
-       [RDMA_USER_CM_CMD_DESTROY_ID]   = ucma_destroy_id,
-       [RDMA_USER_CM_CMD_BIND_ADDR]    = ucma_bind_addr,
-       [RDMA_USER_CM_CMD_RESOLVE_ADDR] = ucma_resolve_addr,
-       [RDMA_USER_CM_CMD_RESOLVE_ROUTE]= ucma_resolve_route,
-       [RDMA_USER_CM_CMD_QUERY_ROUTE]  = ucma_query_route,
-       [RDMA_USER_CM_CMD_CONNECT]      = ucma_connect,
-       [RDMA_USER_CM_CMD_LISTEN]       = ucma_listen,
-       [RDMA_USER_CM_CMD_ACCEPT]       = ucma_accept,
-       [RDMA_USER_CM_CMD_REJECT]       = ucma_reject,
-       [RDMA_USER_CM_CMD_DISCONNECT]   = ucma_disconnect,
-       [RDMA_USER_CM_CMD_INIT_QP_ATTR] = ucma_init_qp_attr,
-       [RDMA_USER_CM_CMD_GET_EVENT]    = ucma_get_event,
-       [RDMA_USER_CM_CMD_GET_OPTION]   = NULL,
-       [RDMA_USER_CM_CMD_SET_OPTION]   = ucma_set_option,
-       [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_CREATE_ID]     = ucma_create_id,
+       [RDMA_USER_CM_CMD_DESTROY_ID]    = ucma_destroy_id,
+       [RDMA_USER_CM_CMD_BIND_IP]       = ucma_bind_ip,
+       [RDMA_USER_CM_CMD_RESOLVE_IP]    = ucma_resolve_ip,
+       [RDMA_USER_CM_CMD_RESOLVE_ROUTE] = ucma_resolve_route,
+       [RDMA_USER_CM_CMD_QUERY_ROUTE]   = ucma_query_route,
+       [RDMA_USER_CM_CMD_CONNECT]       = ucma_connect,
+       [RDMA_USER_CM_CMD_LISTEN]        = ucma_listen,
+       [RDMA_USER_CM_CMD_ACCEPT]        = ucma_accept,
+       [RDMA_USER_CM_CMD_REJECT]        = ucma_reject,
+       [RDMA_USER_CM_CMD_DISCONNECT]    = ucma_disconnect,
+       [RDMA_USER_CM_CMD_INIT_QP_ATTR]  = ucma_init_qp_attr,
+       [RDMA_USER_CM_CMD_GET_EVENT]     = ucma_get_event,
+       [RDMA_USER_CM_CMD_GET_OPTION]    = NULL,
+       [RDMA_USER_CM_CMD_SET_OPTION]    = ucma_set_option,
+       [RDMA_USER_CM_CMD_NOTIFY]        = ucma_notify,
+       [RDMA_USER_CM_CMD_JOIN_IP_MCAST] = ucma_join_ip_multicast,
+       [RDMA_USER_CM_CMD_LEAVE_MCAST]   = ucma_leave_multicast,
+       [RDMA_USER_CM_CMD_MIGRATE_ID]    = ucma_migrate_id,
+       [RDMA_USER_CM_CMD_QUERY]         = ucma_query,
+       [RDMA_USER_CM_CMD_BIND]          = ucma_bind,
+       [RDMA_USER_CM_CMD_RESOLVE_ADDR]  = ucma_resolve_addr,
+       [RDMA_USER_CM_CMD_JOIN_MCAST]    = ucma_join_multicast
 };
 
 static ssize_t ucma_write(struct file *filp, const char __user *buf,