Main batch of InfiniBand/RDMA changes for 3.16:

- Add iWARP port mapper to avoid conflicts between RDMA and normal
    stack TCP connections.
 
  - Fixes for i386 / x86-64 structure padding differences (ABI
    compatibility for 32-on-64) from Yann Droneaud.
 
  - A pile of SRP initiator fixes from Bart Van Assche.
 
  - Fixes for a writeback / memory allocation deadlock with NFS over
    IPoIB connected mode from Jiri Kosina.
 
  - The usual fixes and cleanups to mlx4, mlx5, cxgb4 and other
    low-level drivers.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJTlzyEAAoJEENa44ZhAt0h9yoP/1UeXlejOpCJyiNdtJZ+ilcU
 cb0PEzsjzqACyDqcoQ0EpQM3/3emccVIC3uUXK12mzlTIXOFYTeRLays/TbxZDLt
 FK5D/NrMmmJmciPt1ZRgUX82kFFRGScEfpkXYs7jxtRaNT7CW5KwSNQr6aFXskUz
 1gpdK1ARCN5rWcGl2HJx5o9C4c/Fa/Vov8lOsAkUZXD1SuPNT/fFN0u1pRzU68g0
 k3oj81XnZq5ejOBQKXEHImcmjXwaJ2yjmzxhSsKebqDWDdXuS/F9e4taKneHTZmr
 AdwJaLLJPWmAGi/vYYhkuLKpzIDpzMCqwr39lEabmjWvznYOlnjfVUXwUTE2nwNC
 DIXuHOLFrSvF2cNxh8ZeEYKS8AV+PjAOahPC5whkWkY256Q67uB7cy9ilWAK+7xS
 QcQ5Inr6iXvxIGYA4hNwUo8aK0NuKFwhkVVFEbkPaurbQZPqiKwyVE3w2FOws/Qp
 0kLLCVvpRQYjKzkxyof2tb1AcNuVNKXHrYk6RaBDJ9mjxHbhvY4OSt4CBxAAXBu6
 zoedUydN1Nz1UgAB1jDsBdyE2QQnXockA1+JJKNq6gM5Dz0DUdAylzQ2NqY9tnYz
 RTzihEPYIiQUkV3B8ErbqsuO6z7M830AXO5AR6bLZn1zgJ0cbMLBaKLA8LRufJI/
 qxNVwL32Uv1PjKZ+yX1x
 =Wcdc
 -----END PGP SIGNATURE-----

Merge tag 'rdma-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband

Pull main InfiniBand/RDMA updates from Roland Dreier:

 - add iWARP port mapper to avoid conflicts between RDMA and normal
   stack TCP connections.

 - fixes for i386 / x86-64 structure padding differences (ABI
   compatibility for 32-on-64) from Yann Droneaud.

 - a pile of SRP initiator fixes from Bart Van Assche.

 - fixes for a writeback / memory allocation deadlock with NFS over
   IPoIB connected mode from Jiri Kosina.

 - the usual fixes and cleanups to mlx4, mlx5, cxgb4 and other low-level
   drivers.

* tag 'rdma-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband: (61 commits)
  RDMA/cxgb4: Add support for iWARP Port Mapper user space service
  RDMA/nes: Add support for iWARP Port Mapper user space service
  RDMA/core: Add support for iWARP Port Mapper user space service
  IB/mlx4: Fix gfp passing in create_qp_common()
  IB/umad: Fix use-after-free on close
  IB/core: Fix kobject leak on device register error flow
  RDMA/cxgb4: add missing padding at end of struct c4iw_alloc_ucontext_resp
  mlx4_core: Fix GFP flags parameters to be gfp_t
  IB/core: Fix port kobject deletion during error flow
  IB/core: Remove unneeded kobject_get/put calls
  IB/core: Fix sparse warnings about redeclared functions
  IB/mad: Fix sparse warning about gfp_t use
  IB/mlx4: Implement IB_QP_CREATE_USE_GFP_NOIO
  IB: Add a QP creation flag to use GFP_NOIO allocations
  IB: Return error for unsupported QP creation flags
  IB: Allow build of hw/ and ulp/ subdirectories independently
  mlx4_core: Move handling of MLX4_QP_ST_MLX to proper switch statement
  RDMA/cxgb4: Add missing padding at end of struct c4iw_create_cq_resp
  IB/srp: Avoid problems if a header uses pr_fmt
  IB/umad: Fix error handling
  ...
This commit is contained in:
Linus Torvalds 2014-06-10 10:41:33 -07:00
commit 1d21b1bf53
76 changed files with 3871 additions and 734 deletions

View file

@ -1,18 +1,3 @@
obj-$(CONFIG_INFINIBAND) += core/ obj-$(CONFIG_INFINIBAND) += core/
obj-$(CONFIG_INFINIBAND_MTHCA) += hw/mthca/ obj-$(CONFIG_INFINIBAND) += hw/
obj-$(CONFIG_INFINIBAND_IPATH) += hw/ipath/ obj-$(CONFIG_INFINIBAND) += ulp/
obj-$(CONFIG_INFINIBAND_QIB) += hw/qib/
obj-$(CONFIG_INFINIBAND_EHCA) += hw/ehca/
obj-$(CONFIG_INFINIBAND_AMSO1100) += hw/amso1100/
obj-$(CONFIG_INFINIBAND_CXGB3) += hw/cxgb3/
obj-$(CONFIG_INFINIBAND_CXGB4) += hw/cxgb4/
obj-$(CONFIG_MLX4_INFINIBAND) += hw/mlx4/
obj-$(CONFIG_MLX5_INFINIBAND) += hw/mlx5/
obj-$(CONFIG_INFINIBAND_NES) += hw/nes/
obj-$(CONFIG_INFINIBAND_OCRDMA) += hw/ocrdma/
obj-$(CONFIG_INFINIBAND_USNIC) += hw/usnic/
obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/
obj-$(CONFIG_INFINIBAND_SRP) += ulp/srp/
obj-$(CONFIG_INFINIBAND_SRPT) += ulp/srpt/
obj-$(CONFIG_INFINIBAND_ISER) += ulp/iser/
obj-$(CONFIG_INFINIBAND_ISERT) += ulp/isert/

View file

@ -18,7 +18,7 @@ ib_sa-y := sa_query.o multicast.o
ib_cm-y := cm.o ib_cm-y := cm.o
iw_cm-y := iwcm.o iw_cm-y := iwcm.o iwpm_util.o iwpm_msg.o
rdma_cm-y := cma.o rdma_cm-y := cma.o

View file

@ -3607,7 +3607,8 @@ static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb)
id_stats = ibnl_put_msg(skb, &nlh, cb->nlh->nlmsg_seq, id_stats = ibnl_put_msg(skb, &nlh, cb->nlh->nlmsg_seq,
sizeof *id_stats, RDMA_NL_RDMA_CM, sizeof *id_stats, RDMA_NL_RDMA_CM,
RDMA_NL_RDMA_CM_ID_STATS); RDMA_NL_RDMA_CM_ID_STATS,
NLM_F_MULTI);
if (!id_stats) if (!id_stats)
goto out; goto out;

View file

@ -0,0 +1,685 @@
/*
* Copyright (c) 2014 Intel Corporation. All rights reserved.
* Copyright (c) 2014 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "iwpm_util.h"
static const char iwpm_ulib_name[] = "iWarpPortMapperUser";
static int iwpm_ulib_version = 3;
static int iwpm_user_pid = IWPM_PID_UNDEFINED;
static atomic_t echo_nlmsg_seq;
int iwpm_valid_pid(void)
{
return iwpm_user_pid > 0;
}
EXPORT_SYMBOL(iwpm_valid_pid);
/*
* iwpm_register_pid - Send a netlink query to user space
* for the iwarp port mapper pid
*
* nlmsg attributes:
* [IWPM_NLA_REG_PID_SEQ]
* [IWPM_NLA_REG_IF_NAME]
* [IWPM_NLA_REG_IBDEV_NAME]
* [IWPM_NLA_REG_ULIB_NAME]
*/
int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client)
{
struct sk_buff *skb = NULL;
struct iwpm_nlmsg_request *nlmsg_request = NULL;
struct nlmsghdr *nlh;
u32 msg_seq;
const char *err_str = "";
int ret = -EINVAL;
if (!iwpm_valid_client(nl_client)) {
err_str = "Invalid port mapper client";
goto pid_query_error;
}
if (iwpm_registered_client(nl_client))
return 0;
skb = iwpm_create_nlmsg(RDMA_NL_IWPM_REG_PID, &nlh, nl_client);
if (!skb) {
err_str = "Unable to create a nlmsg";
goto pid_query_error;
}
nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
nlmsg_request = iwpm_get_nlmsg_request(nlh->nlmsg_seq, nl_client, GFP_KERNEL);
if (!nlmsg_request) {
err_str = "Unable to allocate netlink request";
goto pid_query_error;
}
msg_seq = atomic_read(&echo_nlmsg_seq);
/* fill in the pid request message */
err_str = "Unable to put attribute of the nlmsg";
ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, IWPM_NLA_REG_PID_SEQ);
if (ret)
goto pid_query_error;
ret = ibnl_put_attr(skb, nlh, IWPM_IFNAME_SIZE,
pm_msg->if_name, IWPM_NLA_REG_IF_NAME);
if (ret)
goto pid_query_error;
ret = ibnl_put_attr(skb, nlh, IWPM_DEVNAME_SIZE,
pm_msg->dev_name, IWPM_NLA_REG_IBDEV_NAME);
if (ret)
goto pid_query_error;
ret = ibnl_put_attr(skb, nlh, IWPM_ULIBNAME_SIZE,
(char *)iwpm_ulib_name, IWPM_NLA_REG_ULIB_NAME);
if (ret)
goto pid_query_error;
pr_debug("%s: Multicasting a nlmsg (dev = %s ifname = %s iwpm = %s)\n",
__func__, pm_msg->dev_name, pm_msg->if_name, iwpm_ulib_name);
ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_IWPM, GFP_KERNEL);
if (ret) {
skb = NULL; /* skb is freed in the netlink send-op handling */
iwpm_set_registered(nl_client, 1);
iwpm_user_pid = IWPM_PID_UNAVAILABLE;
err_str = "Unable to send a nlmsg";
goto pid_query_error;
}
nlmsg_request->req_buffer = pm_msg;
ret = iwpm_wait_complete_req(nlmsg_request);
return ret;
pid_query_error:
pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client);
if (skb)
dev_kfree_skb(skb);
if (nlmsg_request)
iwpm_free_nlmsg_request(&nlmsg_request->kref);
return ret;
}
EXPORT_SYMBOL(iwpm_register_pid);
/*
* iwpm_add_mapping - Send a netlink add mapping message
* to the port mapper
* nlmsg attributes:
* [IWPM_NLA_MANAGE_MAPPING_SEQ]
* [IWPM_NLA_MANAGE_ADDR]
*/
int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
{
struct sk_buff *skb = NULL;
struct iwpm_nlmsg_request *nlmsg_request = NULL;
struct nlmsghdr *nlh;
u32 msg_seq;
const char *err_str = "";
int ret = -EINVAL;
if (!iwpm_valid_client(nl_client)) {
err_str = "Invalid port mapper client";
goto add_mapping_error;
}
if (!iwpm_registered_client(nl_client)) {
err_str = "Unregistered port mapper client";
goto add_mapping_error;
}
if (!iwpm_valid_pid())
return 0;
skb = iwpm_create_nlmsg(RDMA_NL_IWPM_ADD_MAPPING, &nlh, nl_client);
if (!skb) {
err_str = "Unable to create a nlmsg";
goto add_mapping_error;
}
nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
nlmsg_request = iwpm_get_nlmsg_request(nlh->nlmsg_seq, nl_client, GFP_KERNEL);
if (!nlmsg_request) {
err_str = "Unable to allocate netlink request";
goto add_mapping_error;
}
msg_seq = atomic_read(&echo_nlmsg_seq);
/* fill in the add mapping message */
err_str = "Unable to put attribute of the nlmsg";
ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq,
IWPM_NLA_MANAGE_MAPPING_SEQ);
if (ret)
goto add_mapping_error;
ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
&pm_msg->loc_addr, IWPM_NLA_MANAGE_ADDR);
if (ret)
goto add_mapping_error;
nlmsg_request->req_buffer = pm_msg;
ret = ibnl_unicast(skb, nlh, iwpm_user_pid);
if (ret) {
skb = NULL; /* skb is freed in the netlink send-op handling */
iwpm_user_pid = IWPM_PID_UNDEFINED;
err_str = "Unable to send a nlmsg";
goto add_mapping_error;
}
ret = iwpm_wait_complete_req(nlmsg_request);
return ret;
add_mapping_error:
pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client);
if (skb)
dev_kfree_skb(skb);
if (nlmsg_request)
iwpm_free_nlmsg_request(&nlmsg_request->kref);
return ret;
}
EXPORT_SYMBOL(iwpm_add_mapping);
/*
* iwpm_add_and_query_mapping - Send a netlink add and query
* mapping message to the port mapper
* nlmsg attributes:
* [IWPM_NLA_QUERY_MAPPING_SEQ]
* [IWPM_NLA_QUERY_LOCAL_ADDR]
* [IWPM_NLA_QUERY_REMOTE_ADDR]
*/
int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
{
struct sk_buff *skb = NULL;
struct iwpm_nlmsg_request *nlmsg_request = NULL;
struct nlmsghdr *nlh;
u32 msg_seq;
const char *err_str = "";
int ret = -EINVAL;
if (!iwpm_valid_client(nl_client)) {
err_str = "Invalid port mapper client";
goto query_mapping_error;
}
if (!iwpm_registered_client(nl_client)) {
err_str = "Unregistered port mapper client";
goto query_mapping_error;
}
if (!iwpm_valid_pid())
return 0;
ret = -ENOMEM;
skb = iwpm_create_nlmsg(RDMA_NL_IWPM_QUERY_MAPPING, &nlh, nl_client);
if (!skb) {
err_str = "Unable to create a nlmsg";
goto query_mapping_error;
}
nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
nlmsg_request = iwpm_get_nlmsg_request(nlh->nlmsg_seq,
nl_client, GFP_KERNEL);
if (!nlmsg_request) {
err_str = "Unable to allocate netlink request";
goto query_mapping_error;
}
msg_seq = atomic_read(&echo_nlmsg_seq);
/* fill in the query message */
err_str = "Unable to put attribute of the nlmsg";
ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq,
IWPM_NLA_QUERY_MAPPING_SEQ);
if (ret)
goto query_mapping_error;
ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
&pm_msg->loc_addr, IWPM_NLA_QUERY_LOCAL_ADDR);
if (ret)
goto query_mapping_error;
ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
&pm_msg->rem_addr, IWPM_NLA_QUERY_REMOTE_ADDR);
if (ret)
goto query_mapping_error;
nlmsg_request->req_buffer = pm_msg;
ret = ibnl_unicast(skb, nlh, iwpm_user_pid);
if (ret) {
skb = NULL; /* skb is freed in the netlink send-op handling */
err_str = "Unable to send a nlmsg";
goto query_mapping_error;
}
ret = iwpm_wait_complete_req(nlmsg_request);
return ret;
query_mapping_error:
pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client);
if (skb)
dev_kfree_skb(skb);
if (nlmsg_request)
iwpm_free_nlmsg_request(&nlmsg_request->kref);
return ret;
}
EXPORT_SYMBOL(iwpm_add_and_query_mapping);
/*
* iwpm_remove_mapping - Send a netlink remove mapping message
* to the port mapper
* nlmsg attributes:
* [IWPM_NLA_MANAGE_MAPPING_SEQ]
* [IWPM_NLA_MANAGE_ADDR]
*/
int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client)
{
struct sk_buff *skb = NULL;
struct nlmsghdr *nlh;
u32 msg_seq;
const char *err_str = "";
int ret = -EINVAL;
if (!iwpm_valid_client(nl_client)) {
err_str = "Invalid port mapper client";
goto remove_mapping_error;
}
if (!iwpm_registered_client(nl_client)) {
err_str = "Unregistered port mapper client";
goto remove_mapping_error;
}
if (!iwpm_valid_pid())
return 0;
skb = iwpm_create_nlmsg(RDMA_NL_IWPM_REMOVE_MAPPING, &nlh, nl_client);
if (!skb) {
ret = -ENOMEM;
err_str = "Unable to create a nlmsg";
goto remove_mapping_error;
}
msg_seq = atomic_read(&echo_nlmsg_seq);
nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
err_str = "Unable to put attribute of the nlmsg";
ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq,
IWPM_NLA_MANAGE_MAPPING_SEQ);
if (ret)
goto remove_mapping_error;
ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
local_addr, IWPM_NLA_MANAGE_ADDR);
if (ret)
goto remove_mapping_error;
ret = ibnl_unicast(skb, nlh, iwpm_user_pid);
if (ret) {
skb = NULL; /* skb is freed in the netlink send-op handling */
iwpm_user_pid = IWPM_PID_UNDEFINED;
err_str = "Unable to send a nlmsg";
goto remove_mapping_error;
}
iwpm_print_sockaddr(local_addr,
"remove_mapping: Local sockaddr:");
return 0;
remove_mapping_error:
pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client);
if (skb)
dev_kfree_skb_any(skb);
return ret;
}
EXPORT_SYMBOL(iwpm_remove_mapping);
/* netlink attribute policy for the received response to register pid request */
static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = {
[IWPM_NLA_RREG_PID_SEQ] = { .type = NLA_U32 },
[IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_STRING,
.len = IWPM_DEVNAME_SIZE - 1 },
[IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_STRING,
.len = IWPM_ULIBNAME_SIZE - 1 },
[IWPM_NLA_RREG_ULIB_VER] = { .type = NLA_U16 },
[IWPM_NLA_RREG_PID_ERR] = { .type = NLA_U16 }
};
/*
* iwpm_register_pid_cb - Process a port mapper response to
* iwpm_register_pid()
*/
int iwpm_register_pid_cb(struct sk_buff *skb, struct netlink_callback *cb)
{
struct iwpm_nlmsg_request *nlmsg_request = NULL;
struct nlattr *nltb[IWPM_NLA_RREG_PID_MAX];
struct iwpm_dev_data *pm_msg;
char *dev_name, *iwpm_name;
u32 msg_seq;
u8 nl_client;
u16 iwpm_version;
const char *msg_type = "Register Pid response";
if (iwpm_parse_nlmsg(cb, IWPM_NLA_RREG_PID_MAX,
resp_reg_policy, nltb, msg_type))
return -EINVAL;
msg_seq = nla_get_u32(nltb[IWPM_NLA_RREG_PID_SEQ]);
nlmsg_request = iwpm_find_nlmsg_request(msg_seq);
if (!nlmsg_request) {
pr_info("%s: Could not find a matching request (seq = %u)\n",
__func__, msg_seq);
return -EINVAL;
}
pm_msg = nlmsg_request->req_buffer;
nl_client = nlmsg_request->nl_client;
dev_name = (char *)nla_data(nltb[IWPM_NLA_RREG_IBDEV_NAME]);
iwpm_name = (char *)nla_data(nltb[IWPM_NLA_RREG_ULIB_NAME]);
iwpm_version = nla_get_u16(nltb[IWPM_NLA_RREG_ULIB_VER]);
/* check device name, ulib name and version */
if (strcmp(pm_msg->dev_name, dev_name) ||
strcmp(iwpm_ulib_name, iwpm_name) ||
iwpm_version != iwpm_ulib_version) {
pr_info("%s: Incorrect info (dev = %s name = %s version = %d)\n",
__func__, dev_name, iwpm_name, iwpm_version);
nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
goto register_pid_response_exit;
}
iwpm_user_pid = cb->nlh->nlmsg_pid;
atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
pr_debug("%s: iWarp Port Mapper (pid = %d) is available!\n",
__func__, iwpm_user_pid);
if (iwpm_valid_client(nl_client))
iwpm_set_registered(nl_client, 1);
register_pid_response_exit:
nlmsg_request->request_done = 1;
/* always for found nlmsg_request */
kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
barrier();
wake_up(&nlmsg_request->waitq);
return 0;
}
EXPORT_SYMBOL(iwpm_register_pid_cb);
/* netlink attribute policy for the received response to add mapping request */
static const struct nla_policy resp_add_policy[IWPM_NLA_RMANAGE_MAPPING_MAX] = {
[IWPM_NLA_MANAGE_MAPPING_SEQ] = { .type = NLA_U32 },
[IWPM_NLA_MANAGE_ADDR] = { .len = sizeof(struct sockaddr_storage) },
[IWPM_NLA_MANAGE_MAPPED_LOC_ADDR] = { .len = sizeof(struct sockaddr_storage) },
[IWPM_NLA_RMANAGE_MAPPING_ERR] = { .type = NLA_U16 }
};
/*
* iwpm_add_mapping_cb - Process a port mapper response to
* iwpm_add_mapping()
*/
int iwpm_add_mapping_cb(struct sk_buff *skb, struct netlink_callback *cb)
{
struct iwpm_sa_data *pm_msg;
struct iwpm_nlmsg_request *nlmsg_request = NULL;
struct nlattr *nltb[IWPM_NLA_RMANAGE_MAPPING_MAX];
struct sockaddr_storage *local_sockaddr;
struct sockaddr_storage *mapped_sockaddr;
const char *msg_type;
u32 msg_seq;
msg_type = "Add Mapping response";
if (iwpm_parse_nlmsg(cb, IWPM_NLA_RMANAGE_MAPPING_MAX,
resp_add_policy, nltb, msg_type))
return -EINVAL;
atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
msg_seq = nla_get_u32(nltb[IWPM_NLA_MANAGE_MAPPING_SEQ]);
nlmsg_request = iwpm_find_nlmsg_request(msg_seq);
if (!nlmsg_request) {
pr_info("%s: Could not find a matching request (seq = %u)\n",
__func__, msg_seq);
return -EINVAL;
}
pm_msg = nlmsg_request->req_buffer;
local_sockaddr = (struct sockaddr_storage *)
nla_data(nltb[IWPM_NLA_MANAGE_ADDR]);
mapped_sockaddr = (struct sockaddr_storage *)
nla_data(nltb[IWPM_NLA_MANAGE_MAPPED_LOC_ADDR]);
if (iwpm_compare_sockaddr(local_sockaddr, &pm_msg->loc_addr)) {
nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
goto add_mapping_response_exit;
}
if (mapped_sockaddr->ss_family != local_sockaddr->ss_family) {
pr_info("%s: Sockaddr family doesn't match the requested one\n",
__func__);
nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
goto add_mapping_response_exit;
}
memcpy(&pm_msg->mapped_loc_addr, mapped_sockaddr,
sizeof(*mapped_sockaddr));
iwpm_print_sockaddr(&pm_msg->loc_addr,
"add_mapping: Local sockaddr:");
iwpm_print_sockaddr(&pm_msg->mapped_loc_addr,
"add_mapping: Mapped local sockaddr:");
add_mapping_response_exit:
nlmsg_request->request_done = 1;
/* always for found request */
kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
barrier();
wake_up(&nlmsg_request->waitq);
return 0;
}
EXPORT_SYMBOL(iwpm_add_mapping_cb);
/* netlink attribute policy for the response to add and query mapping request */
static const struct nla_policy resp_query_policy[IWPM_NLA_RQUERY_MAPPING_MAX] = {
[IWPM_NLA_QUERY_MAPPING_SEQ] = { .type = NLA_U32 },
[IWPM_NLA_QUERY_LOCAL_ADDR] = { .len = sizeof(struct sockaddr_storage) },
[IWPM_NLA_QUERY_REMOTE_ADDR] = { .len = sizeof(struct sockaddr_storage) },
[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR] = { .len = sizeof(struct sockaddr_storage) },
[IWPM_NLA_RQUERY_MAPPED_REM_ADDR] = { .len = sizeof(struct sockaddr_storage) },
[IWPM_NLA_RQUERY_MAPPING_ERR] = { .type = NLA_U16 }
};
/*
* iwpm_add_and_query_mapping_cb - Process a port mapper response to
* iwpm_add_and_query_mapping()
*/
int iwpm_add_and_query_mapping_cb(struct sk_buff *skb,
struct netlink_callback *cb)
{
struct iwpm_sa_data *pm_msg;
struct iwpm_nlmsg_request *nlmsg_request = NULL;
struct nlattr *nltb[IWPM_NLA_RQUERY_MAPPING_MAX];
struct sockaddr_storage *local_sockaddr, *remote_sockaddr;
struct sockaddr_storage *mapped_loc_sockaddr, *mapped_rem_sockaddr;
const char *msg_type;
u32 msg_seq;
u16 err_code;
msg_type = "Query Mapping response";
if (iwpm_parse_nlmsg(cb, IWPM_NLA_RQUERY_MAPPING_MAX,
resp_query_policy, nltb, msg_type))
return -EINVAL;
atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
msg_seq = nla_get_u32(nltb[IWPM_NLA_QUERY_MAPPING_SEQ]);
nlmsg_request = iwpm_find_nlmsg_request(msg_seq);
if (!nlmsg_request) {
pr_info("%s: Could not find a matching request (seq = %u)\n",
__func__, msg_seq);
return -EINVAL;
}
pm_msg = nlmsg_request->req_buffer;
local_sockaddr = (struct sockaddr_storage *)
nla_data(nltb[IWPM_NLA_QUERY_LOCAL_ADDR]);
remote_sockaddr = (struct sockaddr_storage *)
nla_data(nltb[IWPM_NLA_QUERY_REMOTE_ADDR]);
mapped_loc_sockaddr = (struct sockaddr_storage *)
nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR]);
mapped_rem_sockaddr = (struct sockaddr_storage *)
nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_REM_ADDR]);
err_code = nla_get_u16(nltb[IWPM_NLA_RQUERY_MAPPING_ERR]);
if (err_code == IWPM_REMOTE_QUERY_REJECT) {
pr_info("%s: Received a Reject (pid = %u, echo seq = %u)\n",
__func__, cb->nlh->nlmsg_pid, msg_seq);
nlmsg_request->err_code = IWPM_REMOTE_QUERY_REJECT;
}
if (iwpm_compare_sockaddr(local_sockaddr, &pm_msg->loc_addr) ||
iwpm_compare_sockaddr(remote_sockaddr, &pm_msg->rem_addr)) {
pr_info("%s: Incorrect local sockaddr\n", __func__);
nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
goto query_mapping_response_exit;
}
if (mapped_loc_sockaddr->ss_family != local_sockaddr->ss_family ||
mapped_rem_sockaddr->ss_family != remote_sockaddr->ss_family) {
pr_info("%s: Sockaddr family doesn't match the requested one\n",
__func__);
nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
goto query_mapping_response_exit;
}
memcpy(&pm_msg->mapped_loc_addr, mapped_loc_sockaddr,
sizeof(*mapped_loc_sockaddr));
memcpy(&pm_msg->mapped_rem_addr, mapped_rem_sockaddr,
sizeof(*mapped_rem_sockaddr));
iwpm_print_sockaddr(&pm_msg->loc_addr,
"query_mapping: Local sockaddr:");
iwpm_print_sockaddr(&pm_msg->mapped_loc_addr,
"query_mapping: Mapped local sockaddr:");
iwpm_print_sockaddr(&pm_msg->rem_addr,
"query_mapping: Remote sockaddr:");
iwpm_print_sockaddr(&pm_msg->mapped_rem_addr,
"query_mapping: Mapped remote sockaddr:");
query_mapping_response_exit:
nlmsg_request->request_done = 1;
/* always for found request */
kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
barrier();
wake_up(&nlmsg_request->waitq);
return 0;
}
EXPORT_SYMBOL(iwpm_add_and_query_mapping_cb);
/* netlink attribute policy for the received request for mapping info */
static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = {
[IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING,
.len = IWPM_ULIBNAME_SIZE - 1 },
[IWPM_NLA_MAPINFO_ULIB_VER] = { .type = NLA_U16 }
};
/*
* iwpm_mapping_info_cb - Process a port mapper request for mapping info
*/
int iwpm_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
{
struct nlattr *nltb[IWPM_NLA_MAPINFO_REQ_MAX];
const char *msg_type = "Mapping Info response";
int iwpm_pid;
u8 nl_client;
char *iwpm_name;
u16 iwpm_version;
int ret = -EINVAL;
if (iwpm_parse_nlmsg(cb, IWPM_NLA_MAPINFO_REQ_MAX,
resp_mapinfo_policy, nltb, msg_type)) {
pr_info("%s: Unable to parse nlmsg\n", __func__);
return ret;
}
iwpm_name = (char *)nla_data(nltb[IWPM_NLA_MAPINFO_ULIB_NAME]);
iwpm_version = nla_get_u16(nltb[IWPM_NLA_MAPINFO_ULIB_VER]);
if (strcmp(iwpm_ulib_name, iwpm_name) ||
iwpm_version != iwpm_ulib_version) {
pr_info("%s: Invalid port mapper name = %s version = %d\n",
__func__, iwpm_name, iwpm_version);
return ret;
}
nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type);
if (!iwpm_valid_client(nl_client)) {
pr_info("%s: Invalid port mapper client = %d\n",
__func__, nl_client);
return ret;
}
iwpm_set_registered(nl_client, 0);
atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
if (!iwpm_mapinfo_available())
return 0;
iwpm_pid = cb->nlh->nlmsg_pid;
pr_debug("%s: iWarp Port Mapper (pid = %d) is available!\n",
__func__, iwpm_pid);
ret = iwpm_send_mapinfo(nl_client, iwpm_pid);
return ret;
}
EXPORT_SYMBOL(iwpm_mapping_info_cb);
/* netlink attribute policy for the received mapping info ack */
static const struct nla_policy ack_mapinfo_policy[IWPM_NLA_MAPINFO_NUM_MAX] = {
[IWPM_NLA_MAPINFO_SEQ] = { .type = NLA_U32 },
[IWPM_NLA_MAPINFO_SEND_NUM] = { .type = NLA_U32 },
[IWPM_NLA_MAPINFO_ACK_NUM] = { .type = NLA_U32 }
};
/*
* iwpm_ack_mapping_info_cb - Process a port mapper ack for
* the provided mapping info records
*/
int iwpm_ack_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
{
struct nlattr *nltb[IWPM_NLA_MAPINFO_NUM_MAX];
u32 mapinfo_send, mapinfo_ack;
const char *msg_type = "Mapping Info Ack";
if (iwpm_parse_nlmsg(cb, IWPM_NLA_MAPINFO_NUM_MAX,
ack_mapinfo_policy, nltb, msg_type))
return -EINVAL;
mapinfo_send = nla_get_u32(nltb[IWPM_NLA_MAPINFO_SEND_NUM]);
mapinfo_ack = nla_get_u32(nltb[IWPM_NLA_MAPINFO_ACK_NUM]);
if (mapinfo_ack != mapinfo_send)
pr_info("%s: Invalid mapinfo number (sent = %u ack-ed = %u)\n",
__func__, mapinfo_send, mapinfo_ack);
atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
return 0;
}
EXPORT_SYMBOL(iwpm_ack_mapping_info_cb);
/* netlink attribute policy for the received port mapper error message */
static const struct nla_policy map_error_policy[IWPM_NLA_ERR_MAX] = {
[IWPM_NLA_ERR_SEQ] = { .type = NLA_U32 },
[IWPM_NLA_ERR_CODE] = { .type = NLA_U16 },
};
/*
* iwpm_mapping_error_cb - Process a port mapper error message
*/
int iwpm_mapping_error_cb(struct sk_buff *skb, struct netlink_callback *cb)
{
struct iwpm_nlmsg_request *nlmsg_request = NULL;
int nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type);
struct nlattr *nltb[IWPM_NLA_ERR_MAX];
u32 msg_seq;
u16 err_code;
const char *msg_type = "Mapping Error Msg";
if (iwpm_parse_nlmsg(cb, IWPM_NLA_ERR_MAX,
map_error_policy, nltb, msg_type))
return -EINVAL;
msg_seq = nla_get_u32(nltb[IWPM_NLA_ERR_SEQ]);
err_code = nla_get_u16(nltb[IWPM_NLA_ERR_CODE]);
pr_info("%s: Received msg seq = %u err code = %u client = %d\n",
__func__, msg_seq, err_code, nl_client);
/* look for nlmsg_request */
nlmsg_request = iwpm_find_nlmsg_request(msg_seq);
if (!nlmsg_request) {
/* not all errors have associated requests */
pr_debug("Could not find matching req (seq = %u)\n", msg_seq);
return 0;
}
atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
nlmsg_request->err_code = err_code;
nlmsg_request->request_done = 1;
/* always for found request */
kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
barrier();
wake_up(&nlmsg_request->waitq);
return 0;
}
EXPORT_SYMBOL(iwpm_mapping_error_cb);

View file

@ -0,0 +1,607 @@
/*
* Copyright (c) 2014 Chelsio, Inc. All rights reserved.
* Copyright (c) 2014 Intel Corporation. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "iwpm_util.h"
#define IWPM_HASH_BUCKET_SIZE 512
#define IWPM_HASH_BUCKET_MASK (IWPM_HASH_BUCKET_SIZE - 1)
static LIST_HEAD(iwpm_nlmsg_req_list);
static DEFINE_SPINLOCK(iwpm_nlmsg_req_lock);
static struct hlist_head *iwpm_hash_bucket;
static DEFINE_SPINLOCK(iwpm_mapinfo_lock);
static DEFINE_MUTEX(iwpm_admin_lock);
static struct iwpm_admin_data iwpm_admin;
int iwpm_init(u8 nl_client)
{
if (iwpm_valid_client(nl_client))
return -EINVAL;
mutex_lock(&iwpm_admin_lock);
if (atomic_read(&iwpm_admin.refcount) == 0) {
iwpm_hash_bucket = kzalloc(IWPM_HASH_BUCKET_SIZE *
sizeof(struct hlist_head), GFP_KERNEL);
if (!iwpm_hash_bucket) {
mutex_unlock(&iwpm_admin_lock);
pr_err("%s Unable to create mapinfo hash table\n", __func__);
return -ENOMEM;
}
}
atomic_inc(&iwpm_admin.refcount);
mutex_unlock(&iwpm_admin_lock);
iwpm_set_valid(nl_client, 1);
return 0;
}
EXPORT_SYMBOL(iwpm_init);
static void free_hash_bucket(void);
int iwpm_exit(u8 nl_client)
{
if (!iwpm_valid_client(nl_client))
return -EINVAL;
mutex_lock(&iwpm_admin_lock);
if (atomic_read(&iwpm_admin.refcount) == 0) {
mutex_unlock(&iwpm_admin_lock);
pr_err("%s Incorrect usage - negative refcount\n", __func__);
return -EINVAL;
}
if (atomic_dec_and_test(&iwpm_admin.refcount)) {
free_hash_bucket();
pr_debug("%s: Mapinfo hash table is destroyed\n", __func__);
}
mutex_unlock(&iwpm_admin_lock);
iwpm_set_valid(nl_client, 0);
return 0;
}
EXPORT_SYMBOL(iwpm_exit);
static struct hlist_head *get_hash_bucket_head(struct sockaddr_storage *,
struct sockaddr_storage *);
int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr,
struct sockaddr_storage *mapped_sockaddr,
u8 nl_client)
{
struct hlist_head *hash_bucket_head;
struct iwpm_mapping_info *map_info;
unsigned long flags;
if (!iwpm_valid_client(nl_client))
return -EINVAL;
map_info = kzalloc(sizeof(struct iwpm_mapping_info), GFP_KERNEL);
if (!map_info) {
pr_err("%s: Unable to allocate a mapping info\n", __func__);
return -ENOMEM;
}
memcpy(&map_info->local_sockaddr, local_sockaddr,
sizeof(struct sockaddr_storage));
memcpy(&map_info->mapped_sockaddr, mapped_sockaddr,
sizeof(struct sockaddr_storage));
map_info->nl_client = nl_client;
spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
if (iwpm_hash_bucket) {
hash_bucket_head = get_hash_bucket_head(
&map_info->local_sockaddr,
&map_info->mapped_sockaddr);
hlist_add_head(&map_info->hlist_node, hash_bucket_head);
}
spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
return 0;
}
EXPORT_SYMBOL(iwpm_create_mapinfo);
int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr,
struct sockaddr_storage *mapped_local_addr)
{
struct hlist_node *tmp_hlist_node;
struct hlist_head *hash_bucket_head;
struct iwpm_mapping_info *map_info = NULL;
unsigned long flags;
int ret = -EINVAL;
spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
if (iwpm_hash_bucket) {
hash_bucket_head = get_hash_bucket_head(
local_sockaddr,
mapped_local_addr);
hlist_for_each_entry_safe(map_info, tmp_hlist_node,
hash_bucket_head, hlist_node) {
if (!iwpm_compare_sockaddr(&map_info->mapped_sockaddr,
mapped_local_addr)) {
hlist_del_init(&map_info->hlist_node);
kfree(map_info);
ret = 0;
break;
}
}
}
spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
return ret;
}
EXPORT_SYMBOL(iwpm_remove_mapinfo);
static void free_hash_bucket(void)
{
struct hlist_node *tmp_hlist_node;
struct iwpm_mapping_info *map_info;
unsigned long flags;
int i;
/* remove all the mapinfo data from the list */
spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) {
hlist_for_each_entry_safe(map_info, tmp_hlist_node,
&iwpm_hash_bucket[i], hlist_node) {
hlist_del_init(&map_info->hlist_node);
kfree(map_info);
}
}
/* free the hash list */
kfree(iwpm_hash_bucket);
iwpm_hash_bucket = NULL;
spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
}
struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq,
u8 nl_client, gfp_t gfp)
{
struct iwpm_nlmsg_request *nlmsg_request = NULL;
unsigned long flags;
nlmsg_request = kzalloc(sizeof(struct iwpm_nlmsg_request), gfp);
if (!nlmsg_request) {
pr_err("%s Unable to allocate a nlmsg_request\n", __func__);
return NULL;
}
spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
list_add_tail(&nlmsg_request->inprocess_list, &iwpm_nlmsg_req_list);
spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
kref_init(&nlmsg_request->kref);
kref_get(&nlmsg_request->kref);
nlmsg_request->nlmsg_seq = nlmsg_seq;
nlmsg_request->nl_client = nl_client;
nlmsg_request->request_done = 0;
nlmsg_request->err_code = 0;
return nlmsg_request;
}
void iwpm_free_nlmsg_request(struct kref *kref)
{
struct iwpm_nlmsg_request *nlmsg_request;
unsigned long flags;
nlmsg_request = container_of(kref, struct iwpm_nlmsg_request, kref);
spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
list_del_init(&nlmsg_request->inprocess_list);
spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
if (!nlmsg_request->request_done)
pr_debug("%s Freeing incomplete nlmsg request (seq = %u).\n",
__func__, nlmsg_request->nlmsg_seq);
kfree(nlmsg_request);
}
struct iwpm_nlmsg_request *iwpm_find_nlmsg_request(__u32 echo_seq)
{
struct iwpm_nlmsg_request *nlmsg_request;
struct iwpm_nlmsg_request *found_request = NULL;
unsigned long flags;
spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
list_for_each_entry(nlmsg_request, &iwpm_nlmsg_req_list,
inprocess_list) {
if (nlmsg_request->nlmsg_seq == echo_seq) {
found_request = nlmsg_request;
kref_get(&nlmsg_request->kref);
break;
}
}
spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
return found_request;
}
int iwpm_wait_complete_req(struct iwpm_nlmsg_request *nlmsg_request)
{
int ret;
init_waitqueue_head(&nlmsg_request->waitq);
ret = wait_event_timeout(nlmsg_request->waitq,
(nlmsg_request->request_done != 0), IWPM_NL_TIMEOUT);
if (!ret) {
ret = -EINVAL;
pr_info("%s: Timeout %d sec for netlink request (seq = %u)\n",
__func__, (IWPM_NL_TIMEOUT/HZ), nlmsg_request->nlmsg_seq);
} else {
ret = nlmsg_request->err_code;
}
kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
return ret;
}
int iwpm_get_nlmsg_seq(void)
{
return atomic_inc_return(&iwpm_admin.nlmsg_seq);
}
int iwpm_valid_client(u8 nl_client)
{
if (nl_client >= RDMA_NL_NUM_CLIENTS)
return 0;
return iwpm_admin.client_list[nl_client];
}
void iwpm_set_valid(u8 nl_client, int valid)
{
if (nl_client >= RDMA_NL_NUM_CLIENTS)
return;
iwpm_admin.client_list[nl_client] = valid;
}
/* valid client */
int iwpm_registered_client(u8 nl_client)
{
return iwpm_admin.reg_list[nl_client];
}
/* valid client */
void iwpm_set_registered(u8 nl_client, int reg)
{
iwpm_admin.reg_list[nl_client] = reg;
}
int iwpm_compare_sockaddr(struct sockaddr_storage *a_sockaddr,
struct sockaddr_storage *b_sockaddr)
{
if (a_sockaddr->ss_family != b_sockaddr->ss_family)
return 1;
if (a_sockaddr->ss_family == AF_INET) {
struct sockaddr_in *a4_sockaddr =
(struct sockaddr_in *)a_sockaddr;
struct sockaddr_in *b4_sockaddr =
(struct sockaddr_in *)b_sockaddr;
if (!memcmp(&a4_sockaddr->sin_addr,
&b4_sockaddr->sin_addr, sizeof(struct in_addr))
&& a4_sockaddr->sin_port == b4_sockaddr->sin_port)
return 0;
} else if (a_sockaddr->ss_family == AF_INET6) {
struct sockaddr_in6 *a6_sockaddr =
(struct sockaddr_in6 *)a_sockaddr;
struct sockaddr_in6 *b6_sockaddr =
(struct sockaddr_in6 *)b_sockaddr;
if (!memcmp(&a6_sockaddr->sin6_addr,
&b6_sockaddr->sin6_addr, sizeof(struct in6_addr))
&& a6_sockaddr->sin6_port == b6_sockaddr->sin6_port)
return 0;
} else {
pr_err("%s: Invalid sockaddr family\n", __func__);
}
return 1;
}
struct sk_buff *iwpm_create_nlmsg(u32 nl_op, struct nlmsghdr **nlh,
int nl_client)
{
struct sk_buff *skb = NULL;
skb = dev_alloc_skb(NLMSG_GOODSIZE);
if (!skb) {
pr_err("%s Unable to allocate skb\n", __func__);
goto create_nlmsg_exit;
}
if (!(ibnl_put_msg(skb, nlh, 0, 0, nl_client, nl_op,
NLM_F_REQUEST))) {
pr_warn("%s: Unable to put the nlmsg header\n", __func__);
dev_kfree_skb(skb);
skb = NULL;
}
create_nlmsg_exit:
return skb;
}
int iwpm_parse_nlmsg(struct netlink_callback *cb, int policy_max,
const struct nla_policy *nlmsg_policy,
struct nlattr *nltb[], const char *msg_type)
{
int nlh_len = 0;
int ret;
const char *err_str = "";
ret = nlmsg_validate(cb->nlh, nlh_len, policy_max-1, nlmsg_policy);
if (ret) {
err_str = "Invalid attribute";
goto parse_nlmsg_error;
}
ret = nlmsg_parse(cb->nlh, nlh_len, nltb, policy_max-1, nlmsg_policy);
if (ret) {
err_str = "Unable to parse the nlmsg";
goto parse_nlmsg_error;
}
ret = iwpm_validate_nlmsg_attr(nltb, policy_max);
if (ret) {
err_str = "Invalid NULL attribute";
goto parse_nlmsg_error;
}
return 0;
parse_nlmsg_error:
pr_warn("%s: %s (msg type %s ret = %d)\n",
__func__, err_str, msg_type, ret);
return ret;
}
void iwpm_print_sockaddr(struct sockaddr_storage *sockaddr, char *msg)
{
struct sockaddr_in6 *sockaddr_v6;
struct sockaddr_in *sockaddr_v4;
switch (sockaddr->ss_family) {
case AF_INET:
sockaddr_v4 = (struct sockaddr_in *)sockaddr;
pr_debug("%s IPV4 %pI4: %u(0x%04X)\n",
msg, &sockaddr_v4->sin_addr,
ntohs(sockaddr_v4->sin_port),
ntohs(sockaddr_v4->sin_port));
break;
case AF_INET6:
sockaddr_v6 = (struct sockaddr_in6 *)sockaddr;
pr_debug("%s IPV6 %pI6: %u(0x%04X)\n",
msg, &sockaddr_v6->sin6_addr,
ntohs(sockaddr_v6->sin6_port),
ntohs(sockaddr_v6->sin6_port));
break;
default:
break;
}
}
static u32 iwpm_ipv6_jhash(struct sockaddr_in6 *ipv6_sockaddr)
{
u32 ipv6_hash = jhash(&ipv6_sockaddr->sin6_addr, sizeof(struct in6_addr), 0);
u32 hash = jhash_2words(ipv6_hash, (__force u32) ipv6_sockaddr->sin6_port, 0);
return hash;
}
static u32 iwpm_ipv4_jhash(struct sockaddr_in *ipv4_sockaddr)
{
u32 ipv4_hash = jhash(&ipv4_sockaddr->sin_addr, sizeof(struct in_addr), 0);
u32 hash = jhash_2words(ipv4_hash, (__force u32) ipv4_sockaddr->sin_port, 0);
return hash;
}
static struct hlist_head *get_hash_bucket_head(struct sockaddr_storage
*local_sockaddr,
struct sockaddr_storage
*mapped_sockaddr)
{
u32 local_hash, mapped_hash, hash;
if (local_sockaddr->ss_family == AF_INET) {
local_hash = iwpm_ipv4_jhash((struct sockaddr_in *) local_sockaddr);
mapped_hash = iwpm_ipv4_jhash((struct sockaddr_in *) mapped_sockaddr);
} else if (local_sockaddr->ss_family == AF_INET6) {
local_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) local_sockaddr);
mapped_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) mapped_sockaddr);
} else {
pr_err("%s: Invalid sockaddr family\n", __func__);
return NULL;
}
if (local_hash == mapped_hash) /* if port mapper isn't available */
hash = local_hash;
else
hash = jhash_2words(local_hash, mapped_hash, 0);
return &iwpm_hash_bucket[hash & IWPM_HASH_BUCKET_MASK];
}
static int send_mapinfo_num(u32 mapping_num, u8 nl_client, int iwpm_pid)
{
struct sk_buff *skb = NULL;
struct nlmsghdr *nlh;
u32 msg_seq;
const char *err_str = "";
int ret = -EINVAL;
skb = iwpm_create_nlmsg(RDMA_NL_IWPM_MAPINFO_NUM, &nlh, nl_client);
if (!skb) {
err_str = "Unable to create a nlmsg";
goto mapinfo_num_error;
}
nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
msg_seq = 0;
err_str = "Unable to put attribute of mapinfo number nlmsg";
ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, IWPM_NLA_MAPINFO_SEQ);
if (ret)
goto mapinfo_num_error;
ret = ibnl_put_attr(skb, nlh, sizeof(u32),
&mapping_num, IWPM_NLA_MAPINFO_SEND_NUM);
if (ret)
goto mapinfo_num_error;
ret = ibnl_unicast(skb, nlh, iwpm_pid);
if (ret) {
skb = NULL;
err_str = "Unable to send a nlmsg";
goto mapinfo_num_error;
}
pr_debug("%s: Sent mapping number = %d\n", __func__, mapping_num);
return 0;
mapinfo_num_error:
pr_info("%s: %s\n", __func__, err_str);
if (skb)
dev_kfree_skb(skb);
return ret;
}
static int send_nlmsg_done(struct sk_buff *skb, u8 nl_client, int iwpm_pid)
{
struct nlmsghdr *nlh = NULL;
int ret = 0;
if (!skb)
return ret;
if (!(ibnl_put_msg(skb, &nlh, 0, 0, nl_client,
RDMA_NL_IWPM_MAPINFO, NLM_F_MULTI))) {
pr_warn("%s Unable to put NLMSG_DONE\n", __func__);
return -ENOMEM;
}
nlh->nlmsg_type = NLMSG_DONE;
ret = ibnl_unicast(skb, (struct nlmsghdr *)skb->data, iwpm_pid);
if (ret)
pr_warn("%s Unable to send a nlmsg\n", __func__);
return ret;
}
int iwpm_send_mapinfo(u8 nl_client, int iwpm_pid)
{
struct iwpm_mapping_info *map_info;
struct sk_buff *skb = NULL;
struct nlmsghdr *nlh;
int skb_num = 0, mapping_num = 0;
int i = 0, nlmsg_bytes = 0;
unsigned long flags;
const char *err_str = "";
int ret;
skb = dev_alloc_skb(NLMSG_GOODSIZE);
if (!skb) {
ret = -ENOMEM;
err_str = "Unable to allocate skb";
goto send_mapping_info_exit;
}
skb_num++;
spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) {
hlist_for_each_entry(map_info, &iwpm_hash_bucket[i],
hlist_node) {
if (map_info->nl_client != nl_client)
continue;
nlh = NULL;
if (!(ibnl_put_msg(skb, &nlh, 0, 0, nl_client,
RDMA_NL_IWPM_MAPINFO, NLM_F_MULTI))) {
ret = -ENOMEM;
err_str = "Unable to put the nlmsg header";
goto send_mapping_info_unlock;
}
err_str = "Unable to put attribute of the nlmsg";
ret = ibnl_put_attr(skb, nlh,
sizeof(struct sockaddr_storage),
&map_info->local_sockaddr,
IWPM_NLA_MAPINFO_LOCAL_ADDR);
if (ret)
goto send_mapping_info_unlock;
ret = ibnl_put_attr(skb, nlh,
sizeof(struct sockaddr_storage),
&map_info->mapped_sockaddr,
IWPM_NLA_MAPINFO_MAPPED_ADDR);
if (ret)
goto send_mapping_info_unlock;
iwpm_print_sockaddr(&map_info->local_sockaddr,
"send_mapping_info: Local sockaddr:");
iwpm_print_sockaddr(&map_info->mapped_sockaddr,
"send_mapping_info: Mapped local sockaddr:");
mapping_num++;
nlmsg_bytes += nlh->nlmsg_len;
/* check if all mappings can fit in one skb */
if (NLMSG_GOODSIZE - nlmsg_bytes < nlh->nlmsg_len * 2) {
/* and leave room for NLMSG_DONE */
nlmsg_bytes = 0;
skb_num++;
spin_unlock_irqrestore(&iwpm_mapinfo_lock,
flags);
/* send the skb */
ret = send_nlmsg_done(skb, nl_client, iwpm_pid);
skb = NULL;
if (ret) {
err_str = "Unable to send map info";
goto send_mapping_info_exit;
}
if (skb_num == IWPM_MAPINFO_SKB_COUNT) {
ret = -ENOMEM;
err_str = "Insufficient skbs for map info";
goto send_mapping_info_exit;
}
skb = dev_alloc_skb(NLMSG_GOODSIZE);
if (!skb) {
ret = -ENOMEM;
err_str = "Unable to allocate skb";
goto send_mapping_info_exit;
}
spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
}
}
}
send_mapping_info_unlock:
spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
send_mapping_info_exit:
if (ret) {
pr_warn("%s: %s (ret = %d)\n", __func__, err_str, ret);
if (skb)
dev_kfree_skb(skb);
return ret;
}
send_nlmsg_done(skb, nl_client, iwpm_pid);
return send_mapinfo_num(mapping_num, nl_client, iwpm_pid);
}
int iwpm_mapinfo_available(void)
{
unsigned long flags;
int full_bucket = 0, i = 0;
spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
if (iwpm_hash_bucket) {
for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) {
if (!hlist_empty(&iwpm_hash_bucket[i])) {
full_bucket = 1;
break;
}
}
}
spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
return full_bucket;
}

View file

@ -0,0 +1,238 @@
/*
* Copyright (c) 2014 Intel Corporation. All rights reserved.
* Copyright (c) 2014 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _IWPM_UTIL_H
#define _IWPM_UTIL_H
#include <linux/module.h>
#include <linux/io.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/spinlock.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <linux/jhash.h>
#include <linux/kref.h>
#include <net/netlink.h>
#include <linux/errno.h>
#include <rdma/iw_portmap.h>
#include <rdma/rdma_netlink.h>
#define IWPM_NL_RETRANS 3
#define IWPM_NL_TIMEOUT (10*HZ)
#define IWPM_MAPINFO_SKB_COUNT 20
#define IWPM_PID_UNDEFINED -1
#define IWPM_PID_UNAVAILABLE -2
struct iwpm_nlmsg_request {
struct list_head inprocess_list;
__u32 nlmsg_seq;
void *req_buffer;
u8 nl_client;
u8 request_done;
u16 err_code;
wait_queue_head_t waitq;
struct kref kref;
};
struct iwpm_mapping_info {
struct hlist_node hlist_node;
struct sockaddr_storage local_sockaddr;
struct sockaddr_storage mapped_sockaddr;
u8 nl_client;
};
struct iwpm_admin_data {
atomic_t refcount;
atomic_t nlmsg_seq;
int client_list[RDMA_NL_NUM_CLIENTS];
int reg_list[RDMA_NL_NUM_CLIENTS];
};
/**
* iwpm_get_nlmsg_request - Allocate and initialize netlink message request
* @nlmsg_seq: Sequence number of the netlink message
* @nl_client: The index of the netlink client
* @gfp: Indicates how the memory for the request should be allocated
*
* Returns the newly allocated netlink request object if successful,
* otherwise returns NULL
*/
struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq,
u8 nl_client, gfp_t gfp);
/**
* iwpm_free_nlmsg_request - Deallocate netlink message request
* @kref: Holds reference of netlink message request
*/
void iwpm_free_nlmsg_request(struct kref *kref);
/**
* iwpm_find_nlmsg_request - Find netlink message request in the request list
* @echo_seq: Sequence number of the netlink request to find
*
* Returns the found netlink message request,
* if not found, returns NULL
*/
struct iwpm_nlmsg_request *iwpm_find_nlmsg_request(__u32 echo_seq);
/**
* iwpm_wait_complete_req - Block while servicing the netlink request
* @nlmsg_request: Netlink message request to service
*
* Wakes up, after the request is completed or expired
* Returns 0 if the request is complete without error
*/
int iwpm_wait_complete_req(struct iwpm_nlmsg_request *nlmsg_request);
/**
* iwpm_get_nlmsg_seq - Get the sequence number for a netlink
* message to send to the port mapper
*
* Returns the sequence number for the netlink message.
*/
int iwpm_get_nlmsg_seq(void);
/**
* iwpm_valid_client - Check if the port mapper client is valid
* @nl_client: The index of the netlink client
*
* Valid clients need to call iwpm_init() before using
* the port mapper
*/
int iwpm_valid_client(u8 nl_client);
/**
* iwpm_set_valid - Set the port mapper client to valid or not
* @nl_client: The index of the netlink client
* @valid: 1 if valid or 0 if invalid
*/
void iwpm_set_valid(u8 nl_client, int valid);
/**
* iwpm_registered_client - Check if the port mapper client is registered
* @nl_client: The index of the netlink client
*
* Call iwpm_register_pid() to register a client
*/
int iwpm_registered_client(u8 nl_client);
/**
* iwpm_set_registered - Set the port mapper client to registered or not
* @nl_client: The index of the netlink client
* @reg: 1 if registered or 0 if not
*/
void iwpm_set_registered(u8 nl_client, int reg);
/**
* iwpm_send_mapinfo - Send local and mapped IPv4/IPv6 address info of
* a client to the user space port mapper
* @nl_client: The index of the netlink client
* @iwpm_pid: The pid of the user space port mapper
*
* If successful, returns the number of sent mapping info records
*/
int iwpm_send_mapinfo(u8 nl_client, int iwpm_pid);
/**
* iwpm_mapinfo_available - Check if any mapping info records is available
* in the hash table
*
* Returns 1 if mapping information is available, otherwise returns 0
*/
int iwpm_mapinfo_available(void);
/**
* iwpm_compare_sockaddr - Compare two sockaddr storage structs
*
* Returns 0 if they are holding the same ip/tcp address info,
* otherwise returns 1
*/
int iwpm_compare_sockaddr(struct sockaddr_storage *a_sockaddr,
struct sockaddr_storage *b_sockaddr);
/**
* iwpm_validate_nlmsg_attr - Check for NULL netlink attributes
* @nltb: Holds address of each netlink message attributes
* @nla_count: Number of netlink message attributes
*
* Returns error if any of the nla_count attributes is NULL
*/
static inline int iwpm_validate_nlmsg_attr(struct nlattr *nltb[],
int nla_count)
{
int i;
for (i = 1; i < nla_count; i++) {
if (!nltb[i])
return -EINVAL;
}
return 0;
}
/**
* iwpm_create_nlmsg - Allocate skb and form a netlink message
* @nl_op: Netlink message opcode
* @nlh: Holds address of the netlink message header in skb
* @nl_client: The index of the netlink client
*
* Returns the newly allcated skb, or NULL if the tailroom of the skb
* is insufficient to store the message header and payload
*/
struct sk_buff *iwpm_create_nlmsg(u32 nl_op, struct nlmsghdr **nlh,
int nl_client);
/**
* iwpm_parse_nlmsg - Validate and parse the received netlink message
* @cb: Netlink callback structure
* @policy_max: Maximum attribute type to be expected
* @nlmsg_policy: Validation policy
* @nltb: Array to store policy_max parsed elements
* @msg_type: Type of netlink message
*
* Returns 0 on success or a negative error code
*/
int iwpm_parse_nlmsg(struct netlink_callback *cb, int policy_max,
const struct nla_policy *nlmsg_policy,
struct nlattr *nltb[], const char *msg_type);
/**
* iwpm_print_sockaddr - Print IPv4/IPv6 address and TCP port
* @sockaddr: Socket address to print
* @msg: Message to print
*/
void iwpm_print_sockaddr(struct sockaddr_storage *sockaddr, char *msg);
#endif

View file

@ -103,13 +103,13 @@ int ibnl_remove_client(int index)
EXPORT_SYMBOL(ibnl_remove_client); EXPORT_SYMBOL(ibnl_remove_client);
void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq, void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq,
int len, int client, int op) int len, int client, int op, int flags)
{ {
unsigned char *prev_tail; unsigned char *prev_tail;
prev_tail = skb_tail_pointer(skb); prev_tail = skb_tail_pointer(skb);
*nlh = nlmsg_put(skb, 0, seq, RDMA_NL_GET_TYPE(client, op), *nlh = nlmsg_put(skb, 0, seq, RDMA_NL_GET_TYPE(client, op),
len, NLM_F_MULTI); len, flags);
if (!*nlh) if (!*nlh)
goto out_nlmsg_trim; goto out_nlmsg_trim;
(*nlh)->nlmsg_len = skb_tail_pointer(skb) - prev_tail; (*nlh)->nlmsg_len = skb_tail_pointer(skb) - prev_tail;
@ -172,6 +172,20 @@ static void ibnl_rcv(struct sk_buff *skb)
mutex_unlock(&ibnl_mutex); mutex_unlock(&ibnl_mutex);
} }
int ibnl_unicast(struct sk_buff *skb, struct nlmsghdr *nlh,
__u32 pid)
{
return nlmsg_unicast(nls, skb, pid);
}
EXPORT_SYMBOL(ibnl_unicast);
int ibnl_multicast(struct sk_buff *skb, struct nlmsghdr *nlh,
unsigned int group, gfp_t flags)
{
return nlmsg_multicast(nls, skb, 0, group, flags);
}
EXPORT_SYMBOL(ibnl_multicast);
int __init ibnl_init(void) int __init ibnl_init(void)
{ {
struct netlink_kernel_cfg cfg = { struct netlink_kernel_cfg cfg = {

View file

@ -618,7 +618,7 @@ static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent)
static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask) static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask)
{ {
bool preload = gfp_mask & __GFP_WAIT; bool preload = !!(gfp_mask & __GFP_WAIT);
unsigned long flags; unsigned long flags;
int ret, id; int ret, id;

View file

@ -429,15 +429,19 @@ static void ib_port_release(struct kobject *kobj)
struct attribute *a; struct attribute *a;
int i; int i;
for (i = 0; (a = p->gid_group.attrs[i]); ++i) if (p->gid_group.attrs) {
kfree(a); for (i = 0; (a = p->gid_group.attrs[i]); ++i)
kfree(a);
kfree(p->gid_group.attrs); kfree(p->gid_group.attrs);
}
for (i = 0; (a = p->pkey_group.attrs[i]); ++i) if (p->pkey_group.attrs) {
kfree(a); for (i = 0; (a = p->pkey_group.attrs[i]); ++i)
kfree(a);
kfree(p->pkey_group.attrs); kfree(p->pkey_group.attrs);
}
kfree(p); kfree(p);
} }
@ -534,10 +538,12 @@ static int add_port(struct ib_device *device, int port_num,
p->port_num = port_num; p->port_num = port_num;
ret = kobject_init_and_add(&p->kobj, &port_type, ret = kobject_init_and_add(&p->kobj, &port_type,
kobject_get(device->ports_parent), device->ports_parent,
"%d", port_num); "%d", port_num);
if (ret) if (ret) {
goto err_put; kfree(p);
return ret;
}
ret = sysfs_create_group(&p->kobj, &pma_group); ret = sysfs_create_group(&p->kobj, &pma_group);
if (ret) if (ret)
@ -585,6 +591,7 @@ err_free_pkey:
kfree(p->pkey_group.attrs[i]); kfree(p->pkey_group.attrs[i]);
kfree(p->pkey_group.attrs); kfree(p->pkey_group.attrs);
p->pkey_group.attrs = NULL;
err_remove_gid: err_remove_gid:
sysfs_remove_group(&p->kobj, &p->gid_group); sysfs_remove_group(&p->kobj, &p->gid_group);
@ -594,13 +601,13 @@ err_free_gid:
kfree(p->gid_group.attrs[i]); kfree(p->gid_group.attrs[i]);
kfree(p->gid_group.attrs); kfree(p->gid_group.attrs);
p->gid_group.attrs = NULL;
err_remove_pma: err_remove_pma:
sysfs_remove_group(&p->kobj, &pma_group); sysfs_remove_group(&p->kobj, &pma_group);
err_put: err_put:
kobject_put(device->ports_parent); kobject_put(&p->kobj);
kfree(p);
return ret; return ret;
} }
@ -809,6 +816,22 @@ static struct attribute_group iw_stats_group = {
.attrs = iw_proto_stats_attrs, .attrs = iw_proto_stats_attrs,
}; };
static void free_port_list_attributes(struct ib_device *device)
{
struct kobject *p, *t;
list_for_each_entry_safe(p, t, &device->port_list, entry) {
struct ib_port *port = container_of(p, struct ib_port, kobj);
list_del(&p->entry);
sysfs_remove_group(p, &pma_group);
sysfs_remove_group(p, &port->pkey_group);
sysfs_remove_group(p, &port->gid_group);
kobject_put(p);
}
kobject_put(device->ports_parent);
}
int ib_device_register_sysfs(struct ib_device *device, int ib_device_register_sysfs(struct ib_device *device,
int (*port_callback)(struct ib_device *, int (*port_callback)(struct ib_device *,
u8, struct kobject *)) u8, struct kobject *))
@ -835,7 +858,7 @@ int ib_device_register_sysfs(struct ib_device *device,
} }
device->ports_parent = kobject_create_and_add("ports", device->ports_parent = kobject_create_and_add("ports",
kobject_get(&class_dev->kobj)); &class_dev->kobj);
if (!device->ports_parent) { if (!device->ports_parent) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_put; goto err_put;
@ -862,21 +885,7 @@ int ib_device_register_sysfs(struct ib_device *device,
return 0; return 0;
err_put: err_put:
{ free_port_list_attributes(device);
struct kobject *p, *t;
struct ib_port *port;
list_for_each_entry_safe(p, t, &device->port_list, entry) {
list_del(&p->entry);
port = container_of(p, struct ib_port, kobj);
sysfs_remove_group(p, &pma_group);
sysfs_remove_group(p, &port->pkey_group);
sysfs_remove_group(p, &port->gid_group);
kobject_put(p);
}
}
kobject_put(&class_dev->kobj);
err_unregister: err_unregister:
device_unregister(class_dev); device_unregister(class_dev);
@ -887,22 +896,18 @@ err:
void ib_device_unregister_sysfs(struct ib_device *device) void ib_device_unregister_sysfs(struct ib_device *device)
{ {
struct kobject *p, *t;
struct ib_port *port;
/* Hold kobject until ib_dealloc_device() */ /* Hold kobject until ib_dealloc_device() */
kobject_get(&device->dev.kobj); struct kobject *kobj_dev = kobject_get(&device->dev.kobj);
int i;
list_for_each_entry_safe(p, t, &device->port_list, entry) { if (device->node_type == RDMA_NODE_RNIC && device->get_protocol_stats)
list_del(&p->entry); sysfs_remove_group(kobj_dev, &iw_stats_group);
port = container_of(p, struct ib_port, kobj);
sysfs_remove_group(p, &pma_group); free_port_list_attributes(device);
sysfs_remove_group(p, &port->pkey_group);
sysfs_remove_group(p, &port->gid_group); for (i = 0; i < ARRAY_SIZE(ib_class_attributes); ++i)
kobject_put(p); device_remove_file(&device->dev, ib_class_attributes[i]);
}
kobject_put(device->ports_parent);
device_unregister(&device->dev); device_unregister(&device->dev);
} }

View file

@ -98,7 +98,7 @@ struct ib_umad_port {
struct ib_umad_device { struct ib_umad_device {
int start_port, end_port; int start_port, end_port;
struct kref ref; struct kobject kobj;
struct ib_umad_port port[0]; struct ib_umad_port port[0];
}; };
@ -134,14 +134,18 @@ static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS);
static void ib_umad_add_one(struct ib_device *device); static void ib_umad_add_one(struct ib_device *device);
static void ib_umad_remove_one(struct ib_device *device); static void ib_umad_remove_one(struct ib_device *device);
static void ib_umad_release_dev(struct kref *ref) static void ib_umad_release_dev(struct kobject *kobj)
{ {
struct ib_umad_device *dev = struct ib_umad_device *dev =
container_of(ref, struct ib_umad_device, ref); container_of(kobj, struct ib_umad_device, kobj);
kfree(dev); kfree(dev);
} }
static struct kobj_type ib_umad_dev_ktype = {
.release = ib_umad_release_dev,
};
static int hdr_size(struct ib_umad_file *file) static int hdr_size(struct ib_umad_file *file)
{ {
return file->use_pkey_index ? sizeof (struct ib_user_mad_hdr) : return file->use_pkey_index ? sizeof (struct ib_user_mad_hdr) :
@ -780,27 +784,19 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
{ {
struct ib_umad_port *port; struct ib_umad_port *port;
struct ib_umad_file *file; struct ib_umad_file *file;
int ret; int ret = -ENXIO;
port = container_of(inode->i_cdev, struct ib_umad_port, cdev); port = container_of(inode->i_cdev, struct ib_umad_port, cdev);
if (port)
kref_get(&port->umad_dev->ref);
else
return -ENXIO;
mutex_lock(&port->file_mutex); mutex_lock(&port->file_mutex);
if (!port->ib_dev) { if (!port->ib_dev)
ret = -ENXIO;
goto out; goto out;
}
ret = -ENOMEM;
file = kzalloc(sizeof *file, GFP_KERNEL); file = kzalloc(sizeof *file, GFP_KERNEL);
if (!file) { if (!file)
kref_put(&port->umad_dev->ref, ib_umad_release_dev);
ret = -ENOMEM;
goto out; goto out;
}
mutex_init(&file->mutex); mutex_init(&file->mutex);
spin_lock_init(&file->send_lock); spin_lock_init(&file->send_lock);
@ -814,6 +810,13 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
list_add_tail(&file->port_list, &port->file_list); list_add_tail(&file->port_list, &port->file_list);
ret = nonseekable_open(inode, filp); ret = nonseekable_open(inode, filp);
if (ret) {
list_del(&file->port_list);
kfree(file);
goto out;
}
kobject_get(&port->umad_dev->kobj);
out: out:
mutex_unlock(&port->file_mutex); mutex_unlock(&port->file_mutex);
@ -852,7 +855,7 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
mutex_unlock(&file->port->file_mutex); mutex_unlock(&file->port->file_mutex);
kfree(file); kfree(file);
kref_put(&dev->ref, ib_umad_release_dev); kobject_put(&dev->kobj);
return 0; return 0;
} }
@ -880,10 +883,6 @@ static int ib_umad_sm_open(struct inode *inode, struct file *filp)
int ret; int ret;
port = container_of(inode->i_cdev, struct ib_umad_port, sm_cdev); port = container_of(inode->i_cdev, struct ib_umad_port, sm_cdev);
if (port)
kref_get(&port->umad_dev->ref);
else
return -ENXIO;
if (filp->f_flags & O_NONBLOCK) { if (filp->f_flags & O_NONBLOCK) {
if (down_trylock(&port->sm_sem)) { if (down_trylock(&port->sm_sem)) {
@ -898,17 +897,27 @@ static int ib_umad_sm_open(struct inode *inode, struct file *filp)
} }
ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props); ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
if (ret) { if (ret)
up(&port->sm_sem); goto err_up_sem;
goto fail;
}
filp->private_data = port; filp->private_data = port;
return nonseekable_open(inode, filp); ret = nonseekable_open(inode, filp);
if (ret)
goto err_clr_sm_cap;
kobject_get(&port->umad_dev->kobj);
return 0;
err_clr_sm_cap:
swap(props.set_port_cap_mask, props.clr_port_cap_mask);
ib_modify_port(port->ib_dev, port->port_num, 0, &props);
err_up_sem:
up(&port->sm_sem);
fail: fail:
kref_put(&port->umad_dev->ref, ib_umad_release_dev);
return ret; return ret;
} }
@ -927,7 +936,7 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp)
up(&port->sm_sem); up(&port->sm_sem);
kref_put(&port->umad_dev->ref, ib_umad_release_dev); kobject_put(&port->umad_dev->kobj);
return ret; return ret;
} }
@ -995,6 +1004,7 @@ static int find_overflow_devnum(void)
} }
static int ib_umad_init_port(struct ib_device *device, int port_num, static int ib_umad_init_port(struct ib_device *device, int port_num,
struct ib_umad_device *umad_dev,
struct ib_umad_port *port) struct ib_umad_port *port)
{ {
int devnum; int devnum;
@ -1027,6 +1037,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
cdev_init(&port->cdev, &umad_fops); cdev_init(&port->cdev, &umad_fops);
port->cdev.owner = THIS_MODULE; port->cdev.owner = THIS_MODULE;
port->cdev.kobj.parent = &umad_dev->kobj;
kobject_set_name(&port->cdev.kobj, "umad%d", port->dev_num); kobject_set_name(&port->cdev.kobj, "umad%d", port->dev_num);
if (cdev_add(&port->cdev, base, 1)) if (cdev_add(&port->cdev, base, 1))
goto err_cdev; goto err_cdev;
@ -1045,6 +1056,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
base += IB_UMAD_MAX_PORTS; base += IB_UMAD_MAX_PORTS;
cdev_init(&port->sm_cdev, &umad_sm_fops); cdev_init(&port->sm_cdev, &umad_sm_fops);
port->sm_cdev.owner = THIS_MODULE; port->sm_cdev.owner = THIS_MODULE;
port->sm_cdev.kobj.parent = &umad_dev->kobj;
kobject_set_name(&port->sm_cdev.kobj, "issm%d", port->dev_num); kobject_set_name(&port->sm_cdev.kobj, "issm%d", port->dev_num);
if (cdev_add(&port->sm_cdev, base, 1)) if (cdev_add(&port->sm_cdev, base, 1))
goto err_sm_cdev; goto err_sm_cdev;
@ -1138,7 +1150,7 @@ static void ib_umad_add_one(struct ib_device *device)
if (!umad_dev) if (!umad_dev)
return; return;
kref_init(&umad_dev->ref); kobject_init(&umad_dev->kobj, &ib_umad_dev_ktype);
umad_dev->start_port = s; umad_dev->start_port = s;
umad_dev->end_port = e; umad_dev->end_port = e;
@ -1146,7 +1158,8 @@ static void ib_umad_add_one(struct ib_device *device)
for (i = s; i <= e; ++i) { for (i = s; i <= e; ++i) {
umad_dev->port[i - s].umad_dev = umad_dev; umad_dev->port[i - s].umad_dev = umad_dev;
if (ib_umad_init_port(device, i, &umad_dev->port[i - s])) if (ib_umad_init_port(device, i, umad_dev,
&umad_dev->port[i - s]))
goto err; goto err;
} }
@ -1158,7 +1171,7 @@ err:
while (--i >= s) while (--i >= s)
ib_umad_kill_port(&umad_dev->port[i - s]); ib_umad_kill_port(&umad_dev->port[i - s]);
kref_put(&umad_dev->ref, ib_umad_release_dev); kobject_put(&umad_dev->kobj);
} }
static void ib_umad_remove_one(struct ib_device *device) static void ib_umad_remove_one(struct ib_device *device)
@ -1172,7 +1185,7 @@ static void ib_umad_remove_one(struct ib_device *device)
for (i = 0; i <= umad_dev->end_port - umad_dev->start_port; ++i) for (i = 0; i <= umad_dev->end_port - umad_dev->start_port; ++i)
ib_umad_kill_port(&umad_dev->port[i]); ib_umad_kill_port(&umad_dev->port[i]);
kref_put(&umad_dev->ref, ib_umad_release_dev); kobject_put(&umad_dev->kobj);
} }
static char *umad_devnode(struct device *dev, umode_t *mode) static char *umad_devnode(struct device *dev, umode_t *mode)

View file

@ -48,7 +48,7 @@
#include "core_priv.h" #include "core_priv.h"
int ib_rate_to_mult(enum ib_rate rate) __attribute_const__ int ib_rate_to_mult(enum ib_rate rate)
{ {
switch (rate) { switch (rate) {
case IB_RATE_2_5_GBPS: return 1; case IB_RATE_2_5_GBPS: return 1;
@ -65,7 +65,7 @@ int ib_rate_to_mult(enum ib_rate rate)
} }
EXPORT_SYMBOL(ib_rate_to_mult); EXPORT_SYMBOL(ib_rate_to_mult);
enum ib_rate mult_to_ib_rate(int mult) __attribute_const__ enum ib_rate mult_to_ib_rate(int mult)
{ {
switch (mult) { switch (mult) {
case 1: return IB_RATE_2_5_GBPS; case 1: return IB_RATE_2_5_GBPS;
@ -82,7 +82,7 @@ enum ib_rate mult_to_ib_rate(int mult)
} }
EXPORT_SYMBOL(mult_to_ib_rate); EXPORT_SYMBOL(mult_to_ib_rate);
int ib_rate_to_mbps(enum ib_rate rate) __attribute_const__ int ib_rate_to_mbps(enum ib_rate rate)
{ {
switch (rate) { switch (rate) {
case IB_RATE_2_5_GBPS: return 2500; case IB_RATE_2_5_GBPS: return 2500;
@ -107,7 +107,7 @@ int ib_rate_to_mbps(enum ib_rate rate)
} }
EXPORT_SYMBOL(ib_rate_to_mbps); EXPORT_SYMBOL(ib_rate_to_mbps);
enum rdma_transport_type __attribute_const__ enum rdma_transport_type
rdma_node_get_transport(enum rdma_node_type node_type) rdma_node_get_transport(enum rdma_node_type node_type)
{ {
switch (node_type) { switch (node_type) {

View file

@ -0,0 +1,12 @@
obj-$(CONFIG_INFINIBAND_MTHCA) += mthca/
obj-$(CONFIG_INFINIBAND_IPATH) += ipath/
obj-$(CONFIG_INFINIBAND_QIB) += qib/
obj-$(CONFIG_INFINIBAND_EHCA) += ehca/
obj-$(CONFIG_INFINIBAND_AMSO1100) += amso1100/
obj-$(CONFIG_INFINIBAND_CXGB3) += cxgb3/
obj-$(CONFIG_INFINIBAND_CXGB4) += cxgb4/
obj-$(CONFIG_MLX4_INFINIBAND) += mlx4/
obj-$(CONFIG_MLX5_INFINIBAND) += mlx5/
obj-$(CONFIG_INFINIBAND_NES) += nes/
obj-$(CONFIG_INFINIBAND_OCRDMA) += ocrdma/
obj-$(CONFIG_INFINIBAND_USNIC) += usnic/

View file

@ -735,14 +735,12 @@ static int __cxio_tpt_op(struct cxio_rdev *rdev_p, u32 reset_tpt_entry,
((perm & TPT_MW_BIND) ? F_TPT_MW_BIND_ENABLE : 0) | ((perm & TPT_MW_BIND) ? F_TPT_MW_BIND_ENABLE : 0) |
V_TPT_ADDR_TYPE((zbva ? TPT_ZBTO : TPT_VATO)) | V_TPT_ADDR_TYPE((zbva ? TPT_ZBTO : TPT_VATO)) |
V_TPT_PAGE_SIZE(page_size)); V_TPT_PAGE_SIZE(page_size));
tpt.rsvd_pbl_addr = reset_tpt_entry ? 0 : tpt.rsvd_pbl_addr = cpu_to_be32(V_TPT_PBL_ADDR(PBL_OFF(rdev_p, pbl_addr)>>3));
cpu_to_be32(V_TPT_PBL_ADDR(PBL_OFF(rdev_p, pbl_addr)>>3));
tpt.len = cpu_to_be32(len); tpt.len = cpu_to_be32(len);
tpt.va_hi = cpu_to_be32((u32) (to >> 32)); tpt.va_hi = cpu_to_be32((u32) (to >> 32));
tpt.va_low_or_fbo = cpu_to_be32((u32) (to & 0xFFFFFFFFULL)); tpt.va_low_or_fbo = cpu_to_be32((u32) (to & 0xFFFFFFFFULL));
tpt.rsvd_bind_cnt_or_pstag = 0; tpt.rsvd_bind_cnt_or_pstag = 0;
tpt.rsvd_pbl_size = reset_tpt_entry ? 0 : tpt.rsvd_pbl_size = cpu_to_be32(V_TPT_PBL_SIZE(pbl_size >> 2));
cpu_to_be32(V_TPT_PBL_SIZE(pbl_size >> 2));
} }
err = cxio_hal_ctrl_qp_write_mem(rdev_p, err = cxio_hal_ctrl_qp_write_mem(rdev_p,
stag_idx + stag_idx +

View file

@ -418,6 +418,7 @@ static int send_abort(struct iwch_ep *ep, struct sk_buff *skb, gfp_t gfp)
skb->priority = CPL_PRIORITY_DATA; skb->priority = CPL_PRIORITY_DATA;
set_arp_failure_handler(skb, abort_arp_failure); set_arp_failure_handler(skb, abort_arp_failure);
req = (struct cpl_abort_req *) skb_put(skb, sizeof(*req)); req = (struct cpl_abort_req *) skb_put(skb, sizeof(*req));
memset(req, 0, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ));
req->wr.wr_lo = htonl(V_WR_TID(ep->hwtid)); req->wr.wr_lo = htonl(V_WR_TID(ep->hwtid));
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ABORT_REQ, ep->hwtid)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ABORT_REQ, ep->hwtid));

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved. * Copyright (c) 2009-2014 Chelsio, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU * licenses. You may choose to be licensed under the terms of the GNU
@ -47,6 +47,8 @@
#include <net/ip6_route.h> #include <net/ip6_route.h>
#include <net/addrconf.h> #include <net/addrconf.h>
#include <rdma/ib_addr.h>
#include "iw_cxgb4.h" #include "iw_cxgb4.h"
static char *states[] = { static char *states[] = {
@ -294,6 +296,12 @@ void _c4iw_free_ep(struct kref *kref)
dst_release(ep->dst); dst_release(ep->dst);
cxgb4_l2t_release(ep->l2t); cxgb4_l2t_release(ep->l2t);
} }
if (test_bit(RELEASE_MAPINFO, &ep->com.flags)) {
print_addr(&ep->com, __func__, "remove_mapinfo/mapping");
iwpm_remove_mapinfo(&ep->com.local_addr,
&ep->com.mapped_local_addr);
iwpm_remove_mapping(&ep->com.local_addr, RDMA_NL_C4IW);
}
kfree(ep); kfree(ep);
} }
@ -341,10 +349,7 @@ static struct sk_buff *get_skb(struct sk_buff *skb, int len, gfp_t gfp)
static struct net_device *get_real_dev(struct net_device *egress_dev) static struct net_device *get_real_dev(struct net_device *egress_dev)
{ {
struct net_device *phys_dev = egress_dev; return rdma_vlan_dev_real_dev(egress_dev) ? : egress_dev;
if (egress_dev->priv_flags & IFF_802_1Q_VLAN)
phys_dev = vlan_dev_real_dev(egress_dev);
return phys_dev;
} }
static int our_interface(struct c4iw_dev *dev, struct net_device *egress_dev) static int our_interface(struct c4iw_dev *dev, struct net_device *egress_dev)
@ -528,6 +533,38 @@ static int send_abort(struct c4iw_ep *ep, struct sk_buff *skb, gfp_t gfp)
return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t); return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
} }
/*
* c4iw_form_pm_msg - Form a port mapper message with mapping info
*/
static void c4iw_form_pm_msg(struct c4iw_ep *ep,
struct iwpm_sa_data *pm_msg)
{
memcpy(&pm_msg->loc_addr, &ep->com.local_addr,
sizeof(ep->com.local_addr));
memcpy(&pm_msg->rem_addr, &ep->com.remote_addr,
sizeof(ep->com.remote_addr));
}
/*
* c4iw_form_reg_msg - Form a port mapper message with dev info
*/
static void c4iw_form_reg_msg(struct c4iw_dev *dev,
struct iwpm_dev_data *pm_msg)
{
memcpy(pm_msg->dev_name, dev->ibdev.name, IWPM_DEVNAME_SIZE);
memcpy(pm_msg->if_name, dev->rdev.lldi.ports[0]->name,
IWPM_IFNAME_SIZE);
}
static void c4iw_record_pm_msg(struct c4iw_ep *ep,
struct iwpm_sa_data *pm_msg)
{
memcpy(&ep->com.mapped_local_addr, &pm_msg->mapped_loc_addr,
sizeof(ep->com.mapped_local_addr));
memcpy(&ep->com.mapped_remote_addr, &pm_msg->mapped_rem_addr,
sizeof(ep->com.mapped_remote_addr));
}
static int send_connect(struct c4iw_ep *ep) static int send_connect(struct c4iw_ep *ep)
{ {
struct cpl_act_open_req *req; struct cpl_act_open_req *req;
@ -546,10 +583,14 @@ static int send_connect(struct c4iw_ep *ep)
int sizev6 = is_t4(ep->com.dev->rdev.lldi.adapter_type) ? int sizev6 = is_t4(ep->com.dev->rdev.lldi.adapter_type) ?
sizeof(struct cpl_act_open_req6) : sizeof(struct cpl_act_open_req6) :
sizeof(struct cpl_t5_act_open_req6); sizeof(struct cpl_t5_act_open_req6);
struct sockaddr_in *la = (struct sockaddr_in *)&ep->com.local_addr; struct sockaddr_in *la = (struct sockaddr_in *)
struct sockaddr_in *ra = (struct sockaddr_in *)&ep->com.remote_addr; &ep->com.mapped_local_addr;
struct sockaddr_in6 *la6 = (struct sockaddr_in6 *)&ep->com.local_addr; struct sockaddr_in *ra = (struct sockaddr_in *)
struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)&ep->com.remote_addr; &ep->com.mapped_remote_addr;
struct sockaddr_in6 *la6 = (struct sockaddr_in6 *)
&ep->com.mapped_local_addr;
struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)
&ep->com.mapped_remote_addr;
wrlen = (ep->com.remote_addr.ss_family == AF_INET) ? wrlen = (ep->com.remote_addr.ss_family == AF_INET) ?
roundup(sizev4, 16) : roundup(sizev4, 16) :
@ -1627,10 +1668,10 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)
req->le.filter = cpu_to_be32(cxgb4_select_ntuple( req->le.filter = cpu_to_be32(cxgb4_select_ntuple(
ep->com.dev->rdev.lldi.ports[0], ep->com.dev->rdev.lldi.ports[0],
ep->l2t)); ep->l2t));
sin = (struct sockaddr_in *)&ep->com.local_addr; sin = (struct sockaddr_in *)&ep->com.mapped_local_addr;
req->le.lport = sin->sin_port; req->le.lport = sin->sin_port;
req->le.u.ipv4.lip = sin->sin_addr.s_addr; req->le.u.ipv4.lip = sin->sin_addr.s_addr;
sin = (struct sockaddr_in *)&ep->com.remote_addr; sin = (struct sockaddr_in *)&ep->com.mapped_remote_addr;
req->le.pport = sin->sin_port; req->le.pport = sin->sin_port;
req->le.u.ipv4.pip = sin->sin_addr.s_addr; req->le.u.ipv4.pip = sin->sin_addr.s_addr;
req->tcb.t_state_to_astid = req->tcb.t_state_to_astid =
@ -1746,16 +1787,16 @@ static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,
if (!ep->l2t) if (!ep->l2t)
goto out; goto out;
ep->mtu = dst_mtu(dst); ep->mtu = dst_mtu(dst);
ep->tx_chan = cxgb4_port_chan(n->dev); ep->tx_chan = cxgb4_port_chan(pdev);
ep->smac_idx = (cxgb4_port_viid(n->dev) & 0x7F) << 1; ep->smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1;
step = cdev->rdev.lldi.ntxq / step = cdev->rdev.lldi.ntxq /
cdev->rdev.lldi.nchan; cdev->rdev.lldi.nchan;
ep->txq_idx = cxgb4_port_idx(n->dev) * step; ep->txq_idx = cxgb4_port_idx(pdev) * step;
ep->ctrlq_idx = cxgb4_port_idx(n->dev); ep->ctrlq_idx = cxgb4_port_idx(pdev);
step = cdev->rdev.lldi.nrxq / step = cdev->rdev.lldi.nrxq /
cdev->rdev.lldi.nchan; cdev->rdev.lldi.nchan;
ep->rss_qid = cdev->rdev.lldi.rxq_ids[ ep->rss_qid = cdev->rdev.lldi.rxq_ids[
cxgb4_port_idx(n->dev) * step]; cxgb4_port_idx(pdev) * step];
if (clear_mpa_v1) { if (clear_mpa_v1) {
ep->retry_with_mpa_v1 = 0; ep->retry_with_mpa_v1 = 0;
@ -1870,10 +1911,10 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
struct sockaddr_in6 *ra6; struct sockaddr_in6 *ra6;
ep = lookup_atid(t, atid); ep = lookup_atid(t, atid);
la = (struct sockaddr_in *)&ep->com.local_addr; la = (struct sockaddr_in *)&ep->com.mapped_local_addr;
ra = (struct sockaddr_in *)&ep->com.remote_addr; ra = (struct sockaddr_in *)&ep->com.mapped_remote_addr;
la6 = (struct sockaddr_in6 *)&ep->com.local_addr; la6 = (struct sockaddr_in6 *)&ep->com.mapped_local_addr;
ra6 = (struct sockaddr_in6 *)&ep->com.remote_addr; ra6 = (struct sockaddr_in6 *)&ep->com.mapped_remote_addr;
PDBG("%s ep %p atid %u status %u errno %d\n", __func__, ep, atid, PDBG("%s ep %p atid %u status %u errno %d\n", __func__, ep, atid,
status, status2errno(status)); status, status2errno(status));
@ -2730,13 +2771,15 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
struct c4iw_dev *dev = to_c4iw_dev(cm_id->device); struct c4iw_dev *dev = to_c4iw_dev(cm_id->device);
struct c4iw_ep *ep; struct c4iw_ep *ep;
int err = 0; int err = 0;
struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->local_addr; struct sockaddr_in *laddr;
struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->remote_addr; struct sockaddr_in *raddr;
struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)&cm_id->local_addr; struct sockaddr_in6 *laddr6;
struct sockaddr_in6 *raddr6 = (struct sockaddr_in6 *) struct sockaddr_in6 *raddr6;
&cm_id->remote_addr; struct iwpm_dev_data pm_reg_msg;
struct iwpm_sa_data pm_msg;
__u8 *ra; __u8 *ra;
int iptype; int iptype;
int iwpm_err = 0;
if ((conn_param->ord > c4iw_max_read_depth) || if ((conn_param->ord > c4iw_max_read_depth) ||
(conn_param->ird > c4iw_max_read_depth)) { (conn_param->ird > c4iw_max_read_depth)) {
@ -2767,7 +2810,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if (!ep->com.qp) { if (!ep->com.qp) {
PDBG("%s qpn 0x%x not found!\n", __func__, conn_param->qpn); PDBG("%s qpn 0x%x not found!\n", __func__, conn_param->qpn);
err = -EINVAL; err = -EINVAL;
goto fail2; goto fail1;
} }
ref_qp(ep); ref_qp(ep);
PDBG("%s qpn 0x%x qp %p cm_id %p\n", __func__, conn_param->qpn, PDBG("%s qpn 0x%x qp %p cm_id %p\n", __func__, conn_param->qpn,
@ -2780,10 +2823,50 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if (ep->atid == -1) { if (ep->atid == -1) {
printk(KERN_ERR MOD "%s - cannot alloc atid.\n", __func__); printk(KERN_ERR MOD "%s - cannot alloc atid.\n", __func__);
err = -ENOMEM; err = -ENOMEM;
goto fail2; goto fail1;
} }
insert_handle(dev, &dev->atid_idr, ep, ep->atid); insert_handle(dev, &dev->atid_idr, ep, ep->atid);
memcpy(&ep->com.local_addr, &cm_id->local_addr,
sizeof(ep->com.local_addr));
memcpy(&ep->com.remote_addr, &cm_id->remote_addr,
sizeof(ep->com.remote_addr));
/* No port mapper available, go with the specified peer information */
memcpy(&ep->com.mapped_local_addr, &cm_id->local_addr,
sizeof(ep->com.mapped_local_addr));
memcpy(&ep->com.mapped_remote_addr, &cm_id->remote_addr,
sizeof(ep->com.mapped_remote_addr));
c4iw_form_reg_msg(dev, &pm_reg_msg);
iwpm_err = iwpm_register_pid(&pm_reg_msg, RDMA_NL_C4IW);
if (iwpm_err) {
PDBG("%s: Port Mapper reg pid fail (err = %d).\n",
__func__, iwpm_err);
}
if (iwpm_valid_pid() && !iwpm_err) {
c4iw_form_pm_msg(ep, &pm_msg);
iwpm_err = iwpm_add_and_query_mapping(&pm_msg, RDMA_NL_C4IW);
if (iwpm_err)
PDBG("%s: Port Mapper query fail (err = %d).\n",
__func__, iwpm_err);
else
c4iw_record_pm_msg(ep, &pm_msg);
}
if (iwpm_create_mapinfo(&ep->com.local_addr,
&ep->com.mapped_local_addr, RDMA_NL_C4IW)) {
iwpm_remove_mapping(&ep->com.local_addr, RDMA_NL_C4IW);
err = -ENOMEM;
goto fail1;
}
print_addr(&ep->com, __func__, "add_query/create_mapinfo");
set_bit(RELEASE_MAPINFO, &ep->com.flags);
laddr = (struct sockaddr_in *)&ep->com.mapped_local_addr;
raddr = (struct sockaddr_in *)&ep->com.mapped_remote_addr;
laddr6 = (struct sockaddr_in6 *)&ep->com.mapped_local_addr;
raddr6 = (struct sockaddr_in6 *) &ep->com.mapped_remote_addr;
if (cm_id->remote_addr.ss_family == AF_INET) { if (cm_id->remote_addr.ss_family == AF_INET) {
iptype = 4; iptype = 4;
ra = (__u8 *)&raddr->sin_addr; ra = (__u8 *)&raddr->sin_addr;
@ -2794,7 +2877,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if ((__force int)raddr->sin_addr.s_addr == INADDR_ANY) { if ((__force int)raddr->sin_addr.s_addr == INADDR_ANY) {
err = pick_local_ipaddrs(dev, cm_id); err = pick_local_ipaddrs(dev, cm_id);
if (err) if (err)
goto fail2; goto fail1;
} }
/* find a route */ /* find a route */
@ -2814,7 +2897,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if (ipv6_addr_type(&raddr6->sin6_addr) == IPV6_ADDR_ANY) { if (ipv6_addr_type(&raddr6->sin6_addr) == IPV6_ADDR_ANY) {
err = pick_local_ip6addrs(dev, cm_id); err = pick_local_ip6addrs(dev, cm_id);
if (err) if (err)
goto fail2; goto fail1;
} }
/* find a route */ /* find a route */
@ -2830,13 +2913,13 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if (!ep->dst) { if (!ep->dst) {
printk(KERN_ERR MOD "%s - cannot find route.\n", __func__); printk(KERN_ERR MOD "%s - cannot find route.\n", __func__);
err = -EHOSTUNREACH; err = -EHOSTUNREACH;
goto fail3; goto fail2;
} }
err = import_ep(ep, iptype, ra, ep->dst, ep->com.dev, true); err = import_ep(ep, iptype, ra, ep->dst, ep->com.dev, true);
if (err) { if (err) {
printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__); printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__);
goto fail4; goto fail3;
} }
PDBG("%s txq_idx %u tx_chan %u smac_idx %u rss_qid %u l2t_idx %u\n", PDBG("%s txq_idx %u tx_chan %u smac_idx %u rss_qid %u l2t_idx %u\n",
@ -2845,10 +2928,6 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
state_set(&ep->com, CONNECTING); state_set(&ep->com, CONNECTING);
ep->tos = 0; ep->tos = 0;
memcpy(&ep->com.local_addr, &cm_id->local_addr,
sizeof(ep->com.local_addr));
memcpy(&ep->com.remote_addr, &cm_id->remote_addr,
sizeof(ep->com.remote_addr));
/* send connect request to rnic */ /* send connect request to rnic */
err = send_connect(ep); err = send_connect(ep);
@ -2856,12 +2935,12 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
goto out; goto out;
cxgb4_l2t_release(ep->l2t); cxgb4_l2t_release(ep->l2t);
fail4:
dst_release(ep->dst);
fail3: fail3:
dst_release(ep->dst);
fail2:
remove_handle(ep->com.dev, &ep->com.dev->atid_idr, ep->atid); remove_handle(ep->com.dev, &ep->com.dev->atid_idr, ep->atid);
cxgb4_free_atid(ep->com.dev->rdev.lldi.tids, ep->atid); cxgb4_free_atid(ep->com.dev->rdev.lldi.tids, ep->atid);
fail2: fail1:
cm_id->rem_ref(cm_id); cm_id->rem_ref(cm_id);
c4iw_put_ep(&ep->com); c4iw_put_ep(&ep->com);
out: out:
@ -2871,7 +2950,8 @@ out:
static int create_server6(struct c4iw_dev *dev, struct c4iw_listen_ep *ep) static int create_server6(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)
{ {
int err; int err;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ep->com.local_addr; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
&ep->com.mapped_local_addr;
c4iw_init_wr_wait(&ep->com.wr_wait); c4iw_init_wr_wait(&ep->com.wr_wait);
err = cxgb4_create_server6(ep->com.dev->rdev.lldi.ports[0], err = cxgb4_create_server6(ep->com.dev->rdev.lldi.ports[0],
@ -2892,7 +2972,8 @@ static int create_server6(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)
static int create_server4(struct c4iw_dev *dev, struct c4iw_listen_ep *ep) static int create_server4(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)
{ {
int err; int err;
struct sockaddr_in *sin = (struct sockaddr_in *)&ep->com.local_addr; struct sockaddr_in *sin = (struct sockaddr_in *)
&ep->com.mapped_local_addr;
if (dev->rdev.lldi.enable_fw_ofld_conn) { if (dev->rdev.lldi.enable_fw_ofld_conn) {
do { do {
@ -2927,6 +3008,9 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
int err = 0; int err = 0;
struct c4iw_dev *dev = to_c4iw_dev(cm_id->device); struct c4iw_dev *dev = to_c4iw_dev(cm_id->device);
struct c4iw_listen_ep *ep; struct c4iw_listen_ep *ep;
struct iwpm_dev_data pm_reg_msg;
struct iwpm_sa_data pm_msg;
int iwpm_err = 0;
might_sleep(); might_sleep();
@ -2961,6 +3045,37 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
goto fail2; goto fail2;
} }
insert_handle(dev, &dev->stid_idr, ep, ep->stid); insert_handle(dev, &dev->stid_idr, ep, ep->stid);
/* No port mapper available, go with the specified info */
memcpy(&ep->com.mapped_local_addr, &cm_id->local_addr,
sizeof(ep->com.mapped_local_addr));
c4iw_form_reg_msg(dev, &pm_reg_msg);
iwpm_err = iwpm_register_pid(&pm_reg_msg, RDMA_NL_C4IW);
if (iwpm_err) {
PDBG("%s: Port Mapper reg pid fail (err = %d).\n",
__func__, iwpm_err);
}
if (iwpm_valid_pid() && !iwpm_err) {
memcpy(&pm_msg.loc_addr, &ep->com.local_addr,
sizeof(ep->com.local_addr));
iwpm_err = iwpm_add_mapping(&pm_msg, RDMA_NL_C4IW);
if (iwpm_err)
PDBG("%s: Port Mapper query fail (err = %d).\n",
__func__, iwpm_err);
else
memcpy(&ep->com.mapped_local_addr,
&pm_msg.mapped_loc_addr,
sizeof(ep->com.mapped_local_addr));
}
if (iwpm_create_mapinfo(&ep->com.local_addr,
&ep->com.mapped_local_addr, RDMA_NL_C4IW)) {
err = -ENOMEM;
goto fail3;
}
print_addr(&ep->com, __func__, "add_mapping/create_mapinfo");
set_bit(RELEASE_MAPINFO, &ep->com.flags);
state_set(&ep->com, LISTEN); state_set(&ep->com, LISTEN);
if (ep->com.local_addr.ss_family == AF_INET) if (ep->com.local_addr.ss_family == AF_INET)
err = create_server4(dev, ep); err = create_server4(dev, ep);
@ -2970,6 +3085,8 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
cm_id->provider_data = ep; cm_id->provider_data = ep;
goto out; goto out;
} }
fail3:
cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid, cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid,
ep->com.local_addr.ss_family); ep->com.local_addr.ss_family);
fail2: fail2:

View file

@ -940,7 +940,6 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
if (!mm2) if (!mm2)
goto err4; goto err4;
memset(&uresp, 0, sizeof(uresp));
uresp.qid_mask = rhp->rdev.cqmask; uresp.qid_mask = rhp->rdev.cqmask;
uresp.cqid = chp->cq.cqid; uresp.cqid = chp->cq.cqid;
uresp.size = chp->cq.size; uresp.size = chp->cq.size;
@ -951,7 +950,8 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
uresp.gts_key = ucontext->key; uresp.gts_key = ucontext->key;
ucontext->key += PAGE_SIZE; ucontext->key += PAGE_SIZE;
spin_unlock(&ucontext->mmap_lock); spin_unlock(&ucontext->mmap_lock);
ret = ib_copy_to_udata(udata, &uresp, sizeof uresp); ret = ib_copy_to_udata(udata, &uresp,
sizeof(uresp) - sizeof(uresp.reserved));
if (ret) if (ret)
goto err5; goto err5;

View file

@ -77,6 +77,16 @@ struct c4iw_debugfs_data {
int pos; int pos;
}; };
/* registered cxgb4 netlink callbacks */
static struct ibnl_client_cbs c4iw_nl_cb_table[] = {
[RDMA_NL_IWPM_REG_PID] = {.dump = iwpm_register_pid_cb},
[RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb},
[RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = iwpm_add_and_query_mapping_cb},
[RDMA_NL_IWPM_HANDLE_ERR] = {.dump = iwpm_mapping_error_cb},
[RDMA_NL_IWPM_MAPINFO] = {.dump = iwpm_mapping_info_cb},
[RDMA_NL_IWPM_MAPINFO_NUM] = {.dump = iwpm_ack_mapping_info_cb}
};
static int count_idrs(int id, void *p, void *data) static int count_idrs(int id, void *p, void *data)
{ {
int *countp = data; int *countp = data;
@ -113,35 +123,49 @@ static int dump_qp(int id, void *p, void *data)
&qp->ep->com.local_addr; &qp->ep->com.local_addr;
struct sockaddr_in *rsin = (struct sockaddr_in *) struct sockaddr_in *rsin = (struct sockaddr_in *)
&qp->ep->com.remote_addr; &qp->ep->com.remote_addr;
struct sockaddr_in *mapped_lsin = (struct sockaddr_in *)
&qp->ep->com.mapped_local_addr;
struct sockaddr_in *mapped_rsin = (struct sockaddr_in *)
&qp->ep->com.mapped_remote_addr;
cc = snprintf(qpd->buf + qpd->pos, space, cc = snprintf(qpd->buf + qpd->pos, space,
"rc qp sq id %u rq id %u state %u " "rc qp sq id %u rq id %u state %u "
"onchip %u ep tid %u state %u " "onchip %u ep tid %u state %u "
"%pI4:%u->%pI4:%u\n", "%pI4:%u/%u->%pI4:%u/%u\n",
qp->wq.sq.qid, qp->wq.rq.qid, qp->wq.sq.qid, qp->wq.rq.qid,
(int)qp->attr.state, (int)qp->attr.state,
qp->wq.sq.flags & T4_SQ_ONCHIP, qp->wq.sq.flags & T4_SQ_ONCHIP,
qp->ep->hwtid, (int)qp->ep->com.state, qp->ep->hwtid, (int)qp->ep->com.state,
&lsin->sin_addr, ntohs(lsin->sin_port), &lsin->sin_addr, ntohs(lsin->sin_port),
&rsin->sin_addr, ntohs(rsin->sin_port)); ntohs(mapped_lsin->sin_port),
&rsin->sin_addr, ntohs(rsin->sin_port),
ntohs(mapped_rsin->sin_port));
} else { } else {
struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *) struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *)
&qp->ep->com.local_addr; &qp->ep->com.local_addr;
struct sockaddr_in6 *rsin6 = (struct sockaddr_in6 *) struct sockaddr_in6 *rsin6 = (struct sockaddr_in6 *)
&qp->ep->com.remote_addr; &qp->ep->com.remote_addr;
struct sockaddr_in6 *mapped_lsin6 =
(struct sockaddr_in6 *)
&qp->ep->com.mapped_local_addr;
struct sockaddr_in6 *mapped_rsin6 =
(struct sockaddr_in6 *)
&qp->ep->com.mapped_remote_addr;
cc = snprintf(qpd->buf + qpd->pos, space, cc = snprintf(qpd->buf + qpd->pos, space,
"rc qp sq id %u rq id %u state %u " "rc qp sq id %u rq id %u state %u "
"onchip %u ep tid %u state %u " "onchip %u ep tid %u state %u "
"%pI6:%u->%pI6:%u\n", "%pI6:%u/%u->%pI6:%u/%u\n",
qp->wq.sq.qid, qp->wq.rq.qid, qp->wq.sq.qid, qp->wq.rq.qid,
(int)qp->attr.state, (int)qp->attr.state,
qp->wq.sq.flags & T4_SQ_ONCHIP, qp->wq.sq.flags & T4_SQ_ONCHIP,
qp->ep->hwtid, (int)qp->ep->com.state, qp->ep->hwtid, (int)qp->ep->com.state,
&lsin6->sin6_addr, &lsin6->sin6_addr,
ntohs(lsin6->sin6_port), ntohs(lsin6->sin6_port),
ntohs(mapped_lsin6->sin6_port),
&rsin6->sin6_addr, &rsin6->sin6_addr,
ntohs(rsin6->sin6_port)); ntohs(rsin6->sin6_port),
ntohs(mapped_rsin6->sin6_port));
} }
} else } else
cc = snprintf(qpd->buf + qpd->pos, space, cc = snprintf(qpd->buf + qpd->pos, space,
@ -386,31 +410,43 @@ static int dump_ep(int id, void *p, void *data)
&ep->com.local_addr; &ep->com.local_addr;
struct sockaddr_in *rsin = (struct sockaddr_in *) struct sockaddr_in *rsin = (struct sockaddr_in *)
&ep->com.remote_addr; &ep->com.remote_addr;
struct sockaddr_in *mapped_lsin = (struct sockaddr_in *)
&ep->com.mapped_local_addr;
struct sockaddr_in *mapped_rsin = (struct sockaddr_in *)
&ep->com.mapped_remote_addr;
cc = snprintf(epd->buf + epd->pos, space, cc = snprintf(epd->buf + epd->pos, space,
"ep %p cm_id %p qp %p state %d flags 0x%lx " "ep %p cm_id %p qp %p state %d flags 0x%lx "
"history 0x%lx hwtid %d atid %d " "history 0x%lx hwtid %d atid %d "
"%pI4:%d <-> %pI4:%d\n", "%pI4:%d/%d <-> %pI4:%d/%d\n",
ep, ep->com.cm_id, ep->com.qp, ep, ep->com.cm_id, ep->com.qp,
(int)ep->com.state, ep->com.flags, (int)ep->com.state, ep->com.flags,
ep->com.history, ep->hwtid, ep->atid, ep->com.history, ep->hwtid, ep->atid,
&lsin->sin_addr, ntohs(lsin->sin_port), &lsin->sin_addr, ntohs(lsin->sin_port),
&rsin->sin_addr, ntohs(rsin->sin_port)); ntohs(mapped_lsin->sin_port),
&rsin->sin_addr, ntohs(rsin->sin_port),
ntohs(mapped_rsin->sin_port));
} else { } else {
struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *) struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *)
&ep->com.local_addr; &ep->com.local_addr;
struct sockaddr_in6 *rsin6 = (struct sockaddr_in6 *) struct sockaddr_in6 *rsin6 = (struct sockaddr_in6 *)
&ep->com.remote_addr; &ep->com.remote_addr;
struct sockaddr_in6 *mapped_lsin6 = (struct sockaddr_in6 *)
&ep->com.mapped_local_addr;
struct sockaddr_in6 *mapped_rsin6 = (struct sockaddr_in6 *)
&ep->com.mapped_remote_addr;
cc = snprintf(epd->buf + epd->pos, space, cc = snprintf(epd->buf + epd->pos, space,
"ep %p cm_id %p qp %p state %d flags 0x%lx " "ep %p cm_id %p qp %p state %d flags 0x%lx "
"history 0x%lx hwtid %d atid %d " "history 0x%lx hwtid %d atid %d "
"%pI6:%d <-> %pI6:%d\n", "%pI6:%d/%d <-> %pI6:%d/%d\n",
ep, ep->com.cm_id, ep->com.qp, ep, ep->com.cm_id, ep->com.qp,
(int)ep->com.state, ep->com.flags, (int)ep->com.state, ep->com.flags,
ep->com.history, ep->hwtid, ep->atid, ep->com.history, ep->hwtid, ep->atid,
&lsin6->sin6_addr, ntohs(lsin6->sin6_port), &lsin6->sin6_addr, ntohs(lsin6->sin6_port),
&rsin6->sin6_addr, ntohs(rsin6->sin6_port)); ntohs(mapped_lsin6->sin6_port),
&rsin6->sin6_addr, ntohs(rsin6->sin6_port),
ntohs(mapped_rsin6->sin6_port));
} }
if (cc < space) if (cc < space)
epd->pos += cc; epd->pos += cc;
@ -431,23 +467,29 @@ static int dump_listen_ep(int id, void *p, void *data)
if (ep->com.local_addr.ss_family == AF_INET) { if (ep->com.local_addr.ss_family == AF_INET) {
struct sockaddr_in *lsin = (struct sockaddr_in *) struct sockaddr_in *lsin = (struct sockaddr_in *)
&ep->com.local_addr; &ep->com.local_addr;
struct sockaddr_in *mapped_lsin = (struct sockaddr_in *)
&ep->com.mapped_local_addr;
cc = snprintf(epd->buf + epd->pos, space, cc = snprintf(epd->buf + epd->pos, space,
"ep %p cm_id %p state %d flags 0x%lx stid %d " "ep %p cm_id %p state %d flags 0x%lx stid %d "
"backlog %d %pI4:%d\n", "backlog %d %pI4:%d/%d\n",
ep, ep->com.cm_id, (int)ep->com.state, ep, ep->com.cm_id, (int)ep->com.state,
ep->com.flags, ep->stid, ep->backlog, ep->com.flags, ep->stid, ep->backlog,
&lsin->sin_addr, ntohs(lsin->sin_port)); &lsin->sin_addr, ntohs(lsin->sin_port),
ntohs(mapped_lsin->sin_port));
} else { } else {
struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *) struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *)
&ep->com.local_addr; &ep->com.local_addr;
struct sockaddr_in6 *mapped_lsin6 = (struct sockaddr_in6 *)
&ep->com.mapped_local_addr;
cc = snprintf(epd->buf + epd->pos, space, cc = snprintf(epd->buf + epd->pos, space,
"ep %p cm_id %p state %d flags 0x%lx stid %d " "ep %p cm_id %p state %d flags 0x%lx stid %d "
"backlog %d %pI6:%d\n", "backlog %d %pI6:%d/%d\n",
ep, ep->com.cm_id, (int)ep->com.state, ep, ep->com.cm_id, (int)ep->com.state,
ep->com.flags, ep->stid, ep->backlog, ep->com.flags, ep->stid, ep->backlog,
&lsin6->sin6_addr, ntohs(lsin6->sin6_port)); &lsin6->sin6_addr, ntohs(lsin6->sin6_port),
ntohs(mapped_lsin6->sin6_port));
} }
if (cc < space) if (cc < space)
epd->pos += cc; epd->pos += cc;
@ -687,6 +729,7 @@ static void c4iw_dealloc(struct uld_ctx *ctx)
if (ctx->dev->rdev.oc_mw_kva) if (ctx->dev->rdev.oc_mw_kva)
iounmap(ctx->dev->rdev.oc_mw_kva); iounmap(ctx->dev->rdev.oc_mw_kva);
ib_dealloc_device(&ctx->dev->ibdev); ib_dealloc_device(&ctx->dev->ibdev);
iwpm_exit(RDMA_NL_C4IW);
ctx->dev = NULL; ctx->dev = NULL;
} }
@ -736,6 +779,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
pci_resource_len(devp->rdev.lldi.pdev, 2)); pci_resource_len(devp->rdev.lldi.pdev, 2));
if (!devp->rdev.bar2_kva) { if (!devp->rdev.bar2_kva) {
pr_err(MOD "Unable to ioremap BAR2\n"); pr_err(MOD "Unable to ioremap BAR2\n");
ib_dealloc_device(&devp->ibdev);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
} else if (ocqp_supported(infop)) { } else if (ocqp_supported(infop)) {
@ -747,6 +791,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
devp->rdev.lldi.vr->ocq.size); devp->rdev.lldi.vr->ocq.size);
if (!devp->rdev.oc_mw_kva) { if (!devp->rdev.oc_mw_kva) {
pr_err(MOD "Unable to ioremap onchip mem\n"); pr_err(MOD "Unable to ioremap onchip mem\n");
ib_dealloc_device(&devp->ibdev);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
} }
@ -780,6 +825,14 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
c4iw_debugfs_root); c4iw_debugfs_root);
setup_debugfs(devp); setup_debugfs(devp);
} }
ret = iwpm_init(RDMA_NL_C4IW);
if (ret) {
pr_err("port mapper initialization failed with %d\n", ret);
ib_dealloc_device(&devp->ibdev);
return ERR_PTR(ret);
}
return devp; return devp;
} }
@ -1274,6 +1327,11 @@ static int __init c4iw_init_module(void)
printk(KERN_WARNING MOD printk(KERN_WARNING MOD
"could not create debugfs entry, continuing\n"); "could not create debugfs entry, continuing\n");
if (ibnl_add_client(RDMA_NL_C4IW, RDMA_NL_IWPM_NUM_OPS,
c4iw_nl_cb_table))
pr_err("%s[%u]: Failed to add netlink callback\n"
, __func__, __LINE__);
cxgb4_register_uld(CXGB4_ULD_RDMA, &c4iw_uld_info); cxgb4_register_uld(CXGB4_ULD_RDMA, &c4iw_uld_info);
return 0; return 0;
@ -1291,6 +1349,7 @@ static void __exit c4iw_exit_module(void)
} }
mutex_unlock(&dev_mutex); mutex_unlock(&dev_mutex);
cxgb4_unregister_uld(CXGB4_ULD_RDMA); cxgb4_unregister_uld(CXGB4_ULD_RDMA);
ibnl_remove_client(RDMA_NL_C4IW);
c4iw_cm_term(); c4iw_cm_term();
debugfs_remove_recursive(c4iw_debugfs_root); debugfs_remove_recursive(c4iw_debugfs_root);
} }

View file

@ -52,6 +52,8 @@
#include <rdma/ib_verbs.h> #include <rdma/ib_verbs.h>
#include <rdma/iw_cm.h> #include <rdma/iw_cm.h>
#include <rdma/rdma_netlink.h>
#include <rdma/iw_portmap.h>
#include "cxgb4.h" #include "cxgb4.h"
#include "cxgb4_uld.h" #include "cxgb4_uld.h"
@ -728,6 +730,7 @@ enum c4iw_ep_flags {
CLOSE_SENT = 3, CLOSE_SENT = 3,
TIMEOUT = 4, TIMEOUT = 4,
QP_REFERENCED = 5, QP_REFERENCED = 5,
RELEASE_MAPINFO = 6,
}; };
enum c4iw_ep_history { enum c4iw_ep_history {
@ -764,6 +767,8 @@ struct c4iw_ep_common {
struct mutex mutex; struct mutex mutex;
struct sockaddr_storage local_addr; struct sockaddr_storage local_addr;
struct sockaddr_storage remote_addr; struct sockaddr_storage remote_addr;
struct sockaddr_storage mapped_local_addr;
struct sockaddr_storage mapped_remote_addr;
struct c4iw_wr_wait wr_wait; struct c4iw_wr_wait wr_wait;
unsigned long flags; unsigned long flags;
unsigned long history; unsigned long history;
@ -807,6 +812,45 @@ struct c4iw_ep {
unsigned int retry_count; unsigned int retry_count;
}; };
static inline void print_addr(struct c4iw_ep_common *epc, const char *func,
const char *msg)
{
#define SINA(a) (&(((struct sockaddr_in *)(a))->sin_addr.s_addr))
#define SINP(a) ntohs(((struct sockaddr_in *)(a))->sin_port)
#define SIN6A(a) (&(((struct sockaddr_in6 *)(a))->sin6_addr))
#define SIN6P(a) ntohs(((struct sockaddr_in6 *)(a))->sin6_port)
if (c4iw_debug) {
switch (epc->local_addr.ss_family) {
case AF_INET:
PDBG("%s %s %pI4:%u/%u <-> %pI4:%u/%u\n",
func, msg, SINA(&epc->local_addr),
SINP(&epc->local_addr),
SINP(&epc->mapped_local_addr),
SINA(&epc->remote_addr),
SINP(&epc->remote_addr),
SINP(&epc->mapped_remote_addr));
break;
case AF_INET6:
PDBG("%s %s %pI6:%u/%u <-> %pI6:%u/%u\n",
func, msg, SIN6A(&epc->local_addr),
SIN6P(&epc->local_addr),
SIN6P(&epc->mapped_local_addr),
SIN6A(&epc->remote_addr),
SIN6P(&epc->remote_addr),
SIN6P(&epc->mapped_remote_addr));
break;
default:
break;
}
}
#undef SINA
#undef SINP
#undef SIN6A
#undef SIN6P
}
static inline struct c4iw_ep *to_ep(struct iw_cm_id *cm_id) static inline struct c4iw_ep *to_ep(struct iw_cm_id *cm_id)
{ {
return cm_id->provider_data; return cm_id->provider_data;

View file

@ -122,7 +122,7 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev,
INIT_LIST_HEAD(&context->mmaps); INIT_LIST_HEAD(&context->mmaps);
spin_lock_init(&context->mmap_lock); spin_lock_init(&context->mmap_lock);
if (udata->outlen < sizeof(uresp)) { if (udata->outlen < sizeof(uresp) - sizeof(uresp.reserved)) {
if (!warned++) if (!warned++)
pr_err(MOD "Warning - downlevel libcxgb4 (non-fatal), device status page disabled."); pr_err(MOD "Warning - downlevel libcxgb4 (non-fatal), device status page disabled.");
rhp->rdev.flags |= T4_STATUS_PAGE_DISABLED; rhp->rdev.flags |= T4_STATUS_PAGE_DISABLED;
@ -140,7 +140,8 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev,
context->key += PAGE_SIZE; context->key += PAGE_SIZE;
spin_unlock(&context->mmap_lock); spin_unlock(&context->mmap_lock);
ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); ret = ib_copy_to_udata(udata, &uresp,
sizeof(uresp) - sizeof(uresp.reserved));
if (ret) if (ret)
goto err_mm; goto err_mm;

View file

@ -48,6 +48,7 @@ struct c4iw_create_cq_resp {
__u32 cqid; __u32 cqid;
__u32 size; __u32 size;
__u32 qid_mask; __u32 qid_mask;
__u32 reserved; /* explicit padding (optional for i386) */
}; };
@ -74,5 +75,6 @@ struct c4iw_create_qp_resp {
struct c4iw_alloc_ucontext_resp { struct c4iw_alloc_ucontext_resp {
__u64 status_page_key; __u64 status_page_key;
__u32 status_page_size; __u32 status_page_size;
__u32 reserved; /* explicit padding (optional for i386) */
}; };
#endif #endif

View file

@ -346,6 +346,10 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
ret = -EFAULT; ret = -EFAULT;
goto bail; goto bail;
} }
dp.len = odp.len;
dp.unit = odp.unit;
dp.data = odp.data;
dp.pbc_wd = 0;
} else { } else {
ret = -EINVAL; ret = -EINVAL;
goto bail; goto bail;

View file

@ -70,7 +70,7 @@ void ipath_disarm_senderrbufs(struct ipath_devdata *dd)
if (sbuf[0] || sbuf[1] || (piobcnt > 128 && (sbuf[2] || sbuf[3]))) { if (sbuf[0] || sbuf[1] || (piobcnt > 128 && (sbuf[2] || sbuf[3]))) {
int i; int i;
if (ipath_debug & (__IPATH_PKTDBG|__IPATH_DBG) && if (ipath_debug & (__IPATH_PKTDBG|__IPATH_DBG) &&
dd->ipath_lastcancel > jiffies) { time_after(dd->ipath_lastcancel, jiffies)) {
__IPATH_DBG_WHICH(__IPATH_PKTDBG|__IPATH_DBG, __IPATH_DBG_WHICH(__IPATH_PKTDBG|__IPATH_DBG,
"SendbufErrs %lx %lx", sbuf[0], "SendbufErrs %lx %lx", sbuf[0],
sbuf[1]); sbuf[1]);
@ -755,7 +755,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
/* likely due to cancel; so suppress message unless verbose */ /* likely due to cancel; so suppress message unless verbose */
if ((errs & (INFINIPATH_E_SPKTLEN | INFINIPATH_E_SPIOARMLAUNCH)) && if ((errs & (INFINIPATH_E_SPKTLEN | INFINIPATH_E_SPIOARMLAUNCH)) &&
dd->ipath_lastcancel > jiffies) { time_after(dd->ipath_lastcancel, jiffies)) {
/* armlaunch takes precedence; it often causes both. */ /* armlaunch takes precedence; it often causes both. */
ipath_cdbg(VERBOSE, ipath_cdbg(VERBOSE,
"Suppressed %s error (%llx) after sendbuf cancel\n", "Suppressed %s error (%llx) after sendbuf cancel\n",

View file

@ -247,7 +247,7 @@ static void sdma_abort_task(unsigned long opaque)
/* ipath_sdma_abort() is done, waiting for interrupt */ /* ipath_sdma_abort() is done, waiting for interrupt */
if (status == IPATH_SDMA_ABORT_DISARMED) { if (status == IPATH_SDMA_ABORT_DISARMED) {
if (jiffies < dd->ipath_sdma_abort_intr_timeout) if (time_before(jiffies, dd->ipath_sdma_abort_intr_timeout))
goto resched_noprint; goto resched_noprint;
/* give up, intr got lost somewhere */ /* give up, intr got lost somewhere */
ipath_dbg("give up waiting for SDMADISABLED intr\n"); ipath_dbg("give up waiting for SDMADISABLED intr\n");
@ -341,7 +341,7 @@ resched:
* JAG - this is bad to just have default be a loop without * JAG - this is bad to just have default be a loop without
* state change * state change
*/ */
if (jiffies > dd->ipath_sdma_abort_jiffies) { if (time_after(jiffies, dd->ipath_sdma_abort_jiffies)) {
ipath_dbg("looping with status 0x%08lx\n", ipath_dbg("looping with status 0x%08lx\n",
dd->ipath_sdma_status); dd->ipath_sdma_status);
dd->ipath_sdma_abort_jiffies = jiffies + 5 * HZ; dd->ipath_sdma_abort_jiffies = jiffies + 5 * HZ;

View file

@ -73,7 +73,7 @@ static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr
{ {
struct mlx4_ib_dev *ibdev = to_mdev(pd->device); struct mlx4_ib_dev *ibdev = to_mdev(pd->device);
struct mlx4_dev *dev = ibdev->dev; struct mlx4_dev *dev = ibdev->dev;
int is_mcast; int is_mcast = 0;
struct in6_addr in6; struct in6_addr in6;
u16 vlan_tag; u16 vlan_tag;

View file

@ -102,7 +102,7 @@ static int mlx4_ib_alloc_cq_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq_buf *
int err; int err;
err = mlx4_buf_alloc(dev->dev, nent * dev->dev->caps.cqe_size, err = mlx4_buf_alloc(dev->dev, nent * dev->dev->caps.cqe_size,
PAGE_SIZE * 2, &buf->buf); PAGE_SIZE * 2, &buf->buf, GFP_KERNEL);
if (err) if (err)
goto out; goto out;
@ -113,7 +113,7 @@ static int mlx4_ib_alloc_cq_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq_buf *
if (err) if (err)
goto err_buf; goto err_buf;
err = mlx4_buf_write_mtt(dev->dev, &buf->mtt, &buf->buf); err = mlx4_buf_write_mtt(dev->dev, &buf->mtt, &buf->buf, GFP_KERNEL);
if (err) if (err)
goto err_mtt; goto err_mtt;
@ -209,7 +209,7 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector
uar = &to_mucontext(context)->uar; uar = &to_mucontext(context)->uar;
} else { } else {
err = mlx4_db_alloc(dev->dev, &cq->db, 1); err = mlx4_db_alloc(dev->dev, &cq->db, 1, GFP_KERNEL);
if (err) if (err)
goto err_cq; goto err_cq;

View file

@ -478,10 +478,6 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
if (!tun_ctx || tun_ctx->state != DEMUX_PV_STATE_ACTIVE) if (!tun_ctx || tun_ctx->state != DEMUX_PV_STATE_ACTIVE)
return -EAGAIN; return -EAGAIN;
/* QP0 forwarding only for Dom0 */
if (!dest_qpt && (mlx4_master_func_num(dev->dev) != slave))
return -EINVAL;
if (!dest_qpt) if (!dest_qpt)
tun_qp = &tun_ctx->qp[0]; tun_qp = &tun_ctx->qp[0];
else else
@ -667,6 +663,21 @@ static int mlx4_ib_demux_mad(struct ib_device *ibdev, u8 port,
} }
/* Class-specific handling */ /* Class-specific handling */
switch (mad->mad_hdr.mgmt_class) { switch (mad->mad_hdr.mgmt_class) {
case IB_MGMT_CLASS_SUBN_LID_ROUTED:
case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE:
/* 255 indicates the dom0 */
if (slave != 255 && slave != mlx4_master_func_num(dev->dev)) {
if (!mlx4_vf_smi_enabled(dev->dev, slave, port))
return -EPERM;
/* for a VF. drop unsolicited MADs */
if (!(mad->mad_hdr.method & IB_MGMT_METHOD_RESP)) {
mlx4_ib_warn(ibdev, "demux QP0. rejecting unsolicited mad for slave %d class 0x%x, method 0x%x\n",
slave, mad->mad_hdr.mgmt_class,
mad->mad_hdr.method);
return -EINVAL;
}
}
break;
case IB_MGMT_CLASS_SUBN_ADM: case IB_MGMT_CLASS_SUBN_ADM:
if (mlx4_ib_demux_sa_handler(ibdev, port, slave, if (mlx4_ib_demux_sa_handler(ibdev, port, slave,
(struct ib_sa_mad *) mad)) (struct ib_sa_mad *) mad))
@ -1165,10 +1176,6 @@ int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port,
if (!sqp_ctx || sqp_ctx->state != DEMUX_PV_STATE_ACTIVE) if (!sqp_ctx || sqp_ctx->state != DEMUX_PV_STATE_ACTIVE)
return -EAGAIN; return -EAGAIN;
/* QP0 forwarding only for Dom0 */
if (dest_qpt == IB_QPT_SMI && (mlx4_master_func_num(dev->dev) != slave))
return -EINVAL;
if (dest_qpt == IB_QPT_SMI) { if (dest_qpt == IB_QPT_SMI) {
src_qpnum = 0; src_qpnum = 0;
sqp = &sqp_ctx->qp[0]; sqp = &sqp_ctx->qp[0];
@ -1285,11 +1292,6 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc
"belongs to another slave\n", wc->src_qp); "belongs to another slave\n", wc->src_qp);
return; return;
} }
if (slave != mlx4_master_func_num(dev->dev) && !(wc->src_qp & 0x2)) {
mlx4_ib_warn(ctx->ib_dev, "can't multiplex bad sqp:%d: "
"non-master trying to send QP0 packets\n", wc->src_qp);
return;
}
/* Map transaction ID */ /* Map transaction ID */
ib_dma_sync_single_for_cpu(ctx->ib_dev, tun_qp->ring[wr_ix].map, ib_dma_sync_single_for_cpu(ctx->ib_dev, tun_qp->ring[wr_ix].map,
@ -1317,6 +1319,12 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc
/* Class-specific handling */ /* Class-specific handling */
switch (tunnel->mad.mad_hdr.mgmt_class) { switch (tunnel->mad.mad_hdr.mgmt_class) {
case IB_MGMT_CLASS_SUBN_LID_ROUTED:
case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE:
if (slave != mlx4_master_func_num(dev->dev) &&
!mlx4_vf_smi_enabled(dev->dev, slave, ctx->port))
return;
break;
case IB_MGMT_CLASS_SUBN_ADM: case IB_MGMT_CLASS_SUBN_ADM:
if (mlx4_ib_multiplex_sa_handler(ctx->ib_dev, ctx->port, slave, if (mlx4_ib_multiplex_sa_handler(ctx->ib_dev, ctx->port, slave,
(struct ib_sa_mad *) &tunnel->mad)) (struct ib_sa_mad *) &tunnel->mad))
@ -1749,9 +1757,9 @@ static int create_pv_resources(struct ib_device *ibdev, int slave, int port,
return -EEXIST; return -EEXIST;
ctx->state = DEMUX_PV_STATE_STARTING; ctx->state = DEMUX_PV_STATE_STARTING;
/* have QP0 only on port owner, and only if link layer is IB */ /* have QP0 only if link layer is IB */
if (ctx->slave == mlx4_master_func_num(to_mdev(ctx->ib_dev)->dev) && if (rdma_port_get_link_layer(ibdev, ctx->port) ==
rdma_port_get_link_layer(ibdev, ctx->port) == IB_LINK_LAYER_INFINIBAND) IB_LINK_LAYER_INFINIBAND)
ctx->has_smi = 1; ctx->has_smi = 1;
if (ctx->has_smi) { if (ctx->has_smi) {

View file

@ -545,12 +545,11 @@ static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
return 0; return 0;
} }
static int mlx4_SET_PORT(struct mlx4_ib_dev *dev, u8 port, int reset_qkey_viols, static int mlx4_ib_SET_PORT(struct mlx4_ib_dev *dev, u8 port, int reset_qkey_viols,
u32 cap_mask) u32 cap_mask)
{ {
struct mlx4_cmd_mailbox *mailbox; struct mlx4_cmd_mailbox *mailbox;
int err; int err;
u8 is_eth = dev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH;
mailbox = mlx4_alloc_cmd_mailbox(dev->dev); mailbox = mlx4_alloc_cmd_mailbox(dev->dev);
if (IS_ERR(mailbox)) if (IS_ERR(mailbox))
@ -564,8 +563,8 @@ static int mlx4_SET_PORT(struct mlx4_ib_dev *dev, u8 port, int reset_qkey_viols,
((__be32 *) mailbox->buf)[1] = cpu_to_be32(cap_mask); ((__be32 *) mailbox->buf)[1] = cpu_to_be32(cap_mask);
} }
err = mlx4_cmd(dev->dev, mailbox->dma, port, is_eth, MLX4_CMD_SET_PORT, err = mlx4_cmd(dev->dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT,
MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED);
mlx4_free_cmd_mailbox(dev->dev, mailbox); mlx4_free_cmd_mailbox(dev->dev, mailbox);
return err; return err;
@ -574,11 +573,20 @@ static int mlx4_SET_PORT(struct mlx4_ib_dev *dev, u8 port, int reset_qkey_viols,
static int mlx4_ib_modify_port(struct ib_device *ibdev, u8 port, int mask, static int mlx4_ib_modify_port(struct ib_device *ibdev, u8 port, int mask,
struct ib_port_modify *props) struct ib_port_modify *props)
{ {
struct mlx4_ib_dev *mdev = to_mdev(ibdev);
u8 is_eth = mdev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH;
struct ib_port_attr attr; struct ib_port_attr attr;
u32 cap_mask; u32 cap_mask;
int err; int err;
mutex_lock(&to_mdev(ibdev)->cap_mask_mutex); /* return OK if this is RoCE. CM calls ib_modify_port() regardless
* of whether port link layer is ETH or IB. For ETH ports, qkey
* violations and port capabilities are not meaningful.
*/
if (is_eth)
return 0;
mutex_lock(&mdev->cap_mask_mutex);
err = mlx4_ib_query_port(ibdev, port, &attr); err = mlx4_ib_query_port(ibdev, port, &attr);
if (err) if (err)
@ -587,9 +595,9 @@ static int mlx4_ib_modify_port(struct ib_device *ibdev, u8 port, int mask,
cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) & cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) &
~props->clr_port_cap_mask; ~props->clr_port_cap_mask;
err = mlx4_SET_PORT(to_mdev(ibdev), port, err = mlx4_ib_SET_PORT(mdev, port,
!!(mask & IB_PORT_RESET_QKEY_CNTR), !!(mask & IB_PORT_RESET_QKEY_CNTR),
cap_mask); cap_mask);
out: out:
mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex); mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex);

View file

@ -156,6 +156,7 @@ enum mlx4_ib_qp_flags {
MLX4_IB_QP_LSO = IB_QP_CREATE_IPOIB_UD_LSO, MLX4_IB_QP_LSO = IB_QP_CREATE_IPOIB_UD_LSO,
MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK = IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK, MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK = IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK,
MLX4_IB_QP_NETIF = IB_QP_CREATE_NETIF_QP, MLX4_IB_QP_NETIF = IB_QP_CREATE_NETIF_QP,
MLX4_IB_QP_CREATE_USE_GFP_NOIO = IB_QP_CREATE_USE_GFP_NOIO,
MLX4_IB_SRIOV_TUNNEL_QP = 1 << 30, MLX4_IB_SRIOV_TUNNEL_QP = 1 << 30,
MLX4_IB_SRIOV_SQP = 1 << 31, MLX4_IB_SRIOV_SQP = 1 << 31,
}; };

View file

@ -608,9 +608,20 @@ static int qp_has_rq(struct ib_qp_init_attr *attr)
return !attr->srq; return !attr->srq;
} }
static int qp0_enabled_vf(struct mlx4_dev *dev, int qpn)
{
int i;
for (i = 0; i < dev->caps.num_ports; i++) {
if (qpn == dev->caps.qp0_proxy[i])
return !!dev->caps.qp0_qkey[i];
}
return 0;
}
static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
struct ib_qp_init_attr *init_attr, struct ib_qp_init_attr *init_attr,
struct ib_udata *udata, int sqpn, struct mlx4_ib_qp **caller_qp) struct ib_udata *udata, int sqpn, struct mlx4_ib_qp **caller_qp,
gfp_t gfp)
{ {
int qpn; int qpn;
int err; int err;
@ -625,10 +636,13 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
!(init_attr->create_flags & MLX4_IB_SRIOV_SQP))) { !(init_attr->create_flags & MLX4_IB_SRIOV_SQP))) {
if (init_attr->qp_type == IB_QPT_GSI) if (init_attr->qp_type == IB_QPT_GSI)
qp_type = MLX4_IB_QPT_PROXY_GSI; qp_type = MLX4_IB_QPT_PROXY_GSI;
else if (mlx4_is_master(dev->dev)) else {
qp_type = MLX4_IB_QPT_PROXY_SMI_OWNER; if (mlx4_is_master(dev->dev) ||
else qp0_enabled_vf(dev->dev, sqpn))
qp_type = MLX4_IB_QPT_PROXY_SMI; qp_type = MLX4_IB_QPT_PROXY_SMI_OWNER;
else
qp_type = MLX4_IB_QPT_PROXY_SMI;
}
} }
qpn = sqpn; qpn = sqpn;
/* add extra sg entry for tunneling */ /* add extra sg entry for tunneling */
@ -643,7 +657,9 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
return -EINVAL; return -EINVAL;
if (tnl_init->proxy_qp_type == IB_QPT_GSI) if (tnl_init->proxy_qp_type == IB_QPT_GSI)
qp_type = MLX4_IB_QPT_TUN_GSI; qp_type = MLX4_IB_QPT_TUN_GSI;
else if (tnl_init->slave == mlx4_master_func_num(dev->dev)) else if (tnl_init->slave == mlx4_master_func_num(dev->dev) ||
mlx4_vf_smi_enabled(dev->dev, tnl_init->slave,
tnl_init->port))
qp_type = MLX4_IB_QPT_TUN_SMI_OWNER; qp_type = MLX4_IB_QPT_TUN_SMI_OWNER;
else else
qp_type = MLX4_IB_QPT_TUN_SMI; qp_type = MLX4_IB_QPT_TUN_SMI;
@ -658,14 +674,14 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
if (qp_type == MLX4_IB_QPT_SMI || qp_type == MLX4_IB_QPT_GSI || if (qp_type == MLX4_IB_QPT_SMI || qp_type == MLX4_IB_QPT_GSI ||
(qp_type & (MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_SMI_OWNER | (qp_type & (MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_SMI_OWNER |
MLX4_IB_QPT_PROXY_GSI | MLX4_IB_QPT_TUN_SMI_OWNER))) { MLX4_IB_QPT_PROXY_GSI | MLX4_IB_QPT_TUN_SMI_OWNER))) {
sqp = kzalloc(sizeof (struct mlx4_ib_sqp), GFP_KERNEL); sqp = kzalloc(sizeof (struct mlx4_ib_sqp), gfp);
if (!sqp) if (!sqp)
return -ENOMEM; return -ENOMEM;
qp = &sqp->qp; qp = &sqp->qp;
qp->pri.vid = 0xFFFF; qp->pri.vid = 0xFFFF;
qp->alt.vid = 0xFFFF; qp->alt.vid = 0xFFFF;
} else { } else {
qp = kzalloc(sizeof (struct mlx4_ib_qp), GFP_KERNEL); qp = kzalloc(sizeof (struct mlx4_ib_qp), gfp);
if (!qp) if (!qp)
return -ENOMEM; return -ENOMEM;
qp->pri.vid = 0xFFFF; qp->pri.vid = 0xFFFF;
@ -748,14 +764,14 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
goto err; goto err;
if (qp_has_rq(init_attr)) { if (qp_has_rq(init_attr)) {
err = mlx4_db_alloc(dev->dev, &qp->db, 0); err = mlx4_db_alloc(dev->dev, &qp->db, 0, gfp);
if (err) if (err)
goto err; goto err;
*qp->db.db = 0; *qp->db.db = 0;
} }
if (mlx4_buf_alloc(dev->dev, qp->buf_size, PAGE_SIZE * 2, &qp->buf)) { if (mlx4_buf_alloc(dev->dev, qp->buf_size, PAGE_SIZE * 2, &qp->buf, gfp)) {
err = -ENOMEM; err = -ENOMEM;
goto err_db; goto err_db;
} }
@ -765,13 +781,12 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
if (err) if (err)
goto err_buf; goto err_buf;
err = mlx4_buf_write_mtt(dev->dev, &qp->mtt, &qp->buf); err = mlx4_buf_write_mtt(dev->dev, &qp->mtt, &qp->buf, gfp);
if (err) if (err)
goto err_mtt; goto err_mtt;
qp->sq.wrid = kmalloc(qp->sq.wqe_cnt * sizeof (u64), GFP_KERNEL); qp->sq.wrid = kmalloc(qp->sq.wqe_cnt * sizeof (u64), gfp);
qp->rq.wrid = kmalloc(qp->rq.wqe_cnt * sizeof (u64), GFP_KERNEL); qp->rq.wrid = kmalloc(qp->rq.wqe_cnt * sizeof (u64), gfp);
if (!qp->sq.wrid || !qp->rq.wrid) { if (!qp->sq.wrid || !qp->rq.wrid) {
err = -ENOMEM; err = -ENOMEM;
goto err_wrid; goto err_wrid;
@ -801,7 +816,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
goto err_proxy; goto err_proxy;
} }
err = mlx4_qp_alloc(dev->dev, qpn, &qp->mqp); err = mlx4_qp_alloc(dev->dev, qpn, &qp->mqp, gfp);
if (err) if (err)
goto err_qpn; goto err_qpn;
@ -1040,7 +1055,10 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
struct mlx4_ib_qp *qp = NULL; struct mlx4_ib_qp *qp = NULL;
int err; int err;
u16 xrcdn = 0; u16 xrcdn = 0;
gfp_t gfp;
gfp = (init_attr->create_flags & MLX4_IB_QP_CREATE_USE_GFP_NOIO) ?
GFP_NOIO : GFP_KERNEL;
/* /*
* We only support LSO, vendor flag1, and multicast loopback blocking, * We only support LSO, vendor flag1, and multicast loopback blocking,
* and only for kernel UD QPs. * and only for kernel UD QPs.
@ -1049,7 +1067,8 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK | MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK |
MLX4_IB_SRIOV_TUNNEL_QP | MLX4_IB_SRIOV_TUNNEL_QP |
MLX4_IB_SRIOV_SQP | MLX4_IB_SRIOV_SQP |
MLX4_IB_QP_NETIF)) MLX4_IB_QP_NETIF |
MLX4_IB_QP_CREATE_USE_GFP_NOIO))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if (init_attr->create_flags & IB_QP_CREATE_NETIF_QP) { if (init_attr->create_flags & IB_QP_CREATE_NETIF_QP) {
@ -1059,7 +1078,7 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
if (init_attr->create_flags && if (init_attr->create_flags &&
(udata || (udata ||
((init_attr->create_flags & ~MLX4_IB_SRIOV_SQP) && ((init_attr->create_flags & ~(MLX4_IB_SRIOV_SQP | MLX4_IB_QP_CREATE_USE_GFP_NOIO)) &&
init_attr->qp_type != IB_QPT_UD) || init_attr->qp_type != IB_QPT_UD) ||
((init_attr->create_flags & MLX4_IB_SRIOV_SQP) && ((init_attr->create_flags & MLX4_IB_SRIOV_SQP) &&
init_attr->qp_type > IB_QPT_GSI))) init_attr->qp_type > IB_QPT_GSI)))
@ -1079,7 +1098,7 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
case IB_QPT_RC: case IB_QPT_RC:
case IB_QPT_UC: case IB_QPT_UC:
case IB_QPT_RAW_PACKET: case IB_QPT_RAW_PACKET:
qp = kzalloc(sizeof *qp, GFP_KERNEL); qp = kzalloc(sizeof *qp, gfp);
if (!qp) if (!qp)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
qp->pri.vid = 0xFFFF; qp->pri.vid = 0xFFFF;
@ -1088,7 +1107,7 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
case IB_QPT_UD: case IB_QPT_UD:
{ {
err = create_qp_common(to_mdev(pd->device), pd, init_attr, err = create_qp_common(to_mdev(pd->device), pd, init_attr,
udata, 0, &qp); udata, 0, &qp, gfp);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
@ -1106,7 +1125,7 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
err = create_qp_common(to_mdev(pd->device), pd, init_attr, udata, err = create_qp_common(to_mdev(pd->device), pd, init_attr, udata,
get_sqp_num(to_mdev(pd->device), init_attr), get_sqp_num(to_mdev(pd->device), init_attr),
&qp); &qp, gfp);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
@ -1938,6 +1957,19 @@ out:
return err; return err;
} }
static int vf_get_qp0_qkey(struct mlx4_dev *dev, int qpn, u32 *qkey)
{
int i;
for (i = 0; i < dev->caps.num_ports; i++) {
if (qpn == dev->caps.qp0_proxy[i] ||
qpn == dev->caps.qp0_tunnel[i]) {
*qkey = dev->caps.qp0_qkey[i];
return 0;
}
}
return -EINVAL;
}
static int build_sriov_qp0_header(struct mlx4_ib_sqp *sqp, static int build_sriov_qp0_header(struct mlx4_ib_sqp *sqp,
struct ib_send_wr *wr, struct ib_send_wr *wr,
void *wqe, unsigned *mlx_seg_len) void *wqe, unsigned *mlx_seg_len)
@ -1995,8 +2027,13 @@ static int build_sriov_qp0_header(struct mlx4_ib_sqp *sqp,
cpu_to_be32(mdev->dev->caps.qp0_tunnel[sqp->qp.port - 1]); cpu_to_be32(mdev->dev->caps.qp0_tunnel[sqp->qp.port - 1]);
sqp->ud_header.bth.psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1)); sqp->ud_header.bth.psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1));
if (mlx4_get_parav_qkey(mdev->dev, sqp->qp.mqp.qpn, &qkey)) if (mlx4_is_master(mdev->dev)) {
return -EINVAL; if (mlx4_get_parav_qkey(mdev->dev, sqp->qp.mqp.qpn, &qkey))
return -EINVAL;
} else {
if (vf_get_qp0_qkey(mdev->dev, sqp->qp.mqp.qpn, &qkey))
return -EINVAL;
}
sqp->ud_header.deth.qkey = cpu_to_be32(qkey); sqp->ud_header.deth.qkey = cpu_to_be32(qkey);
sqp->ud_header.deth.source_qpn = cpu_to_be32(sqp->qp.mqp.qpn); sqp->ud_header.deth.source_qpn = cpu_to_be32(sqp->qp.mqp.qpn);
@ -2378,7 +2415,8 @@ static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg,
static void set_tunnel_datagram_seg(struct mlx4_ib_dev *dev, static void set_tunnel_datagram_seg(struct mlx4_ib_dev *dev,
struct mlx4_wqe_datagram_seg *dseg, struct mlx4_wqe_datagram_seg *dseg,
struct ib_send_wr *wr, enum ib_qp_type qpt) struct ib_send_wr *wr,
enum mlx4_ib_qp_type qpt)
{ {
union mlx4_ext_av *av = &to_mah(wr->wr.ud.ah)->av; union mlx4_ext_av *av = &to_mah(wr->wr.ud.ah)->av;
struct mlx4_av sqp_av = {0}; struct mlx4_av sqp_av = {0};
@ -2391,8 +2429,10 @@ static void set_tunnel_datagram_seg(struct mlx4_ib_dev *dev,
cpu_to_be32(0xf0000000); cpu_to_be32(0xf0000000);
memcpy(dseg->av, &sqp_av, sizeof (struct mlx4_av)); memcpy(dseg->av, &sqp_av, sizeof (struct mlx4_av));
/* This function used only for sending on QP1 proxies */ if (qpt == MLX4_IB_QPT_PROXY_GSI)
dseg->dqpn = cpu_to_be32(dev->dev->caps.qp1_tunnel[port - 1]); dseg->dqpn = cpu_to_be32(dev->dev->caps.qp1_tunnel[port - 1]);
else
dseg->dqpn = cpu_to_be32(dev->dev->caps.qp0_tunnel[port - 1]);
/* Use QKEY from the QP context, which is set by master */ /* Use QKEY from the QP context, which is set by master */
dseg->qkey = cpu_to_be32(IB_QP_SET_QKEY); dseg->qkey = cpu_to_be32(IB_QP_SET_QKEY);
} }
@ -2687,11 +2727,6 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
break; break;
case MLX4_IB_QPT_PROXY_SMI_OWNER: case MLX4_IB_QPT_PROXY_SMI_OWNER:
if (unlikely(!mlx4_is_master(to_mdev(ibqp->device)->dev))) {
err = -ENOSYS;
*bad_wr = wr;
goto out;
}
err = build_sriov_qp0_header(to_msqp(qp), wr, ctrl, &seglen); err = build_sriov_qp0_header(to_msqp(qp), wr, ctrl, &seglen);
if (unlikely(err)) { if (unlikely(err)) {
*bad_wr = wr; *bad_wr = wr;
@ -2708,16 +2743,13 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
size += seglen / 16; size += seglen / 16;
break; break;
case MLX4_IB_QPT_PROXY_SMI: case MLX4_IB_QPT_PROXY_SMI:
/* don't allow QP0 sends on guests */
err = -ENOSYS;
*bad_wr = wr;
goto out;
case MLX4_IB_QPT_PROXY_GSI: case MLX4_IB_QPT_PROXY_GSI:
/* If we are tunneling special qps, this is a UD qp. /* If we are tunneling special qps, this is a UD qp.
* In this case we first add a UD segment targeting * In this case we first add a UD segment targeting
* the tunnel qp, and then add a header with address * the tunnel qp, and then add a header with address
* information */ * information */
set_tunnel_datagram_seg(to_mdev(ibqp->device), wqe, wr, ibqp->qp_type); set_tunnel_datagram_seg(to_mdev(ibqp->device), wqe, wr,
qp->mlx4_ib_qp_type);
wqe += sizeof (struct mlx4_wqe_datagram_seg); wqe += sizeof (struct mlx4_wqe_datagram_seg);
size += sizeof (struct mlx4_wqe_datagram_seg) / 16; size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
build_tunnel_header(wr, wqe, &seglen); build_tunnel_header(wr, wqe, &seglen);

View file

@ -134,13 +134,14 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd,
if (err) if (err)
goto err_mtt; goto err_mtt;
} else { } else {
err = mlx4_db_alloc(dev->dev, &srq->db, 0); err = mlx4_db_alloc(dev->dev, &srq->db, 0, GFP_KERNEL);
if (err) if (err)
goto err_srq; goto err_srq;
*srq->db.db = 0; *srq->db.db = 0;
if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2, &srq->buf)) { if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2, &srq->buf,
GFP_KERNEL)) {
err = -ENOMEM; err = -ENOMEM;
goto err_db; goto err_db;
} }
@ -165,7 +166,7 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd,
if (err) if (err)
goto err_buf; goto err_buf;
err = mlx4_buf_write_mtt(dev->dev, &srq->mtt, &srq->buf); err = mlx4_buf_write_mtt(dev->dev, &srq->mtt, &srq->buf, GFP_KERNEL);
if (err) if (err)
goto err_mtt; goto err_mtt;

View file

@ -389,8 +389,10 @@ struct mlx4_port {
struct mlx4_ib_dev *dev; struct mlx4_ib_dev *dev;
struct attribute_group pkey_group; struct attribute_group pkey_group;
struct attribute_group gid_group; struct attribute_group gid_group;
u8 port_num; struct device_attribute enable_smi_admin;
struct device_attribute smi_enabled;
int slave; int slave;
u8 port_num;
}; };
@ -558,6 +560,101 @@ err:
return NULL; return NULL;
} }
static ssize_t sysfs_show_smi_enabled(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mlx4_port *p =
container_of(attr, struct mlx4_port, smi_enabled);
ssize_t len = 0;
if (mlx4_vf_smi_enabled(p->dev->dev, p->slave, p->port_num))
len = sprintf(buf, "%d\n", 1);
else
len = sprintf(buf, "%d\n", 0);
return len;
}
static ssize_t sysfs_show_enable_smi_admin(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct mlx4_port *p =
container_of(attr, struct mlx4_port, enable_smi_admin);
ssize_t len = 0;
if (mlx4_vf_get_enable_smi_admin(p->dev->dev, p->slave, p->port_num))
len = sprintf(buf, "%d\n", 1);
else
len = sprintf(buf, "%d\n", 0);
return len;
}
static ssize_t sysfs_store_enable_smi_admin(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct mlx4_port *p =
container_of(attr, struct mlx4_port, enable_smi_admin);
int enable;
if (sscanf(buf, "%i", &enable) != 1 ||
enable < 0 || enable > 1)
return -EINVAL;
if (mlx4_vf_set_enable_smi_admin(p->dev->dev, p->slave, p->port_num, enable))
return -EINVAL;
return count;
}
static int add_vf_smi_entries(struct mlx4_port *p)
{
int is_eth = rdma_port_get_link_layer(&p->dev->ib_dev, p->port_num) ==
IB_LINK_LAYER_ETHERNET;
int ret;
/* do not display entries if eth transport, or if master */
if (is_eth || p->slave == mlx4_master_func_num(p->dev->dev))
return 0;
sysfs_attr_init(&p->smi_enabled.attr);
p->smi_enabled.show = sysfs_show_smi_enabled;
p->smi_enabled.store = NULL;
p->smi_enabled.attr.name = "smi_enabled";
p->smi_enabled.attr.mode = 0444;
ret = sysfs_create_file(&p->kobj, &p->smi_enabled.attr);
if (ret) {
pr_err("failed to create smi_enabled\n");
return ret;
}
sysfs_attr_init(&p->enable_smi_admin.attr);
p->enable_smi_admin.show = sysfs_show_enable_smi_admin;
p->enable_smi_admin.store = sysfs_store_enable_smi_admin;
p->enable_smi_admin.attr.name = "enable_smi_admin";
p->enable_smi_admin.attr.mode = 0644;
ret = sysfs_create_file(&p->kobj, &p->enable_smi_admin.attr);
if (ret) {
pr_err("failed to create enable_smi_admin\n");
sysfs_remove_file(&p->kobj, &p->smi_enabled.attr);
return ret;
}
return 0;
}
static void remove_vf_smi_entries(struct mlx4_port *p)
{
int is_eth = rdma_port_get_link_layer(&p->dev->ib_dev, p->port_num) ==
IB_LINK_LAYER_ETHERNET;
if (is_eth || p->slave == mlx4_master_func_num(p->dev->dev))
return;
sysfs_remove_file(&p->kobj, &p->smi_enabled.attr);
sysfs_remove_file(&p->kobj, &p->enable_smi_admin.attr);
}
static int add_port(struct mlx4_ib_dev *dev, int port_num, int slave) static int add_port(struct mlx4_ib_dev *dev, int port_num, int slave)
{ {
struct mlx4_port *p; struct mlx4_port *p;
@ -602,6 +699,10 @@ static int add_port(struct mlx4_ib_dev *dev, int port_num, int slave)
if (ret) if (ret)
goto err_free_gid; goto err_free_gid;
ret = add_vf_smi_entries(p);
if (ret)
goto err_free_gid;
list_add_tail(&p->kobj.entry, &dev->pkeys.pkey_port_list[slave]); list_add_tail(&p->kobj.entry, &dev->pkeys.pkey_port_list[slave]);
return 0; return 0;
@ -669,6 +770,7 @@ err_add:
mport = container_of(p, struct mlx4_port, kobj); mport = container_of(p, struct mlx4_port, kobj);
sysfs_remove_group(p, &mport->pkey_group); sysfs_remove_group(p, &mport->pkey_group);
sysfs_remove_group(p, &mport->gid_group); sysfs_remove_group(p, &mport->gid_group);
remove_vf_smi_entries(mport);
kobject_put(p); kobject_put(p);
} }
kobject_put(dev->dev_ports_parent[slave]); kobject_put(dev->dev_ports_parent[slave]);
@ -713,6 +815,7 @@ static void unregister_pkey_tree(struct mlx4_ib_dev *device)
port = container_of(p, struct mlx4_port, kobj); port = container_of(p, struct mlx4_port, kobj);
sysfs_remove_group(p, &port->pkey_group); sysfs_remove_group(p, &port->pkey_group);
sysfs_remove_group(p, &port->gid_group); sysfs_remove_group(p, &port->gid_group);
remove_vf_smi_entries(port);
kobject_put(p); kobject_put(p);
kobject_put(device->dev_ports_parent[slave]); kobject_put(device->dev_ports_parent[slave]);
} }

View file

@ -32,6 +32,7 @@
#include <linux/kref.h> #include <linux/kref.h>
#include <rdma/ib_umem.h> #include <rdma/ib_umem.h>
#include <rdma/ib_user_verbs.h>
#include "mlx5_ib.h" #include "mlx5_ib.h"
#include "user.h" #include "user.h"
@ -602,14 +603,24 @@ static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata,
int *cqe_size, int *index, int *inlen) int *cqe_size, int *index, int *inlen)
{ {
struct mlx5_ib_create_cq ucmd; struct mlx5_ib_create_cq ucmd;
size_t ucmdlen;
int page_shift; int page_shift;
int npages; int npages;
int ncont; int ncont;
int err; int err;
if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) ucmdlen =
(udata->inlen - sizeof(struct ib_uverbs_cmd_hdr) <
sizeof(ucmd)) ? (sizeof(ucmd) -
sizeof(ucmd.reserved)) : sizeof(ucmd);
if (ib_copy_from_udata(&ucmd, udata, ucmdlen))
return -EFAULT; return -EFAULT;
if (ucmdlen == sizeof(ucmd) &&
ucmd.reserved != 0)
return -EINVAL;
if (ucmd.cqe_size != 64 && ucmd.cqe_size != 128) if (ucmd.cqe_size != 64 && ucmd.cqe_size != 128)
return -EINVAL; return -EINVAL;

View file

@ -264,8 +264,6 @@ struct mlx5_ib_mr {
__be64 *pas; __be64 *pas;
dma_addr_t dma; dma_addr_t dma;
int npages; int npages;
struct completion done;
enum ib_wc_status status;
struct mlx5_ib_dev *dev; struct mlx5_ib_dev *dev;
struct mlx5_create_mkey_mbox_out out; struct mlx5_create_mkey_mbox_out out;
struct mlx5_core_sig_ctx *sig; struct mlx5_core_sig_ctx *sig;
@ -277,6 +275,17 @@ struct mlx5_ib_fast_reg_page_list {
dma_addr_t map; dma_addr_t map;
}; };
struct mlx5_ib_umr_context {
enum ib_wc_status status;
struct completion done;
};
static inline void mlx5_ib_init_umr_context(struct mlx5_ib_umr_context *context)
{
context->status = -1;
init_completion(&context->done);
}
struct umr_common { struct umr_common {
struct ib_pd *pd; struct ib_pd *pd;
struct ib_cq *cq; struct ib_cq *cq;

View file

@ -73,6 +73,8 @@ static void reg_mr_callback(int status, void *context)
struct mlx5_cache_ent *ent = &cache->ent[c]; struct mlx5_cache_ent *ent = &cache->ent[c];
u8 key; u8 key;
unsigned long flags; unsigned long flags;
struct mlx5_mr_table *table = &dev->mdev.priv.mr_table;
int err;
spin_lock_irqsave(&ent->lock, flags); spin_lock_irqsave(&ent->lock, flags);
ent->pending--; ent->pending--;
@ -107,6 +109,13 @@ static void reg_mr_callback(int status, void *context)
ent->cur++; ent->cur++;
ent->size++; ent->size++;
spin_unlock_irqrestore(&ent->lock, flags); spin_unlock_irqrestore(&ent->lock, flags);
write_lock_irqsave(&table->lock, flags);
err = radix_tree_insert(&table->tree, mlx5_base_mkey(mr->mmr.key),
&mr->mmr);
if (err)
pr_err("Error inserting to mr tree. 0x%x\n", -err);
write_unlock_irqrestore(&table->lock, flags);
} }
static int add_keys(struct mlx5_ib_dev *dev, int c, int num) static int add_keys(struct mlx5_ib_dev *dev, int c, int num)
@ -699,7 +708,7 @@ static void prep_umr_unreg_wqe(struct mlx5_ib_dev *dev,
void mlx5_umr_cq_handler(struct ib_cq *cq, void *cq_context) void mlx5_umr_cq_handler(struct ib_cq *cq, void *cq_context)
{ {
struct mlx5_ib_mr *mr; struct mlx5_ib_umr_context *context;
struct ib_wc wc; struct ib_wc wc;
int err; int err;
@ -712,9 +721,9 @@ void mlx5_umr_cq_handler(struct ib_cq *cq, void *cq_context)
if (err == 0) if (err == 0)
break; break;
mr = (struct mlx5_ib_mr *)(unsigned long)wc.wr_id; context = (struct mlx5_ib_umr_context *) (unsigned long) wc.wr_id;
mr->status = wc.status; context->status = wc.status;
complete(&mr->done); complete(&context->done);
} }
ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
} }
@ -726,11 +735,12 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
struct mlx5_ib_dev *dev = to_mdev(pd->device); struct mlx5_ib_dev *dev = to_mdev(pd->device);
struct device *ddev = dev->ib_dev.dma_device; struct device *ddev = dev->ib_dev.dma_device;
struct umr_common *umrc = &dev->umrc; struct umr_common *umrc = &dev->umrc;
struct mlx5_ib_umr_context umr_context;
struct ib_send_wr wr, *bad; struct ib_send_wr wr, *bad;
struct mlx5_ib_mr *mr; struct mlx5_ib_mr *mr;
struct ib_sge sg; struct ib_sge sg;
int size = sizeof(u64) * npages; int size = sizeof(u64) * npages;
int err; int err = 0;
int i; int i;
for (i = 0; i < 1; i++) { for (i = 0; i < 1; i++) {
@ -751,7 +761,7 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
mr->pas = kmalloc(size + MLX5_UMR_ALIGN - 1, GFP_KERNEL); mr->pas = kmalloc(size + MLX5_UMR_ALIGN - 1, GFP_KERNEL);
if (!mr->pas) { if (!mr->pas) {
err = -ENOMEM; err = -ENOMEM;
goto error; goto free_mr;
} }
mlx5_ib_populate_pas(dev, umem, page_shift, mlx5_ib_populate_pas(dev, umem, page_shift,
@ -760,44 +770,46 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
mr->dma = dma_map_single(ddev, mr_align(mr->pas, MLX5_UMR_ALIGN), size, mr->dma = dma_map_single(ddev, mr_align(mr->pas, MLX5_UMR_ALIGN), size,
DMA_TO_DEVICE); DMA_TO_DEVICE);
if (dma_mapping_error(ddev, mr->dma)) { if (dma_mapping_error(ddev, mr->dma)) {
kfree(mr->pas);
err = -ENOMEM; err = -ENOMEM;
goto error; goto free_pas;
} }
memset(&wr, 0, sizeof(wr)); memset(&wr, 0, sizeof(wr));
wr.wr_id = (u64)(unsigned long)mr; wr.wr_id = (u64)(unsigned long)&umr_context;
prep_umr_reg_wqe(pd, &wr, &sg, mr->dma, npages, mr->mmr.key, page_shift, virt_addr, len, access_flags); prep_umr_reg_wqe(pd, &wr, &sg, mr->dma, npages, mr->mmr.key, page_shift, virt_addr, len, access_flags);
/* We serialize polls so one process does not kidnap another's mlx5_ib_init_umr_context(&umr_context);
* completion. This is not a problem since wr is completed in
* around 1 usec
*/
down(&umrc->sem); down(&umrc->sem);
init_completion(&mr->done);
err = ib_post_send(umrc->qp, &wr, &bad); err = ib_post_send(umrc->qp, &wr, &bad);
if (err) { if (err) {
mlx5_ib_warn(dev, "post send failed, err %d\n", err); mlx5_ib_warn(dev, "post send failed, err %d\n", err);
up(&umrc->sem); goto unmap_dma;
goto error; } else {
wait_for_completion(&umr_context.done);
if (umr_context.status != IB_WC_SUCCESS) {
mlx5_ib_warn(dev, "reg umr failed\n");
err = -EFAULT;
}
} }
wait_for_completion(&mr->done);
up(&umrc->sem);
mr->mmr.iova = virt_addr;
mr->mmr.size = len;
mr->mmr.pd = to_mpd(pd)->pdn;
unmap_dma:
up(&umrc->sem);
dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE); dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
free_pas:
kfree(mr->pas); kfree(mr->pas);
if (mr->status != IB_WC_SUCCESS) { free_mr:
mlx5_ib_warn(dev, "reg umr failed\n"); if (err) {
err = -EFAULT; free_cached_mr(dev, mr);
goto error; return ERR_PTR(err);
} }
return mr; return mr;
error:
free_cached_mr(dev, mr);
return ERR_PTR(err);
} }
static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, u64 virt_addr, static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, u64 virt_addr,
@ -926,24 +938,26 @@ error:
static int unreg_umr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) static int unreg_umr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
{ {
struct umr_common *umrc = &dev->umrc; struct umr_common *umrc = &dev->umrc;
struct mlx5_ib_umr_context umr_context;
struct ib_send_wr wr, *bad; struct ib_send_wr wr, *bad;
int err; int err;
memset(&wr, 0, sizeof(wr)); memset(&wr, 0, sizeof(wr));
wr.wr_id = (u64)(unsigned long)mr; wr.wr_id = (u64)(unsigned long)&umr_context;
prep_umr_unreg_wqe(dev, &wr, mr->mmr.key); prep_umr_unreg_wqe(dev, &wr, mr->mmr.key);
mlx5_ib_init_umr_context(&umr_context);
down(&umrc->sem); down(&umrc->sem);
init_completion(&mr->done);
err = ib_post_send(umrc->qp, &wr, &bad); err = ib_post_send(umrc->qp, &wr, &bad);
if (err) { if (err) {
up(&umrc->sem); up(&umrc->sem);
mlx5_ib_dbg(dev, "err %d\n", err); mlx5_ib_dbg(dev, "err %d\n", err);
goto error; goto error;
} else {
wait_for_completion(&umr_context.done);
up(&umrc->sem);
} }
wait_for_completion(&mr->done); if (umr_context.status != IB_WC_SUCCESS) {
up(&umrc->sem);
if (mr->status != IB_WC_SUCCESS) {
mlx5_ib_warn(dev, "unreg umr failed\n"); mlx5_ib_warn(dev, "unreg umr failed\n");
err = -EFAULT; err = -EFAULT;
goto error; goto error;

View file

@ -574,6 +574,10 @@ static int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd,
uar_index = uuarn_to_uar_index(&context->uuari, uuarn); uar_index = uuarn_to_uar_index(&context->uuari, uuarn);
mlx5_ib_dbg(dev, "uuarn 0x%x, uar_index 0x%x\n", uuarn, uar_index); mlx5_ib_dbg(dev, "uuarn 0x%x, uar_index 0x%x\n", uuarn, uar_index);
qp->rq.offset = 0;
qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB);
qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift;
err = set_user_buf_size(dev, qp, &ucmd); err = set_user_buf_size(dev, qp, &ucmd);
if (err) if (err)
goto err_uuar; goto err_uuar;
@ -2078,6 +2082,7 @@ static int mlx5_set_bsf(struct ib_mr *sig_mr,
struct ib_sig_domain *wire = &sig_attrs->wire; struct ib_sig_domain *wire = &sig_attrs->wire;
int ret, selector; int ret, selector;
memset(bsf, 0, sizeof(*bsf));
switch (sig_attrs->mem.sig_type) { switch (sig_attrs->mem.sig_type) {
case IB_SIG_TYPE_T10_DIF: case IB_SIG_TYPE_T10_DIF:
if (sig_attrs->wire.sig_type != IB_SIG_TYPE_T10_DIF) if (sig_attrs->wire.sig_type != IB_SIG_TYPE_T10_DIF)
@ -2090,9 +2095,11 @@ static int mlx5_set_bsf(struct ib_mr *sig_mr,
/* Same block structure */ /* Same block structure */
basic->bsf_size_sbs = 1 << 4; basic->bsf_size_sbs = 1 << 4;
if (mem->sig.dif.bg_type == wire->sig.dif.bg_type) if (mem->sig.dif.bg_type == wire->sig.dif.bg_type)
basic->wire.copy_byte_mask = 0xff; basic->wire.copy_byte_mask |= 0xc0;
else if (mem->sig.dif.app_tag == wire->sig.dif.app_tag)
basic->wire.copy_byte_mask = 0x3f; basic->wire.copy_byte_mask |= 0x30;
if (mem->sig.dif.ref_tag == wire->sig.dif.ref_tag)
basic->wire.copy_byte_mask |= 0x0f;
} else } else
basic->wire.bs_selector = bs_selector(wire->sig.dif.pi_interval); basic->wire.bs_selector = bs_selector(wire->sig.dif.pi_interval);
@ -2131,9 +2138,13 @@ static int set_sig_data_segment(struct ib_send_wr *wr, struct mlx5_ib_qp *qp,
int ret; int ret;
int wqe_size; int wqe_size;
if (!wr->wr.sig_handover.prot) { if (!wr->wr.sig_handover.prot ||
(data_key == wr->wr.sig_handover.prot->lkey &&
data_va == wr->wr.sig_handover.prot->addr &&
data_len == wr->wr.sig_handover.prot->length)) {
/** /**
* Source domain doesn't contain signature information * Source domain doesn't contain signature information
* or data and protection are interleaved in memory.
* So need construct: * So need construct:
* ------------------ * ------------------
* | data_klm | * | data_klm |
@ -2187,23 +2198,13 @@ static int set_sig_data_segment(struct ib_send_wr *wr, struct mlx5_ib_qp *qp,
data_sentry->bcount = cpu_to_be16(block_size); data_sentry->bcount = cpu_to_be16(block_size);
data_sentry->key = cpu_to_be32(data_key); data_sentry->key = cpu_to_be32(data_key);
data_sentry->va = cpu_to_be64(data_va); data_sentry->va = cpu_to_be64(data_va);
data_sentry->stride = cpu_to_be16(block_size);
prot_sentry->bcount = cpu_to_be16(prot_size); prot_sentry->bcount = cpu_to_be16(prot_size);
prot_sentry->key = cpu_to_be32(prot_key); prot_sentry->key = cpu_to_be32(prot_key);
prot_sentry->va = cpu_to_be64(prot_va);
prot_sentry->stride = cpu_to_be16(prot_size);
if (prot_key == data_key && prot_va == data_va) {
/**
* The data and protection are interleaved
* in a single memory region
**/
prot_sentry->va = cpu_to_be64(data_va + block_size);
prot_sentry->stride = cpu_to_be16(block_size + prot_size);
data_sentry->stride = prot_sentry->stride;
} else {
/* The data and protection are two different buffers */
prot_sentry->va = cpu_to_be64(prot_va);
data_sentry->stride = cpu_to_be16(block_size);
prot_sentry->stride = cpu_to_be16(prot_size);
}
wqe_size = ALIGN(sizeof(*sblock_ctrl) + sizeof(*data_sentry) + wqe_size = ALIGN(sizeof(*sblock_ctrl) + sizeof(*data_sentry) +
sizeof(*prot_sentry), 64); sizeof(*prot_sentry), 64);
} }
@ -2275,7 +2276,10 @@ static int set_sig_umr_wr(struct ib_send_wr *wr, struct mlx5_ib_qp *qp,
/* length of the protected region, data + protection */ /* length of the protected region, data + protection */
region_len = wr->sg_list->length; region_len = wr->sg_list->length;
if (wr->wr.sig_handover.prot) if (wr->wr.sig_handover.prot &&
(wr->wr.sig_handover.prot->lkey != wr->sg_list->lkey ||
wr->wr.sig_handover.prot->addr != wr->sg_list->addr ||
wr->wr.sig_handover.prot->length != wr->sg_list->length))
region_len += wr->wr.sig_handover.prot->length; region_len += wr->wr.sig_handover.prot->length;
/** /**

View file

@ -35,6 +35,7 @@
#include <linux/mlx5/srq.h> #include <linux/mlx5/srq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <rdma/ib_umem.h> #include <rdma/ib_umem.h>
#include <rdma/ib_user_verbs.h>
#include "mlx5_ib.h" #include "mlx5_ib.h"
#include "user.h" #include "user.h"
@ -78,16 +79,27 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
{ {
struct mlx5_ib_dev *dev = to_mdev(pd->device); struct mlx5_ib_dev *dev = to_mdev(pd->device);
struct mlx5_ib_create_srq ucmd; struct mlx5_ib_create_srq ucmd;
size_t ucmdlen;
int err; int err;
int npages; int npages;
int page_shift; int page_shift;
int ncont; int ncont;
u32 offset; u32 offset;
if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) { ucmdlen =
(udata->inlen - sizeof(struct ib_uverbs_cmd_hdr) <
sizeof(ucmd)) ? (sizeof(ucmd) -
sizeof(ucmd.reserved)) : sizeof(ucmd);
if (ib_copy_from_udata(&ucmd, udata, ucmdlen)) {
mlx5_ib_dbg(dev, "failed copy udata\n"); mlx5_ib_dbg(dev, "failed copy udata\n");
return -EFAULT; return -EFAULT;
} }
if (ucmdlen == sizeof(ucmd) &&
ucmd.reserved != 0)
return -EINVAL;
srq->wq_sig = !!(ucmd.flags & MLX5_SRQ_FLAG_SIGNATURE); srq->wq_sig = !!(ucmd.flags & MLX5_SRQ_FLAG_SIGNATURE);
srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, buf_size, srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, buf_size,

View file

@ -91,6 +91,7 @@ struct mlx5_ib_create_cq {
__u64 buf_addr; __u64 buf_addr;
__u64 db_addr; __u64 db_addr;
__u32 cqe_size; __u32 cqe_size;
__u32 reserved; /* explicit padding (optional on i386) */
}; };
struct mlx5_ib_create_cq_resp { struct mlx5_ib_create_cq_resp {
@ -109,6 +110,7 @@ struct mlx5_ib_create_srq {
__u64 buf_addr; __u64 buf_addr;
__u64 db_addr; __u64 db_addr;
__u32 flags; __u32 flags;
__u32 reserved; /* explicit padding (optional on i386) */
}; };
struct mlx5_ib_create_srq_resp { struct mlx5_ib_create_srq_resp {

View file

@ -68,7 +68,6 @@ MODULE_VERSION(DRV_VERSION);
int max_mtu = 9000; int max_mtu = 9000;
int interrupt_mod_interval = 0; int interrupt_mod_interval = 0;
/* Interoperability */ /* Interoperability */
int mpa_version = 1; int mpa_version = 1;
module_param(mpa_version, int, 0644); module_param(mpa_version, int, 0644);
@ -112,6 +111,16 @@ static struct pci_device_id nes_pci_table[] = {
MODULE_DEVICE_TABLE(pci, nes_pci_table); MODULE_DEVICE_TABLE(pci, nes_pci_table);
/* registered nes netlink callbacks */
static struct ibnl_client_cbs nes_nl_cb_table[] = {
[RDMA_NL_IWPM_REG_PID] = {.dump = iwpm_register_pid_cb},
[RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb},
[RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = iwpm_add_and_query_mapping_cb},
[RDMA_NL_IWPM_HANDLE_ERR] = {.dump = iwpm_mapping_error_cb},
[RDMA_NL_IWPM_MAPINFO] = {.dump = iwpm_mapping_info_cb},
[RDMA_NL_IWPM_MAPINFO_NUM] = {.dump = iwpm_ack_mapping_info_cb}
};
static int nes_inetaddr_event(struct notifier_block *, unsigned long, void *); static int nes_inetaddr_event(struct notifier_block *, unsigned long, void *);
static int nes_net_event(struct notifier_block *, unsigned long, void *); static int nes_net_event(struct notifier_block *, unsigned long, void *);
static int nes_notifiers_registered; static int nes_notifiers_registered;
@ -672,6 +681,17 @@ static int nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
} }
nes_notifiers_registered++; nes_notifiers_registered++;
if (ibnl_add_client(RDMA_NL_NES, RDMA_NL_IWPM_NUM_OPS, nes_nl_cb_table))
printk(KERN_ERR PFX "%s[%u]: Failed to add netlink callback\n",
__func__, __LINE__);
ret = iwpm_init(RDMA_NL_NES);
if (ret) {
printk(KERN_ERR PFX "%s: port mapper initialization failed\n",
pci_name(pcidev));
goto bail7;
}
INIT_DELAYED_WORK(&nesdev->work, nes_recheck_link_status); INIT_DELAYED_WORK(&nesdev->work, nes_recheck_link_status);
/* Initialize network devices */ /* Initialize network devices */
@ -710,6 +730,7 @@ static int nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
nes_debug(NES_DBG_INIT, "netdev_count=%d, nesadapter->netdev_count=%d\n", nes_debug(NES_DBG_INIT, "netdev_count=%d, nesadapter->netdev_count=%d\n",
nesdev->netdev_count, nesdev->nesadapter->netdev_count); nesdev->netdev_count, nesdev->nesadapter->netdev_count);
ibnl_remove_client(RDMA_NL_NES);
nes_notifiers_registered--; nes_notifiers_registered--;
if (nes_notifiers_registered == 0) { if (nes_notifiers_registered == 0) {
@ -773,6 +794,8 @@ static void nes_remove(struct pci_dev *pcidev)
nesdev->nesadapter->netdev_count--; nesdev->nesadapter->netdev_count--;
} }
} }
ibnl_remove_client(RDMA_NL_NES);
iwpm_exit(RDMA_NL_NES);
nes_notifiers_registered--; nes_notifiers_registered--;
if (nes_notifiers_registered == 0) { if (nes_notifiers_registered == 0) {

View file

@ -51,6 +51,8 @@
#include <rdma/ib_pack.h> #include <rdma/ib_pack.h>
#include <rdma/rdma_cm.h> #include <rdma/rdma_cm.h>
#include <rdma/iw_cm.h> #include <rdma/iw_cm.h>
#include <rdma/rdma_netlink.h>
#include <rdma/iw_portmap.h>
#define NES_SEND_FIRST_WRITE #define NES_SEND_FIRST_WRITE
@ -130,6 +132,7 @@
#define NES_DBG_IW_TX 0x00040000 #define NES_DBG_IW_TX 0x00040000
#define NES_DBG_SHUTDOWN 0x00080000 #define NES_DBG_SHUTDOWN 0x00080000
#define NES_DBG_PAU 0x00100000 #define NES_DBG_PAU 0x00100000
#define NES_DBG_NLMSG 0x00200000
#define NES_DBG_RSVD1 0x10000000 #define NES_DBG_RSVD1 0x10000000
#define NES_DBG_RSVD2 0x20000000 #define NES_DBG_RSVD2 0x20000000
#define NES_DBG_RSVD3 0x40000000 #define NES_DBG_RSVD3 0x40000000

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved. * Copyright (c) 2006 - 2014 Intel Corporation. All rights reserved.
* *
* This software is available to you under a choice of one of two * This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU * licenses. You may choose to be licensed under the terms of the GNU
@ -59,6 +59,7 @@
#include <net/route.h> #include <net/route.h>
#include <net/ip_fib.h> #include <net/ip_fib.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <linux/fcntl.h>
#include "nes.h" #include "nes.h"
@ -166,7 +167,6 @@ int nes_rem_ref_cm_node(struct nes_cm_node *cm_node)
{ {
return rem_ref_cm_node(cm_node->cm_core, cm_node); return rem_ref_cm_node(cm_node->cm_core, cm_node);
} }
/** /**
* create_event * create_event
*/ */
@ -482,11 +482,11 @@ static void form_cm_frame(struct sk_buff *skb,
iph->ttl = 0x40; iph->ttl = 0x40;
iph->protocol = 0x06; /* IPPROTO_TCP */ iph->protocol = 0x06; /* IPPROTO_TCP */
iph->saddr = htonl(cm_node->loc_addr); iph->saddr = htonl(cm_node->mapped_loc_addr);
iph->daddr = htonl(cm_node->rem_addr); iph->daddr = htonl(cm_node->mapped_rem_addr);
tcph->source = htons(cm_node->loc_port); tcph->source = htons(cm_node->mapped_loc_port);
tcph->dest = htons(cm_node->rem_port); tcph->dest = htons(cm_node->mapped_rem_port);
tcph->seq = htonl(cm_node->tcp_cntxt.loc_seq_num); tcph->seq = htonl(cm_node->tcp_cntxt.loc_seq_num);
if (flags & SET_ACK) { if (flags & SET_ACK) {
@ -525,6 +525,100 @@ static void form_cm_frame(struct sk_buff *skb,
cm_packets_created++; cm_packets_created++;
} }
/*
* nes_create_sockaddr - Record ip addr and tcp port in a sockaddr struct
*/
static void nes_create_sockaddr(__be32 ip_addr, __be16 port,
struct sockaddr_storage *addr)
{
struct sockaddr_in *nes_sockaddr = (struct sockaddr_in *)addr;
nes_sockaddr->sin_family = AF_INET;
memcpy(&nes_sockaddr->sin_addr.s_addr, &ip_addr, sizeof(__be32));
nes_sockaddr->sin_port = port;
}
/*
* nes_create_mapinfo - Create a mapinfo object in the port mapper data base
*/
static int nes_create_mapinfo(struct nes_cm_info *cm_info)
{
struct sockaddr_storage local_sockaddr;
struct sockaddr_storage mapped_sockaddr;
nes_create_sockaddr(htonl(cm_info->loc_addr), htons(cm_info->loc_port),
&local_sockaddr);
nes_create_sockaddr(htonl(cm_info->mapped_loc_addr),
htons(cm_info->mapped_loc_port), &mapped_sockaddr);
return iwpm_create_mapinfo(&local_sockaddr,
&mapped_sockaddr, RDMA_NL_NES);
}
/*
* nes_remove_mapinfo - Remove a mapinfo object from the port mapper data base
* and send a remove mapping op message to
* the userspace port mapper
*/
static int nes_remove_mapinfo(u32 loc_addr, u16 loc_port,
u32 mapped_loc_addr, u16 mapped_loc_port)
{
struct sockaddr_storage local_sockaddr;
struct sockaddr_storage mapped_sockaddr;
nes_create_sockaddr(htonl(loc_addr), htons(loc_port), &local_sockaddr);
nes_create_sockaddr(htonl(mapped_loc_addr), htons(mapped_loc_port),
&mapped_sockaddr);
iwpm_remove_mapinfo(&local_sockaddr, &mapped_sockaddr);
return iwpm_remove_mapping(&local_sockaddr, RDMA_NL_NES);
}
/*
* nes_form_pm_msg - Form a port mapper message with mapping info
*/
static void nes_form_pm_msg(struct nes_cm_info *cm_info,
struct iwpm_sa_data *pm_msg)
{
nes_create_sockaddr(htonl(cm_info->loc_addr), htons(cm_info->loc_port),
&pm_msg->loc_addr);
nes_create_sockaddr(htonl(cm_info->rem_addr), htons(cm_info->rem_port),
&pm_msg->rem_addr);
}
/*
* nes_form_reg_msg - Form a port mapper message with dev info
*/
static void nes_form_reg_msg(struct nes_vnic *nesvnic,
struct iwpm_dev_data *pm_msg)
{
memcpy(pm_msg->dev_name, nesvnic->nesibdev->ibdev.name,
IWPM_DEVNAME_SIZE);
memcpy(pm_msg->if_name, nesvnic->netdev->name, IWPM_IFNAME_SIZE);
}
/*
* nes_record_pm_msg - Save the received mapping info
*/
static void nes_record_pm_msg(struct nes_cm_info *cm_info,
struct iwpm_sa_data *pm_msg)
{
struct sockaddr_in *mapped_loc_addr =
(struct sockaddr_in *)&pm_msg->mapped_loc_addr;
struct sockaddr_in *mapped_rem_addr =
(struct sockaddr_in *)&pm_msg->mapped_rem_addr;
if (mapped_loc_addr->sin_family == AF_INET) {
cm_info->mapped_loc_addr =
ntohl(mapped_loc_addr->sin_addr.s_addr);
cm_info->mapped_loc_port = ntohs(mapped_loc_addr->sin_port);
}
if (mapped_rem_addr->sin_family == AF_INET) {
cm_info->mapped_rem_addr =
ntohl(mapped_rem_addr->sin_addr.s_addr);
cm_info->mapped_rem_port = ntohs(mapped_rem_addr->sin_port);
}
}
/** /**
* print_core - dump a cm core * print_core - dump a cm core
*/ */
@ -1147,8 +1241,11 @@ static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
loc_addr, loc_port, loc_addr, loc_port,
cm_node->rem_addr, cm_node->rem_port, cm_node->rem_addr, cm_node->rem_port,
rem_addr, rem_port); rem_addr, rem_port);
if ((cm_node->loc_addr == loc_addr) && (cm_node->loc_port == loc_port) && if ((cm_node->mapped_loc_addr == loc_addr) &&
(cm_node->rem_addr == rem_addr) && (cm_node->rem_port == rem_port)) { (cm_node->mapped_loc_port == loc_port) &&
(cm_node->mapped_rem_addr == rem_addr) &&
(cm_node->mapped_rem_port == rem_port)) {
add_ref_cm_node(cm_node); add_ref_cm_node(cm_node);
spin_unlock_irqrestore(&cm_core->ht_lock, flags); spin_unlock_irqrestore(&cm_core->ht_lock, flags);
return cm_node; return cm_node;
@ -1165,18 +1262,28 @@ static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
* find_listener - find a cm node listening on this addr-port pair * find_listener - find a cm node listening on this addr-port pair
*/ */
static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core, static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
nes_addr_t dst_addr, u16 dst_port, enum nes_cm_listener_state listener_state) nes_addr_t dst_addr, u16 dst_port,
enum nes_cm_listener_state listener_state, int local)
{ {
unsigned long flags; unsigned long flags;
struct nes_cm_listener *listen_node; struct nes_cm_listener *listen_node;
nes_addr_t listen_addr;
u16 listen_port;
/* walk list and find cm_node associated with this session ID */ /* walk list and find cm_node associated with this session ID */
spin_lock_irqsave(&cm_core->listen_list_lock, flags); spin_lock_irqsave(&cm_core->listen_list_lock, flags);
list_for_each_entry(listen_node, &cm_core->listen_list.list, list) { list_for_each_entry(listen_node, &cm_core->listen_list.list, list) {
if (local) {
listen_addr = listen_node->loc_addr;
listen_port = listen_node->loc_port;
} else {
listen_addr = listen_node->mapped_loc_addr;
listen_port = listen_node->mapped_loc_port;
}
/* compare node pair, return node handle if a match */ /* compare node pair, return node handle if a match */
if (((listen_node->loc_addr == dst_addr) || if (((listen_addr == dst_addr) ||
listen_node->loc_addr == 0x00000000) && listen_addr == 0x00000000) &&
(listen_node->loc_port == dst_port) && (listen_port == dst_port) &&
(listener_state & listen_node->listener_state)) { (listener_state & listen_node->listener_state)) {
atomic_inc(&listen_node->ref_count); atomic_inc(&listen_node->ref_count);
spin_unlock_irqrestore(&cm_core->listen_list_lock, flags); spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
@ -1189,7 +1296,6 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
return NULL; return NULL;
} }
/** /**
* add_hte_node - add a cm node to the hash table * add_hte_node - add a cm node to the hash table
*/ */
@ -1310,9 +1416,20 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
spin_unlock_irqrestore(&cm_core->listen_list_lock, flags); spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
if (listener->nesvnic) if (listener->nesvnic) {
nes_manage_apbvt(listener->nesvnic, listener->loc_port, nes_manage_apbvt(listener->nesvnic,
PCI_FUNC(listener->nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_DEL); listener->mapped_loc_port,
PCI_FUNC(listener->nesvnic->nesdev->pcidev->devfn),
NES_MANAGE_APBVT_DEL);
nes_remove_mapinfo(listener->loc_addr,
listener->loc_port,
listener->mapped_loc_addr,
listener->mapped_loc_port);
nes_debug(NES_DBG_NLMSG,
"Delete APBVT mapped_loc_port = %04X\n",
listener->mapped_loc_port);
}
nes_debug(NES_DBG_CM, "destroying listener (%p)\n", listener); nes_debug(NES_DBG_CM, "destroying listener (%p)\n", listener);
@ -1454,6 +1571,11 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
cm_node->loc_port = cm_info->loc_port; cm_node->loc_port = cm_info->loc_port;
cm_node->rem_port = cm_info->rem_port; cm_node->rem_port = cm_info->rem_port;
cm_node->mapped_loc_addr = cm_info->mapped_loc_addr;
cm_node->mapped_rem_addr = cm_info->mapped_rem_addr;
cm_node->mapped_loc_port = cm_info->mapped_loc_port;
cm_node->mapped_rem_port = cm_info->mapped_rem_port;
cm_node->mpa_frame_rev = mpa_version; cm_node->mpa_frame_rev = mpa_version;
cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO; cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO;
cm_node->mpav2_ird_ord = 0; cm_node->mpav2_ird_ord = 0;
@ -1500,8 +1622,10 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
cm_node->loopbackpartner = NULL; cm_node->loopbackpartner = NULL;
/* get the mac addr for the remote node */ /* get the mac addr for the remote node */
oldarpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE); oldarpindex = nes_arp_table(nesdev, cm_node->mapped_rem_addr,
arpindex = nes_addr_resolve_neigh(nesvnic, cm_info->rem_addr, oldarpindex); NULL, NES_ARP_RESOLVE);
arpindex = nes_addr_resolve_neigh(nesvnic,
cm_node->mapped_rem_addr, oldarpindex);
if (arpindex < 0) { if (arpindex < 0) {
kfree(cm_node); kfree(cm_node);
return NULL; return NULL;
@ -1563,11 +1687,14 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core,
mini_cm_dec_refcnt_listen(cm_core, cm_node->listener, 0); mini_cm_dec_refcnt_listen(cm_core, cm_node->listener, 0);
} else { } else {
if (cm_node->apbvt_set && cm_node->nesvnic) { if (cm_node->apbvt_set && cm_node->nesvnic) {
nes_manage_apbvt(cm_node->nesvnic, cm_node->loc_port, nes_manage_apbvt(cm_node->nesvnic, cm_node->mapped_loc_port,
PCI_FUNC( PCI_FUNC(cm_node->nesvnic->nesdev->pcidev->devfn),
cm_node->nesvnic->nesdev->pcidev->devfn),
NES_MANAGE_APBVT_DEL); NES_MANAGE_APBVT_DEL);
} }
nes_debug(NES_DBG_NLMSG, "Delete APBVT mapped_loc_port = %04X\n",
cm_node->mapped_loc_port);
nes_remove_mapinfo(cm_node->loc_addr, cm_node->loc_port,
cm_node->mapped_loc_addr, cm_node->mapped_loc_port);
} }
atomic_dec(&cm_core->node_cnt); atomic_dec(&cm_core->node_cnt);
@ -2235,17 +2362,21 @@ static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
* mini_cm_listen - create a listen node with params * mini_cm_listen - create a listen node with params
*/ */
static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core, static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
struct nes_vnic *nesvnic, struct nes_cm_info *cm_info) struct nes_vnic *nesvnic, struct nes_cm_info *cm_info)
{ {
struct nes_cm_listener *listener; struct nes_cm_listener *listener;
struct iwpm_dev_data pm_reg_msg;
struct iwpm_sa_data pm_msg;
unsigned long flags; unsigned long flags;
int iwpm_err = 0;
nes_debug(NES_DBG_CM, "Search for 0x%08x : 0x%04x\n", nes_debug(NES_DBG_CM, "Search for 0x%08x : 0x%04x\n",
cm_info->loc_addr, cm_info->loc_port); cm_info->loc_addr, cm_info->loc_port);
/* cannot have multiple matching listeners */ /* cannot have multiple matching listeners */
listener = find_listener(cm_core, htonl(cm_info->loc_addr), listener = find_listener(cm_core, cm_info->loc_addr, cm_info->loc_port,
htons(cm_info->loc_port), NES_CM_LISTENER_EITHER_STATE); NES_CM_LISTENER_EITHER_STATE, 1);
if (listener && listener->listener_state == NES_CM_LISTENER_ACTIVE_STATE) { if (listener && listener->listener_state == NES_CM_LISTENER_ACTIVE_STATE) {
/* find automatically incs ref count ??? */ /* find automatically incs ref count ??? */
atomic_dec(&listener->ref_count); atomic_dec(&listener->ref_count);
@ -2254,6 +2385,22 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
} }
if (!listener) { if (!listener) {
nes_form_reg_msg(nesvnic, &pm_reg_msg);
iwpm_err = iwpm_register_pid(&pm_reg_msg, RDMA_NL_NES);
if (iwpm_err) {
nes_debug(NES_DBG_NLMSG,
"Port Mapper reg pid fail (err = %d).\n", iwpm_err);
}
if (iwpm_valid_pid() && !iwpm_err) {
nes_form_pm_msg(cm_info, &pm_msg);
iwpm_err = iwpm_add_mapping(&pm_msg, RDMA_NL_NES);
if (iwpm_err)
nes_debug(NES_DBG_NLMSG,
"Port Mapper query fail (err = %d).\n", iwpm_err);
else
nes_record_pm_msg(cm_info, &pm_msg);
}
/* create a CM listen node (1/2 node to compare incoming traffic to) */ /* create a CM listen node (1/2 node to compare incoming traffic to) */
listener = kzalloc(sizeof(*listener), GFP_ATOMIC); listener = kzalloc(sizeof(*listener), GFP_ATOMIC);
if (!listener) { if (!listener) {
@ -2261,8 +2408,10 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
return NULL; return NULL;
} }
listener->loc_addr = htonl(cm_info->loc_addr); listener->loc_addr = cm_info->loc_addr;
listener->loc_port = htons(cm_info->loc_port); listener->loc_port = cm_info->loc_port;
listener->mapped_loc_addr = cm_info->mapped_loc_addr;
listener->mapped_loc_port = cm_info->mapped_loc_port;
listener->reused_node = 0; listener->reused_node = 0;
atomic_set(&listener->ref_count, 1); atomic_set(&listener->ref_count, 1);
@ -2324,14 +2473,18 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
if (cm_info->loc_addr == cm_info->rem_addr) { if (cm_info->loc_addr == cm_info->rem_addr) {
loopbackremotelistener = find_listener(cm_core, loopbackremotelistener = find_listener(cm_core,
ntohl(nesvnic->local_ipaddr), cm_node->rem_port, cm_node->mapped_loc_addr, cm_node->mapped_rem_port,
NES_CM_LISTENER_ACTIVE_STATE); NES_CM_LISTENER_ACTIVE_STATE, 0);
if (loopbackremotelistener == NULL) { if (loopbackremotelistener == NULL) {
create_event(cm_node, NES_CM_EVENT_ABORTED); create_event(cm_node, NES_CM_EVENT_ABORTED);
} else { } else {
loopback_cm_info = *cm_info; loopback_cm_info = *cm_info;
loopback_cm_info.loc_port = cm_info->rem_port; loopback_cm_info.loc_port = cm_info->rem_port;
loopback_cm_info.rem_port = cm_info->loc_port; loopback_cm_info.rem_port = cm_info->loc_port;
loopback_cm_info.mapped_loc_port =
cm_info->mapped_rem_port;
loopback_cm_info.mapped_rem_port =
cm_info->mapped_loc_port;
loopback_cm_info.cm_id = loopbackremotelistener->cm_id; loopback_cm_info.cm_id = loopbackremotelistener->cm_id;
loopbackremotenode = make_cm_node(cm_core, nesvnic, loopbackremotenode = make_cm_node(cm_core, nesvnic,
&loopback_cm_info, loopbackremotelistener); &loopback_cm_info, loopbackremotelistener);
@ -2560,6 +2713,12 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,
nfo.rem_addr = ntohl(iph->saddr); nfo.rem_addr = ntohl(iph->saddr);
nfo.rem_port = ntohs(tcph->source); nfo.rem_port = ntohs(tcph->source);
/* If port mapper is available these should be mapped address info */
nfo.mapped_loc_addr = ntohl(iph->daddr);
nfo.mapped_loc_port = ntohs(tcph->dest);
nfo.mapped_rem_addr = ntohl(iph->saddr);
nfo.mapped_rem_port = ntohs(tcph->source);
tmp_daddr = cpu_to_be32(iph->daddr); tmp_daddr = cpu_to_be32(iph->daddr);
tmp_saddr = cpu_to_be32(iph->saddr); tmp_saddr = cpu_to_be32(iph->saddr);
@ -2568,8 +2727,8 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,
do { do {
cm_node = find_node(cm_core, cm_node = find_node(cm_core,
nfo.rem_port, nfo.rem_addr, nfo.mapped_rem_port, nfo.mapped_rem_addr,
nfo.loc_port, nfo.loc_addr); nfo.mapped_loc_port, nfo.mapped_loc_addr);
if (!cm_node) { if (!cm_node) {
/* Only type of packet accepted are for */ /* Only type of packet accepted are for */
@ -2578,9 +2737,9 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,
skb_handled = 0; skb_handled = 0;
break; break;
} }
listener = find_listener(cm_core, nfo.loc_addr, listener = find_listener(cm_core, nfo.mapped_loc_addr,
nfo.loc_port, nfo.mapped_loc_port,
NES_CM_LISTENER_ACTIVE_STATE); NES_CM_LISTENER_ACTIVE_STATE, 0);
if (!listener) { if (!listener) {
nfo.cm_id = NULL; nfo.cm_id = NULL;
nfo.conn_type = 0; nfo.conn_type = 0;
@ -3184,10 +3343,12 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
nes_cm_init_tsa_conn(nesqp, cm_node); nes_cm_init_tsa_conn(nesqp, cm_node);
nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(laddr->sin_port)); nesqp->nesqp_context->tcpPorts[0] =
nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(raddr->sin_port)); cpu_to_le16(cm_node->mapped_loc_port);
nesqp->nesqp_context->tcpPorts[1] =
cpu_to_le16(cm_node->mapped_rem_port);
nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(raddr->sin_addr.s_addr)); nesqp->nesqp_context->ip0 = cpu_to_le32(cm_node->mapped_rem_addr);
nesqp->nesqp_context->misc2 |= cpu_to_le32( nesqp->nesqp_context->misc2 |= cpu_to_le32(
(u32)PCI_FUNC(nesdev->pcidev->devfn) << (u32)PCI_FUNC(nesdev->pcidev->devfn) <<
@ -3211,9 +3372,9 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
memset(&nes_quad, 0, sizeof(nes_quad)); memset(&nes_quad, 0, sizeof(nes_quad));
nes_quad.DstIpAdrIndex = nes_quad.DstIpAdrIndex =
cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24); cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
nes_quad.SrcIpadr = raddr->sin_addr.s_addr; nes_quad.SrcIpadr = htonl(cm_node->mapped_rem_addr);
nes_quad.TcpPorts[0] = raddr->sin_port; nes_quad.TcpPorts[0] = htons(cm_node->mapped_rem_port);
nes_quad.TcpPorts[1] = laddr->sin_port; nes_quad.TcpPorts[1] = htons(cm_node->mapped_loc_port);
/* Produce hash key */ /* Produce hash key */
crc_value = get_crc_value(&nes_quad); crc_value = get_crc_value(&nes_quad);
@ -3315,6 +3476,9 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
int apbvt_set = 0; int apbvt_set = 0;
struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->local_addr; struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->local_addr;
struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->remote_addr; struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->remote_addr;
struct iwpm_dev_data pm_reg_msg;
struct iwpm_sa_data pm_msg;
int iwpm_err = 0;
if (cm_id->remote_addr.ss_family != AF_INET) if (cm_id->remote_addr.ss_family != AF_INET)
return -ENOSYS; return -ENOSYS;
@ -3352,20 +3516,44 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
nes_debug(NES_DBG_CM, "mpa private data len =%u\n", nes_debug(NES_DBG_CM, "mpa private data len =%u\n",
conn_param->private_data_len); conn_param->private_data_len);
/* set up the connection params for the node */
cm_info.loc_addr = ntohl(laddr->sin_addr.s_addr);
cm_info.loc_port = ntohs(laddr->sin_port);
cm_info.rem_addr = ntohl(raddr->sin_addr.s_addr);
cm_info.rem_port = ntohs(raddr->sin_port);
cm_info.cm_id = cm_id;
cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
/* No port mapper available, go with the specified peer information */
cm_info.mapped_loc_addr = cm_info.loc_addr;
cm_info.mapped_loc_port = cm_info.loc_port;
cm_info.mapped_rem_addr = cm_info.rem_addr;
cm_info.mapped_rem_port = cm_info.rem_port;
nes_form_reg_msg(nesvnic, &pm_reg_msg);
iwpm_err = iwpm_register_pid(&pm_reg_msg, RDMA_NL_NES);
if (iwpm_err) {
nes_debug(NES_DBG_NLMSG,
"Port Mapper reg pid fail (err = %d).\n", iwpm_err);
}
if (iwpm_valid_pid() && !iwpm_err) {
nes_form_pm_msg(&cm_info, &pm_msg);
iwpm_err = iwpm_add_and_query_mapping(&pm_msg, RDMA_NL_NES);
if (iwpm_err)
nes_debug(NES_DBG_NLMSG,
"Port Mapper query fail (err = %d).\n", iwpm_err);
else
nes_record_pm_msg(&cm_info, &pm_msg);
}
if (laddr->sin_addr.s_addr != raddr->sin_addr.s_addr) { if (laddr->sin_addr.s_addr != raddr->sin_addr.s_addr) {
nes_manage_apbvt(nesvnic, ntohs(laddr->sin_port), nes_manage_apbvt(nesvnic, cm_info.mapped_loc_port,
PCI_FUNC(nesdev->pcidev->devfn), PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
NES_MANAGE_APBVT_ADD);
apbvt_set = 1; apbvt_set = 1;
} }
/* set up the connection params for the node */ if (nes_create_mapinfo(&cm_info))
cm_info.loc_addr = htonl(laddr->sin_addr.s_addr); return -ENOMEM;
cm_info.loc_port = htons(laddr->sin_port);
cm_info.rem_addr = htonl(raddr->sin_addr.s_addr);
cm_info.rem_port = htons(raddr->sin_port);
cm_info.cm_id = cm_id;
cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
cm_id->add_ref(cm_id); cm_id->add_ref(cm_id);
@ -3375,10 +3563,14 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
&cm_info); &cm_info);
if (!cm_node) { if (!cm_node) {
if (apbvt_set) if (apbvt_set)
nes_manage_apbvt(nesvnic, ntohs(laddr->sin_port), nes_manage_apbvt(nesvnic, cm_info.mapped_loc_port,
PCI_FUNC(nesdev->pcidev->devfn), PCI_FUNC(nesdev->pcidev->devfn),
NES_MANAGE_APBVT_DEL); NES_MANAGE_APBVT_DEL);
nes_debug(NES_DBG_NLMSG, "Delete mapped_loc_port = %04X\n",
cm_info.mapped_loc_port);
nes_remove_mapinfo(cm_info.loc_addr, cm_info.loc_port,
cm_info.mapped_loc_addr, cm_info.mapped_loc_port);
cm_id->rem_ref(cm_id); cm_id->rem_ref(cm_id);
return -ENOMEM; return -ENOMEM;
} }
@ -3424,13 +3616,16 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
nesvnic->local_ipaddr, laddr->sin_addr.s_addr); nesvnic->local_ipaddr, laddr->sin_addr.s_addr);
/* setup listen params in our api call struct */ /* setup listen params in our api call struct */
cm_info.loc_addr = nesvnic->local_ipaddr; cm_info.loc_addr = ntohl(nesvnic->local_ipaddr);
cm_info.loc_port = laddr->sin_port; cm_info.loc_port = ntohs(laddr->sin_port);
cm_info.backlog = backlog; cm_info.backlog = backlog;
cm_info.cm_id = cm_id; cm_info.cm_id = cm_id;
cm_info.conn_type = NES_CM_IWARP_CONN_TYPE; cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
/* No port mapper available, go with the specified info */
cm_info.mapped_loc_addr = cm_info.loc_addr;
cm_info.mapped_loc_port = cm_info.loc_port;
cm_node = g_cm_core->api->listen(g_cm_core, nesvnic, &cm_info); cm_node = g_cm_core->api->listen(g_cm_core, nesvnic, &cm_info);
if (!cm_node) { if (!cm_node) {
@ -3442,7 +3637,10 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
cm_id->provider_data = cm_node; cm_id->provider_data = cm_node;
if (!cm_node->reused_node) { if (!cm_node->reused_node) {
err = nes_manage_apbvt(nesvnic, ntohs(laddr->sin_port), if (nes_create_mapinfo(&cm_info))
return -ENOMEM;
err = nes_manage_apbvt(nesvnic, cm_node->mapped_loc_port,
PCI_FUNC(nesvnic->nesdev->pcidev->devfn), PCI_FUNC(nesvnic->nesdev->pcidev->devfn),
NES_MANAGE_APBVT_ADD); NES_MANAGE_APBVT_ADD);
if (err) { if (err) {
@ -3567,9 +3765,11 @@ static void cm_event_connected(struct nes_cm_event *event)
nes_cm_init_tsa_conn(nesqp, cm_node); nes_cm_init_tsa_conn(nesqp, cm_node);
/* set the QP tsa context */ /* set the QP tsa context */
nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(laddr->sin_port)); nesqp->nesqp_context->tcpPorts[0] =
nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(raddr->sin_port)); cpu_to_le16(cm_node->mapped_loc_port);
nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(raddr->sin_addr.s_addr)); nesqp->nesqp_context->tcpPorts[1] =
cpu_to_le16(cm_node->mapped_rem_port);
nesqp->nesqp_context->ip0 = cpu_to_le32(cm_node->mapped_rem_addr);
nesqp->nesqp_context->misc2 |= cpu_to_le32( nesqp->nesqp_context->misc2 |= cpu_to_le32(
(u32)PCI_FUNC(nesdev->pcidev->devfn) << (u32)PCI_FUNC(nesdev->pcidev->devfn) <<
@ -3599,9 +3799,9 @@ static void cm_event_connected(struct nes_cm_event *event)
nes_quad.DstIpAdrIndex = nes_quad.DstIpAdrIndex =
cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24); cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
nes_quad.SrcIpadr = raddr->sin_addr.s_addr; nes_quad.SrcIpadr = htonl(cm_node->mapped_rem_addr);
nes_quad.TcpPorts[0] = raddr->sin_port; nes_quad.TcpPorts[0] = htons(cm_node->mapped_rem_port);
nes_quad.TcpPorts[1] = laddr->sin_port; nes_quad.TcpPorts[1] = htons(cm_node->mapped_loc_port);
/* Produce hash key */ /* Produce hash key */
crc_value = get_crc_value(&nes_quad); crc_value = get_crc_value(&nes_quad);
@ -3629,7 +3829,7 @@ static void cm_event_connected(struct nes_cm_event *event)
cm_event.ird = cm_node->ird_size; cm_event.ird = cm_node->ird_size;
cm_event.ord = cm_node->ord_size; cm_event.ord = cm_node->ord_size;
cm_event_laddr->sin_addr.s_addr = event->cm_info.rem_addr; cm_event_laddr->sin_addr.s_addr = htonl(event->cm_info.rem_addr);
ret = cm_id->event_handler(cm_id, &cm_event); ret = cm_id->event_handler(cm_id, &cm_event);
nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret); nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved. * Copyright (c) 2006 - 2014 Intel Corporation. All rights reserved.
* *
* This software is available to you under a choice of one of two * This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU * licenses. You may choose to be licensed under the terms of the GNU
@ -293,8 +293,8 @@ struct nes_cm_listener {
struct list_head list; struct list_head list;
struct nes_cm_core *cm_core; struct nes_cm_core *cm_core;
u8 loc_mac[ETH_ALEN]; u8 loc_mac[ETH_ALEN];
nes_addr_t loc_addr; nes_addr_t loc_addr, mapped_loc_addr;
u16 loc_port; u16 loc_port, mapped_loc_port;
struct iw_cm_id *cm_id; struct iw_cm_id *cm_id;
enum nes_cm_conn_type conn_type; enum nes_cm_conn_type conn_type;
atomic_t ref_count; atomic_t ref_count;
@ -308,7 +308,9 @@ struct nes_cm_listener {
/* per connection node and node state information */ /* per connection node and node state information */
struct nes_cm_node { struct nes_cm_node {
nes_addr_t loc_addr, rem_addr; nes_addr_t loc_addr, rem_addr;
nes_addr_t mapped_loc_addr, mapped_rem_addr;
u16 loc_port, rem_port; u16 loc_port, rem_port;
u16 mapped_loc_port, mapped_rem_port;
u8 loc_mac[ETH_ALEN]; u8 loc_mac[ETH_ALEN];
u8 rem_mac[ETH_ALEN]; u8 rem_mac[ETH_ALEN];
@ -364,6 +366,10 @@ struct nes_cm_info {
u16 rem_port; u16 rem_port;
nes_addr_t loc_addr; nes_addr_t loc_addr;
nes_addr_t rem_addr; nes_addr_t rem_addr;
u16 mapped_loc_port;
u16 mapped_rem_port;
nes_addr_t mapped_loc_addr;
nes_addr_t mapped_rem_addr;
enum nes_cm_conn_type conn_type; enum nes_cm_conn_type conn_type;
int backlog; int backlog;

View file

@ -510,16 +510,9 @@ exit:
return status; return status;
} }
static int ocrdma_debugfs_open(struct inode *inode, struct file *file)
{
if (inode->i_private)
file->private_data = inode->i_private;
return 0;
}
static const struct file_operations ocrdma_dbg_ops = { static const struct file_operations ocrdma_dbg_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = ocrdma_debugfs_open, .open = simple_open,
.read = ocrdma_dbgfs_ops_read, .read = ocrdma_dbgfs_ops_read,
}; };

View file

@ -1272,7 +1272,7 @@ static int qib_notify_dca(struct notifier_block *nb, unsigned long event,
* Do all the generic driver unit- and chip-independent memory * Do all the generic driver unit- and chip-independent memory
* allocation and initialization. * allocation and initialization.
*/ */
static int __init qlogic_ib_init(void) static int __init qib_ib_init(void)
{ {
int ret; int ret;
@ -1316,12 +1316,12 @@ bail:
return ret; return ret;
} }
module_init(qlogic_ib_init); module_init(qib_ib_init);
/* /*
* Do the non-unit driver cleanup, memory free, etc. at unload. * Do the non-unit driver cleanup, memory free, etc. at unload.
*/ */
static void __exit qlogic_ib_cleanup(void) static void __exit qib_ib_cleanup(void)
{ {
int ret; int ret;
@ -1346,7 +1346,7 @@ static void __exit qlogic_ib_cleanup(void)
qib_dev_cleanup(); qib_dev_cleanup();
} }
module_exit(qlogic_ib_cleanup); module_exit(qib_ib_cleanup);
/* this can only be called after a successful initialization */ /* this can only be called after a successful initialization */
static void cleanup_device_data(struct qib_devdata *dd) static void cleanup_device_data(struct qib_devdata *dd)

View file

@ -1028,7 +1028,7 @@ static int set_pkeys(struct qib_devdata *dd, u8 port, u16 *pkeys)
event.event = IB_EVENT_PKEY_CHANGE; event.event = IB_EVENT_PKEY_CHANGE;
event.device = &dd->verbs_dev.ibdev; event.device = &dd->verbs_dev.ibdev;
event.element.port_num = 1; event.element.port_num = port;
ib_dispatch_event(&event); ib_dispatch_event(&event);
} }
return 0; return 0;

View file

@ -985,7 +985,8 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd,
struct ib_qp *ret; struct ib_qp *ret;
if (init_attr->cap.max_send_sge > ib_qib_max_sges || if (init_attr->cap.max_send_sge > ib_qib_max_sges ||
init_attr->cap.max_send_wr > ib_qib_max_qp_wrs) { init_attr->cap.max_send_wr > ib_qib_max_qp_wrs ||
init_attr->create_flags) {
ret = ERR_PTR(-EINVAL); ret = ERR_PTR(-EINVAL);
goto bail; goto bail;
} }

View file

@ -466,6 +466,9 @@ struct ib_qp *usnic_ib_create_qp(struct ib_pd *pd,
ucontext = to_uucontext(pd->uobject->context); ucontext = to_uucontext(pd->uobject->context);
us_ibdev = to_usdev(pd->device); us_ibdev = to_usdev(pd->device);
if (init_attr->create_flags)
return ERR_PTR(-EINVAL);
err = ib_copy_from_udata(&cmd, udata, sizeof(cmd)); err = ib_copy_from_udata(&cmd, udata, sizeof(cmd));
if (err) { if (err) {
usnic_err("%s: cannot copy udata for create_qp\n", usnic_err("%s: cannot copy udata for create_qp\n",

View file

@ -1,3 +1,21 @@
/*
* Copyright (c) 2014, Cisco Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#include <linux/init.h> #include <linux/init.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/slab.h> #include <linux/slab.h>

View file

@ -0,0 +1,5 @@
obj-$(CONFIG_INFINIBAND_IPOIB) += ipoib/
obj-$(CONFIG_INFINIBAND_SRP) += srp/
obj-$(CONFIG_INFINIBAND_SRPT) += srpt/
obj-$(CONFIG_INFINIBAND_ISER) += iser/
obj-$(CONFIG_INFINIBAND_ISERT) += isert/

View file

@ -1030,10 +1030,20 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_
.cap.max_send_sge = 1, .cap.max_send_sge = 1,
.sq_sig_type = IB_SIGNAL_ALL_WR, .sq_sig_type = IB_SIGNAL_ALL_WR,
.qp_type = IB_QPT_RC, .qp_type = IB_QPT_RC,
.qp_context = tx .qp_context = tx,
.create_flags = IB_QP_CREATE_USE_GFP_NOIO
}; };
return ib_create_qp(priv->pd, &attr); struct ib_qp *tx_qp;
tx_qp = ib_create_qp(priv->pd, &attr);
if (PTR_ERR(tx_qp) == -EINVAL) {
ipoib_warn(priv, "can't use GFP_NOIO for QPs on device %s, using GFP_KERNEL\n",
priv->ca->name);
attr.create_flags &= ~IB_QP_CREATE_USE_GFP_NOIO;
tx_qp = ib_create_qp(priv->pd, &attr);
}
return tx_qp;
} }
static int ipoib_cm_send_req(struct net_device *dev, static int ipoib_cm_send_req(struct net_device *dev,
@ -1104,12 +1114,14 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn,
struct ipoib_dev_priv *priv = netdev_priv(p->dev); struct ipoib_dev_priv *priv = netdev_priv(p->dev);
int ret; int ret;
p->tx_ring = vzalloc(ipoib_sendq_size * sizeof *p->tx_ring); p->tx_ring = __vmalloc(ipoib_sendq_size * sizeof *p->tx_ring,
GFP_NOIO, PAGE_KERNEL);
if (!p->tx_ring) { if (!p->tx_ring) {
ipoib_warn(priv, "failed to allocate tx ring\n"); ipoib_warn(priv, "failed to allocate tx ring\n");
ret = -ENOMEM; ret = -ENOMEM;
goto err_tx; goto err_tx;
} }
memset(p->tx_ring, 0, ipoib_sendq_size * sizeof *p->tx_ring);
p->qp = ipoib_cm_create_tx_qp(p->dev, p); p->qp = ipoib_cm_create_tx_qp(p->dev, p);
if (IS_ERR(p->qp)) { if (IS_ERR(p->qp)) {

View file

@ -99,6 +99,7 @@ MODULE_PARM_DESC(pi_enable, "Enable T10-PI offload support (default:disabled)");
module_param_named(pi_guard, iser_pi_guard, int, 0644); module_param_named(pi_guard, iser_pi_guard, int, 0644);
MODULE_PARM_DESC(pi_guard, "T10-PI guard_type, 0:CRC|1:IP_CSUM (default:CRC)"); MODULE_PARM_DESC(pi_guard, "T10-PI guard_type, 0:CRC|1:IP_CSUM (default:CRC)");
static struct workqueue_struct *release_wq;
struct iser_global ig; struct iser_global ig;
void void
@ -337,24 +338,6 @@ iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
return cls_conn; return cls_conn;
} }
static void
iscsi_iser_conn_destroy(struct iscsi_cls_conn *cls_conn)
{
struct iscsi_conn *conn = cls_conn->dd_data;
struct iser_conn *ib_conn = conn->dd_data;
iscsi_conn_teardown(cls_conn);
/*
* Userspace will normally call the stop callback and
* already have freed the ib_conn, but if it goofed up then
* we free it here.
*/
if (ib_conn) {
ib_conn->iscsi_conn = NULL;
iser_conn_put(ib_conn, 1); /* deref iscsi/ib conn unbinding */
}
}
static int static int
iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session, iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, struct iscsi_cls_conn *cls_conn, uint64_t transport_eph,
@ -392,29 +375,39 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
conn->dd_data = ib_conn; conn->dd_data = ib_conn;
ib_conn->iscsi_conn = conn; ib_conn->iscsi_conn = conn;
iser_conn_get(ib_conn); /* ref iscsi/ib conn binding */
return 0; return 0;
} }
static int
iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn)
{
struct iscsi_conn *iscsi_conn;
struct iser_conn *ib_conn;
iscsi_conn = cls_conn->dd_data;
ib_conn = iscsi_conn->dd_data;
reinit_completion(&ib_conn->stop_completion);
return iscsi_conn_start(cls_conn);
}
static void static void
iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
{ {
struct iscsi_conn *conn = cls_conn->dd_data; struct iscsi_conn *conn = cls_conn->dd_data;
struct iser_conn *ib_conn = conn->dd_data; struct iser_conn *ib_conn = conn->dd_data;
iser_dbg("stopping iscsi_conn: %p, ib_conn: %p\n", conn, ib_conn);
iscsi_conn_stop(cls_conn, flag);
/* /*
* Userspace may have goofed up and not bound the connection or * Userspace may have goofed up and not bound the connection or
* might have only partially setup the connection. * might have only partially setup the connection.
*/ */
if (ib_conn) { if (ib_conn) {
iscsi_conn_stop(cls_conn, flag); conn->dd_data = NULL;
/* complete(&ib_conn->stop_completion);
* There is no unbind event so the stop callback
* must release the ref from the bind.
*/
iser_conn_put(ib_conn, 1); /* deref iscsi/ib conn unbinding */
} }
conn->dd_data = NULL;
} }
static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session) static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session)
@ -515,28 +508,28 @@ iscsi_iser_set_param(struct iscsi_cls_conn *cls_conn,
case ISCSI_PARAM_HDRDGST_EN: case ISCSI_PARAM_HDRDGST_EN:
sscanf(buf, "%d", &value); sscanf(buf, "%d", &value);
if (value) { if (value) {
iser_err("DataDigest wasn't negotiated to None"); iser_err("DataDigest wasn't negotiated to None\n");
return -EPROTO; return -EPROTO;
} }
break; break;
case ISCSI_PARAM_DATADGST_EN: case ISCSI_PARAM_DATADGST_EN:
sscanf(buf, "%d", &value); sscanf(buf, "%d", &value);
if (value) { if (value) {
iser_err("DataDigest wasn't negotiated to None"); iser_err("DataDigest wasn't negotiated to None\n");
return -EPROTO; return -EPROTO;
} }
break; break;
case ISCSI_PARAM_IFMARKER_EN: case ISCSI_PARAM_IFMARKER_EN:
sscanf(buf, "%d", &value); sscanf(buf, "%d", &value);
if (value) { if (value) {
iser_err("IFMarker wasn't negotiated to No"); iser_err("IFMarker wasn't negotiated to No\n");
return -EPROTO; return -EPROTO;
} }
break; break;
case ISCSI_PARAM_OFMARKER_EN: case ISCSI_PARAM_OFMARKER_EN:
sscanf(buf, "%d", &value); sscanf(buf, "%d", &value);
if (value) { if (value) {
iser_err("OFMarker wasn't negotiated to No"); iser_err("OFMarker wasn't negotiated to No\n");
return -EPROTO; return -EPROTO;
} }
break; break;
@ -652,19 +645,20 @@ iscsi_iser_ep_disconnect(struct iscsi_endpoint *ep)
struct iser_conn *ib_conn; struct iser_conn *ib_conn;
ib_conn = ep->dd_data; ib_conn = ep->dd_data;
if (ib_conn->iscsi_conn) iser_info("ep %p ib conn %p state %d\n", ep, ib_conn, ib_conn->state);
/*
* Must suspend xmit path if the ep is bound to the
* iscsi_conn, so we know we are not accessing the ib_conn
* when we free it.
*
* This may not be bound if the ep poll failed.
*/
iscsi_suspend_tx(ib_conn->iscsi_conn);
iser_info("ib conn %p state %d\n", ib_conn, ib_conn->state);
iser_conn_terminate(ib_conn); iser_conn_terminate(ib_conn);
/*
* if iser_conn and iscsi_conn are bound, we must wait iscsi_conn_stop
* call and ISER_CONN_DOWN state before freeing the iser resources.
* otherwise we are safe to free resources immediately.
*/
if (ib_conn->iscsi_conn) {
INIT_WORK(&ib_conn->release_work, iser_release_work);
queue_work(release_wq, &ib_conn->release_work);
} else {
iser_conn_release(ib_conn);
}
} }
static umode_t iser_attr_is_visible(int param_type, int param) static umode_t iser_attr_is_visible(int param_type, int param)
@ -748,13 +742,13 @@ static struct iscsi_transport iscsi_iser_transport = {
/* connection management */ /* connection management */
.create_conn = iscsi_iser_conn_create, .create_conn = iscsi_iser_conn_create,
.bind_conn = iscsi_iser_conn_bind, .bind_conn = iscsi_iser_conn_bind,
.destroy_conn = iscsi_iser_conn_destroy, .destroy_conn = iscsi_conn_teardown,
.attr_is_visible = iser_attr_is_visible, .attr_is_visible = iser_attr_is_visible,
.set_param = iscsi_iser_set_param, .set_param = iscsi_iser_set_param,
.get_conn_param = iscsi_conn_get_param, .get_conn_param = iscsi_conn_get_param,
.get_ep_param = iscsi_iser_get_ep_param, .get_ep_param = iscsi_iser_get_ep_param,
.get_session_param = iscsi_session_get_param, .get_session_param = iscsi_session_get_param,
.start_conn = iscsi_conn_start, .start_conn = iscsi_iser_conn_start,
.stop_conn = iscsi_iser_conn_stop, .stop_conn = iscsi_iser_conn_stop,
/* iscsi host params */ /* iscsi host params */
.get_host_param = iscsi_host_get_param, .get_host_param = iscsi_host_get_param,
@ -801,6 +795,12 @@ static int __init iser_init(void)
mutex_init(&ig.connlist_mutex); mutex_init(&ig.connlist_mutex);
INIT_LIST_HEAD(&ig.connlist); INIT_LIST_HEAD(&ig.connlist);
release_wq = alloc_workqueue("release workqueue", 0, 0);
if (!release_wq) {
iser_err("failed to allocate release workqueue\n");
return -ENOMEM;
}
iscsi_iser_scsi_transport = iscsi_register_transport( iscsi_iser_scsi_transport = iscsi_register_transport(
&iscsi_iser_transport); &iscsi_iser_transport);
if (!iscsi_iser_scsi_transport) { if (!iscsi_iser_scsi_transport) {
@ -819,7 +819,24 @@ register_transport_failure:
static void __exit iser_exit(void) static void __exit iser_exit(void)
{ {
struct iser_conn *ib_conn, *n;
int connlist_empty;
iser_dbg("Removing iSER datamover...\n"); iser_dbg("Removing iSER datamover...\n");
destroy_workqueue(release_wq);
mutex_lock(&ig.connlist_mutex);
connlist_empty = list_empty(&ig.connlist);
mutex_unlock(&ig.connlist_mutex);
if (!connlist_empty) {
iser_err("Error cleanup stage completed but we still have iser "
"connections, destroying them anyway.\n");
list_for_each_entry_safe(ib_conn, n, &ig.connlist, conn_list) {
iser_conn_release(ib_conn);
}
}
iscsi_unregister_transport(&iscsi_iser_transport); iscsi_unregister_transport(&iscsi_iser_transport);
kmem_cache_destroy(ig.desc_cache); kmem_cache_destroy(ig.desc_cache);
} }

View file

@ -69,7 +69,7 @@
#define DRV_NAME "iser" #define DRV_NAME "iser"
#define PFX DRV_NAME ": " #define PFX DRV_NAME ": "
#define DRV_VER "1.3" #define DRV_VER "1.4"
#define iser_dbg(fmt, arg...) \ #define iser_dbg(fmt, arg...) \
do { \ do { \
@ -333,6 +333,8 @@ struct iser_conn {
int post_recv_buf_count; /* posted rx count */ int post_recv_buf_count; /* posted rx count */
atomic_t post_send_buf_count; /* posted tx count */ atomic_t post_send_buf_count; /* posted tx count */
char name[ISER_OBJECT_NAME_SIZE]; char name[ISER_OBJECT_NAME_SIZE];
struct work_struct release_work;
struct completion stop_completion;
struct list_head conn_list; /* entry in ig conn list */ struct list_head conn_list; /* entry in ig conn list */
char *login_buf; char *login_buf;
@ -417,12 +419,12 @@ void iscsi_iser_recv(struct iscsi_conn *conn,
void iser_conn_init(struct iser_conn *ib_conn); void iser_conn_init(struct iser_conn *ib_conn);
void iser_conn_get(struct iser_conn *ib_conn); void iser_conn_release(struct iser_conn *ib_conn);
int iser_conn_put(struct iser_conn *ib_conn, int destroy_cma_id_allowed);
void iser_conn_terminate(struct iser_conn *ib_conn); void iser_conn_terminate(struct iser_conn *ib_conn);
void iser_release_work(struct work_struct *work);
void iser_rcv_completion(struct iser_rx_desc *desc, void iser_rcv_completion(struct iser_rx_desc *desc,
unsigned long dto_xfer_len, unsigned long dto_xfer_len,
struct iser_conn *ib_conn); struct iser_conn *ib_conn);

View file

@ -581,14 +581,30 @@ static int iser_conn_state_comp_exch(struct iser_conn *ib_conn,
return ret; return ret;
} }
void iser_release_work(struct work_struct *work)
{
struct iser_conn *ib_conn;
ib_conn = container_of(work, struct iser_conn, release_work);
/* wait for .conn_stop callback */
wait_for_completion(&ib_conn->stop_completion);
/* wait for the qp`s post send and post receive buffers to empty */
wait_event_interruptible(ib_conn->wait,
ib_conn->state == ISER_CONN_DOWN);
iser_conn_release(ib_conn);
}
/** /**
* Frees all conn objects and deallocs conn descriptor * Frees all conn objects and deallocs conn descriptor
*/ */
static void iser_conn_release(struct iser_conn *ib_conn, int can_destroy_id) void iser_conn_release(struct iser_conn *ib_conn)
{ {
struct iser_device *device = ib_conn->device; struct iser_device *device = ib_conn->device;
BUG_ON(ib_conn->state != ISER_CONN_DOWN); BUG_ON(ib_conn->state == ISER_CONN_UP);
mutex_lock(&ig.connlist_mutex); mutex_lock(&ig.connlist_mutex);
list_del(&ib_conn->conn_list); list_del(&ib_conn->conn_list);
@ -600,27 +616,13 @@ static void iser_conn_release(struct iser_conn *ib_conn, int can_destroy_id)
if (device != NULL) if (device != NULL)
iser_device_try_release(device); iser_device_try_release(device);
/* if cma handler context, the caller actually destroy the id */ /* if cma handler context, the caller actually destroy the id */
if (ib_conn->cma_id != NULL && can_destroy_id) { if (ib_conn->cma_id != NULL) {
rdma_destroy_id(ib_conn->cma_id); rdma_destroy_id(ib_conn->cma_id);
ib_conn->cma_id = NULL; ib_conn->cma_id = NULL;
} }
iscsi_destroy_endpoint(ib_conn->ep); iscsi_destroy_endpoint(ib_conn->ep);
} }
void iser_conn_get(struct iser_conn *ib_conn)
{
atomic_inc(&ib_conn->refcount);
}
int iser_conn_put(struct iser_conn *ib_conn, int can_destroy_id)
{
if (atomic_dec_and_test(&ib_conn->refcount)) {
iser_conn_release(ib_conn, can_destroy_id);
return 1;
}
return 0;
}
/** /**
* triggers start of the disconnect procedures and wait for them to be done * triggers start of the disconnect procedures and wait for them to be done
*/ */
@ -638,24 +640,19 @@ void iser_conn_terminate(struct iser_conn *ib_conn)
if (err) if (err)
iser_err("Failed to disconnect, conn: 0x%p err %d\n", iser_err("Failed to disconnect, conn: 0x%p err %d\n",
ib_conn,err); ib_conn,err);
wait_event_interruptible(ib_conn->wait,
ib_conn->state == ISER_CONN_DOWN);
iser_conn_put(ib_conn, 1); /* deref ib conn deallocate */
} }
static int iser_connect_error(struct rdma_cm_id *cma_id) static void iser_connect_error(struct rdma_cm_id *cma_id)
{ {
struct iser_conn *ib_conn; struct iser_conn *ib_conn;
ib_conn = (struct iser_conn *)cma_id->context; ib_conn = (struct iser_conn *)cma_id->context;
ib_conn->state = ISER_CONN_DOWN; ib_conn->state = ISER_CONN_DOWN;
wake_up_interruptible(&ib_conn->wait); wake_up_interruptible(&ib_conn->wait);
return iser_conn_put(ib_conn, 0); /* deref ib conn's cma id */
} }
static int iser_addr_handler(struct rdma_cm_id *cma_id) static void iser_addr_handler(struct rdma_cm_id *cma_id)
{ {
struct iser_device *device; struct iser_device *device;
struct iser_conn *ib_conn; struct iser_conn *ib_conn;
@ -664,7 +661,8 @@ static int iser_addr_handler(struct rdma_cm_id *cma_id)
device = iser_device_find_by_ib_device(cma_id); device = iser_device_find_by_ib_device(cma_id);
if (!device) { if (!device) {
iser_err("device lookup/creation failed\n"); iser_err("device lookup/creation failed\n");
return iser_connect_error(cma_id); iser_connect_error(cma_id);
return;
} }
ib_conn = (struct iser_conn *)cma_id->context; ib_conn = (struct iser_conn *)cma_id->context;
@ -686,13 +684,12 @@ static int iser_addr_handler(struct rdma_cm_id *cma_id)
ret = rdma_resolve_route(cma_id, 1000); ret = rdma_resolve_route(cma_id, 1000);
if (ret) { if (ret) {
iser_err("resolve route failed: %d\n", ret); iser_err("resolve route failed: %d\n", ret);
return iser_connect_error(cma_id); iser_connect_error(cma_id);
return;
} }
return 0;
} }
static int iser_route_handler(struct rdma_cm_id *cma_id) static void iser_route_handler(struct rdma_cm_id *cma_id)
{ {
struct rdma_conn_param conn_param; struct rdma_conn_param conn_param;
int ret; int ret;
@ -720,9 +717,9 @@ static int iser_route_handler(struct rdma_cm_id *cma_id)
goto failure; goto failure;
} }
return 0; return;
failure: failure:
return iser_connect_error(cma_id); iser_connect_error(cma_id);
} }
static void iser_connected_handler(struct rdma_cm_id *cma_id) static void iser_connected_handler(struct rdma_cm_id *cma_id)
@ -735,14 +732,13 @@ static void iser_connected_handler(struct rdma_cm_id *cma_id)
iser_info("remote qpn:%x my qpn:%x\n", attr.dest_qp_num, cma_id->qp->qp_num); iser_info("remote qpn:%x my qpn:%x\n", attr.dest_qp_num, cma_id->qp->qp_num);
ib_conn = (struct iser_conn *)cma_id->context; ib_conn = (struct iser_conn *)cma_id->context;
ib_conn->state = ISER_CONN_UP; if (iser_conn_state_comp_exch(ib_conn, ISER_CONN_PENDING, ISER_CONN_UP))
wake_up_interruptible(&ib_conn->wait); wake_up_interruptible(&ib_conn->wait);
} }
static int iser_disconnected_handler(struct rdma_cm_id *cma_id) static void iser_disconnected_handler(struct rdma_cm_id *cma_id)
{ {
struct iser_conn *ib_conn; struct iser_conn *ib_conn;
int ret;
ib_conn = (struct iser_conn *)cma_id->context; ib_conn = (struct iser_conn *)cma_id->context;
@ -762,24 +758,19 @@ static int iser_disconnected_handler(struct rdma_cm_id *cma_id)
ib_conn->state = ISER_CONN_DOWN; ib_conn->state = ISER_CONN_DOWN;
wake_up_interruptible(&ib_conn->wait); wake_up_interruptible(&ib_conn->wait);
} }
ret = iser_conn_put(ib_conn, 0); /* deref ib conn's cma id */
return ret;
} }
static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
{ {
int ret = 0;
iser_info("event %d status %d conn %p id %p\n", iser_info("event %d status %d conn %p id %p\n",
event->event, event->status, cma_id->context, cma_id); event->event, event->status, cma_id->context, cma_id);
switch (event->event) { switch (event->event) {
case RDMA_CM_EVENT_ADDR_RESOLVED: case RDMA_CM_EVENT_ADDR_RESOLVED:
ret = iser_addr_handler(cma_id); iser_addr_handler(cma_id);
break; break;
case RDMA_CM_EVENT_ROUTE_RESOLVED: case RDMA_CM_EVENT_ROUTE_RESOLVED:
ret = iser_route_handler(cma_id); iser_route_handler(cma_id);
break; break;
case RDMA_CM_EVENT_ESTABLISHED: case RDMA_CM_EVENT_ESTABLISHED:
iser_connected_handler(cma_id); iser_connected_handler(cma_id);
@ -789,18 +780,18 @@ static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *eve
case RDMA_CM_EVENT_CONNECT_ERROR: case RDMA_CM_EVENT_CONNECT_ERROR:
case RDMA_CM_EVENT_UNREACHABLE: case RDMA_CM_EVENT_UNREACHABLE:
case RDMA_CM_EVENT_REJECTED: case RDMA_CM_EVENT_REJECTED:
ret = iser_connect_error(cma_id); iser_connect_error(cma_id);
break; break;
case RDMA_CM_EVENT_DISCONNECTED: case RDMA_CM_EVENT_DISCONNECTED:
case RDMA_CM_EVENT_DEVICE_REMOVAL: case RDMA_CM_EVENT_DEVICE_REMOVAL:
case RDMA_CM_EVENT_ADDR_CHANGE: case RDMA_CM_EVENT_ADDR_CHANGE:
ret = iser_disconnected_handler(cma_id); iser_disconnected_handler(cma_id);
break; break;
default: default:
iser_err("Unexpected RDMA CM event (%d)\n", event->event); iser_err("Unexpected RDMA CM event (%d)\n", event->event);
break; break;
} }
return ret; return 0;
} }
void iser_conn_init(struct iser_conn *ib_conn) void iser_conn_init(struct iser_conn *ib_conn)
@ -809,7 +800,7 @@ void iser_conn_init(struct iser_conn *ib_conn)
init_waitqueue_head(&ib_conn->wait); init_waitqueue_head(&ib_conn->wait);
ib_conn->post_recv_buf_count = 0; ib_conn->post_recv_buf_count = 0;
atomic_set(&ib_conn->post_send_buf_count, 0); atomic_set(&ib_conn->post_send_buf_count, 0);
atomic_set(&ib_conn->refcount, 1); /* ref ib conn allocation */ init_completion(&ib_conn->stop_completion);
INIT_LIST_HEAD(&ib_conn->conn_list); INIT_LIST_HEAD(&ib_conn->conn_list);
spin_lock_init(&ib_conn->lock); spin_lock_init(&ib_conn->lock);
} }
@ -837,7 +828,6 @@ int iser_connect(struct iser_conn *ib_conn,
ib_conn->state = ISER_CONN_PENDING; ib_conn->state = ISER_CONN_PENDING;
iser_conn_get(ib_conn); /* ref ib conn's cma id */
ib_conn->cma_id = rdma_create_id(iser_cma_handler, ib_conn->cma_id = rdma_create_id(iser_cma_handler,
(void *)ib_conn, (void *)ib_conn,
RDMA_PS_TCP, IB_QPT_RC); RDMA_PS_TCP, IB_QPT_RC);
@ -874,9 +864,8 @@ id_failure:
ib_conn->cma_id = NULL; ib_conn->cma_id = NULL;
addr_failure: addr_failure:
ib_conn->state = ISER_CONN_DOWN; ib_conn->state = ISER_CONN_DOWN;
iser_conn_put(ib_conn, 1); /* deref ib conn's cma id */
connect_failure: connect_failure:
iser_conn_put(ib_conn, 1); /* deref ib conn deallocate */ iser_conn_release(ib_conn);
return err; return err;
} }

File diff suppressed because it is too large Load diff

View file

@ -66,13 +66,10 @@ enum {
SRP_TAG_NO_REQ = ~0U, SRP_TAG_NO_REQ = ~0U,
SRP_TAG_TSK_MGMT = 1U << 31, SRP_TAG_TSK_MGMT = 1U << 31,
SRP_FMR_SIZE = 512, SRP_MAX_PAGES_PER_MR = 512,
SRP_FMR_MIN_SIZE = 128,
SRP_FMR_POOL_SIZE = 1024,
SRP_FMR_DIRTY_SIZE = SRP_FMR_POOL_SIZE / 4,
SRP_MAP_ALLOW_FMR = 0, LOCAL_INV_WR_ID_MASK = 1,
SRP_MAP_NO_FMR = 1, FAST_REG_WR_ID_MASK = 2,
}; };
enum srp_target_state { enum srp_target_state {
@ -86,15 +83,24 @@ enum srp_iu_type {
SRP_IU_RSP, SRP_IU_RSP,
}; };
/*
* @mr_page_mask: HCA memory registration page mask.
* @mr_page_size: HCA memory registration page size.
* @mr_max_size: Maximum size in bytes of a single FMR / FR registration
* request.
*/
struct srp_device { struct srp_device {
struct list_head dev_list; struct list_head dev_list;
struct ib_device *dev; struct ib_device *dev;
struct ib_pd *pd; struct ib_pd *pd;
struct ib_mr *mr; struct ib_mr *mr;
struct ib_fmr_pool *fmr_pool; u64 mr_page_mask;
u64 fmr_page_mask; int mr_page_size;
int fmr_page_size; int mr_max_size;
int fmr_max_size; int max_pages_per_mr;
bool has_fmr;
bool has_fr;
bool use_fast_reg;
}; };
struct srp_host { struct srp_host {
@ -112,11 +118,14 @@ struct srp_request {
struct list_head list; struct list_head list;
struct scsi_cmnd *scmnd; struct scsi_cmnd *scmnd;
struct srp_iu *cmd; struct srp_iu *cmd;
struct ib_pool_fmr **fmr_list; union {
struct ib_pool_fmr **fmr_list;
struct srp_fr_desc **fr_list;
};
u64 *map_page; u64 *map_page;
struct srp_direct_buf *indirect_desc; struct srp_direct_buf *indirect_desc;
dma_addr_t indirect_dma_addr; dma_addr_t indirect_dma_addr;
short nfmr; short nmdesc;
short index; short index;
}; };
@ -131,6 +140,10 @@ struct srp_target_port {
struct ib_cq *send_cq ____cacheline_aligned_in_smp; struct ib_cq *send_cq ____cacheline_aligned_in_smp;
struct ib_cq *recv_cq; struct ib_cq *recv_cq;
struct ib_qp *qp; struct ib_qp *qp;
union {
struct ib_fmr_pool *fmr_pool;
struct srp_fr_pool *fr_pool;
};
u32 lkey; u32 lkey;
u32 rkey; u32 rkey;
enum srp_target_state state; enum srp_target_state state;
@ -197,15 +210,66 @@ struct srp_iu {
enum dma_data_direction direction; enum dma_data_direction direction;
}; };
/**
* struct srp_fr_desc - fast registration work request arguments
* @entry: Entry in srp_fr_pool.free_list.
* @mr: Memory region.
* @frpl: Fast registration page list.
*/
struct srp_fr_desc {
struct list_head entry;
struct ib_mr *mr;
struct ib_fast_reg_page_list *frpl;
};
/**
* struct srp_fr_pool - pool of fast registration descriptors
*
* An entry is available for allocation if and only if it occurs in @free_list.
*
* @size: Number of descriptors in this pool.
* @max_page_list_len: Maximum fast registration work request page list length.
* @lock: Protects free_list.
* @free_list: List of free descriptors.
* @desc: Fast registration descriptor pool.
*/
struct srp_fr_pool {
int size;
int max_page_list_len;
spinlock_t lock;
struct list_head free_list;
struct srp_fr_desc desc[0];
};
/**
* struct srp_map_state - per-request DMA memory mapping state
* @desc: Pointer to the element of the SRP buffer descriptor array
* that is being filled in.
* @pages: Array with DMA addresses of pages being considered for
* memory registration.
* @base_dma_addr: DMA address of the first page that has not yet been mapped.
* @dma_len: Number of bytes that will be registered with the next
* FMR or FR memory registration call.
* @total_len: Total number of bytes in the sg-list being mapped.
* @npages: Number of page addresses in the pages[] array.
* @nmdesc: Number of FMR or FR memory descriptors used for mapping.
* @ndesc: Number of SRP buffer descriptors that have been filled in.
* @unmapped_sg: First element of the sg-list that is mapped via FMR or FR.
* @unmapped_index: Index of the first element mapped via FMR or FR.
* @unmapped_addr: DMA address of the first element mapped via FMR or FR.
*/
struct srp_map_state { struct srp_map_state {
struct ib_pool_fmr **next_fmr; union {
struct ib_pool_fmr **next_fmr;
struct srp_fr_desc **next_fr;
};
struct srp_direct_buf *desc; struct srp_direct_buf *desc;
u64 *pages; u64 *pages;
dma_addr_t base_dma_addr; dma_addr_t base_dma_addr;
u32 fmr_len; u32 dma_len;
u32 total_len; u32 total_len;
unsigned int npages; unsigned int npages;
unsigned int nfmr; unsigned int nmdesc;
unsigned int ndesc; unsigned int ndesc;
struct scatterlist *unmapped_sg; struct scatterlist *unmapped_sg;
int unmapped_index; int unmapped_index;

View file

@ -171,7 +171,7 @@ void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap)
*/ */
int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
struct mlx4_buf *buf) struct mlx4_buf *buf, gfp_t gfp)
{ {
dma_addr_t t; dma_addr_t t;
@ -180,7 +180,7 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
buf->npages = 1; buf->npages = 1;
buf->page_shift = get_order(size) + PAGE_SHIFT; buf->page_shift = get_order(size) + PAGE_SHIFT;
buf->direct.buf = dma_alloc_coherent(&dev->pdev->dev, buf->direct.buf = dma_alloc_coherent(&dev->pdev->dev,
size, &t, GFP_KERNEL); size, &t, gfp);
if (!buf->direct.buf) if (!buf->direct.buf)
return -ENOMEM; return -ENOMEM;
@ -200,14 +200,14 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
buf->npages = buf->nbufs; buf->npages = buf->nbufs;
buf->page_shift = PAGE_SHIFT; buf->page_shift = PAGE_SHIFT;
buf->page_list = kcalloc(buf->nbufs, sizeof(*buf->page_list), buf->page_list = kcalloc(buf->nbufs, sizeof(*buf->page_list),
GFP_KERNEL); gfp);
if (!buf->page_list) if (!buf->page_list)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < buf->nbufs; ++i) { for (i = 0; i < buf->nbufs; ++i) {
buf->page_list[i].buf = buf->page_list[i].buf =
dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
&t, GFP_KERNEL); &t, gfp);
if (!buf->page_list[i].buf) if (!buf->page_list[i].buf)
goto err_free; goto err_free;
@ -218,7 +218,7 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
if (BITS_PER_LONG == 64) { if (BITS_PER_LONG == 64) {
struct page **pages; struct page **pages;
pages = kmalloc(sizeof *pages * buf->nbufs, GFP_KERNEL); pages = kmalloc(sizeof *pages * buf->nbufs, gfp);
if (!pages) if (!pages)
goto err_free; goto err_free;
for (i = 0; i < buf->nbufs; ++i) for (i = 0; i < buf->nbufs; ++i)
@ -260,11 +260,12 @@ void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf)
} }
EXPORT_SYMBOL_GPL(mlx4_buf_free); EXPORT_SYMBOL_GPL(mlx4_buf_free);
static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device) static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device,
gfp_t gfp)
{ {
struct mlx4_db_pgdir *pgdir; struct mlx4_db_pgdir *pgdir;
pgdir = kzalloc(sizeof *pgdir, GFP_KERNEL); pgdir = kzalloc(sizeof *pgdir, gfp);
if (!pgdir) if (!pgdir)
return NULL; return NULL;
@ -272,7 +273,7 @@ static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device)
pgdir->bits[0] = pgdir->order0; pgdir->bits[0] = pgdir->order0;
pgdir->bits[1] = pgdir->order1; pgdir->bits[1] = pgdir->order1;
pgdir->db_page = dma_alloc_coherent(dma_device, PAGE_SIZE, pgdir->db_page = dma_alloc_coherent(dma_device, PAGE_SIZE,
&pgdir->db_dma, GFP_KERNEL); &pgdir->db_dma, gfp);
if (!pgdir->db_page) { if (!pgdir->db_page) {
kfree(pgdir); kfree(pgdir);
return NULL; return NULL;
@ -312,7 +313,7 @@ found:
return 0; return 0;
} }
int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order) int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order, gfp_t gfp)
{ {
struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_db_pgdir *pgdir; struct mlx4_db_pgdir *pgdir;
@ -324,7 +325,7 @@ int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order)
if (!mlx4_alloc_db_from_pgdir(pgdir, db, order)) if (!mlx4_alloc_db_from_pgdir(pgdir, db, order))
goto out; goto out;
pgdir = mlx4_alloc_db_pgdir(&(dev->pdev->dev)); pgdir = mlx4_alloc_db_pgdir(&(dev->pdev->dev), gfp);
if (!pgdir) { if (!pgdir) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
@ -376,13 +377,13 @@ int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres,
{ {
int err; int err;
err = mlx4_db_alloc(dev, &wqres->db, 1); err = mlx4_db_alloc(dev, &wqres->db, 1, GFP_KERNEL);
if (err) if (err)
return err; return err;
*wqres->db.db = 0; *wqres->db.db = 0;
err = mlx4_buf_alloc(dev, size, max_direct, &wqres->buf); err = mlx4_buf_alloc(dev, size, max_direct, &wqres->buf, GFP_KERNEL);
if (err) if (err)
goto err_db; goto err_db;
@ -391,7 +392,7 @@ int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres,
if (err) if (err)
goto err_buf; goto err_buf;
err = mlx4_buf_write_mtt(dev, &wqres->mtt, &wqres->buf); err = mlx4_buf_write_mtt(dev, &wqres->mtt, &wqres->buf, GFP_KERNEL);
if (err) if (err)
goto err_mtt; goto err_mtt;

View file

@ -705,20 +705,28 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
struct ib_smp *smp = inbox->buf; struct ib_smp *smp = inbox->buf;
u32 index; u32 index;
u8 port; u8 port;
u8 opcode_modifier;
u16 *table; u16 *table;
int err; int err;
int vidx, pidx; int vidx, pidx;
int network_view;
struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_priv *priv = mlx4_priv(dev);
struct ib_smp *outsmp = outbox->buf; struct ib_smp *outsmp = outbox->buf;
__be16 *outtab = (__be16 *)(outsmp->data); __be16 *outtab = (__be16 *)(outsmp->data);
__be32 slave_cap_mask; __be32 slave_cap_mask;
__be64 slave_node_guid; __be64 slave_node_guid;
port = vhcr->in_modifier; port = vhcr->in_modifier;
/* network-view bit is for driver use only, and should not be passed to FW */
opcode_modifier = vhcr->op_modifier & ~0x8; /* clear netw view bit */
network_view = !!(vhcr->op_modifier & 0x8);
if (smp->base_version == 1 && if (smp->base_version == 1 &&
smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED && smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED &&
smp->class_version == 1) { smp->class_version == 1) {
if (smp->method == IB_MGMT_METHOD_GET) { /* host view is paravirtualized */
if (!network_view && smp->method == IB_MGMT_METHOD_GET) {
if (smp->attr_id == IB_SMP_ATTR_PKEY_TABLE) { if (smp->attr_id == IB_SMP_ATTR_PKEY_TABLE) {
index = be32_to_cpu(smp->attr_mod); index = be32_to_cpu(smp->attr_mod);
if (port < 1 || port > dev->caps.num_ports) if (port < 1 || port > dev->caps.num_ports)
@ -743,7 +751,7 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
/*get the slave specific caps:*/ /*get the slave specific caps:*/
/*do the command */ /*do the command */
err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, err = mlx4_cmd_box(dev, inbox->dma, outbox->dma,
vhcr->in_modifier, vhcr->op_modifier, vhcr->in_modifier, opcode_modifier,
vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
/* modify the response for slaves */ /* modify the response for slaves */
if (!err && slave != mlx4_master_func_num(dev)) { if (!err && slave != mlx4_master_func_num(dev)) {
@ -760,7 +768,7 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
smp->attr_mod = cpu_to_be32(slave / 8); smp->attr_mod = cpu_to_be32(slave / 8);
/* execute cmd */ /* execute cmd */
err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, err = mlx4_cmd_box(dev, inbox->dma, outbox->dma,
vhcr->in_modifier, vhcr->op_modifier, vhcr->in_modifier, opcode_modifier,
vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
if (!err) { if (!err) {
/* if needed, move slave gid to index 0 */ /* if needed, move slave gid to index 0 */
@ -774,7 +782,7 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
} }
if (smp->attr_id == IB_SMP_ATTR_NODE_INFO) { if (smp->attr_id == IB_SMP_ATTR_NODE_INFO) {
err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, err = mlx4_cmd_box(dev, inbox->dma, outbox->dma,
vhcr->in_modifier, vhcr->op_modifier, vhcr->in_modifier, opcode_modifier,
vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
if (!err) { if (!err) {
slave_node_guid = mlx4_get_slave_node_guid(dev, slave); slave_node_guid = mlx4_get_slave_node_guid(dev, slave);
@ -784,19 +792,24 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
} }
} }
} }
/* Non-privileged VFs are only allowed "host" view LID-routed 'Get' MADs.
* These are the MADs used by ib verbs (such as ib_query_gids).
*/
if (slave != mlx4_master_func_num(dev) && if (slave != mlx4_master_func_num(dev) &&
((smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) || !mlx4_vf_smi_enabled(dev, slave, port)) {
(smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED && if (!(smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED &&
smp->method == IB_MGMT_METHOD_SET))) { smp->method == IB_MGMT_METHOD_GET) || network_view) {
mlx4_err(dev, "slave %d is trying to execute a Subnet MGMT MAD, " mlx4_err(dev, "Unprivileged slave %d is trying to execute a Subnet MGMT MAD, class 0x%x, method 0x%x, view=%s for attr 0x%x. Rejecting\n",
"class 0x%x, method 0x%x for attr 0x%x. Rejecting\n", slave, smp->method, smp->mgmt_class,
slave, smp->method, smp->mgmt_class, network_view ? "Network" : "Host",
be16_to_cpu(smp->attr_id)); be16_to_cpu(smp->attr_id));
return -EPERM; return -EPERM;
}
} }
/*default:*/
return mlx4_cmd_box(dev, inbox->dma, outbox->dma, return mlx4_cmd_box(dev, inbox->dma, outbox->dma,
vhcr->in_modifier, vhcr->op_modifier, vhcr->in_modifier, opcode_modifier,
vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
} }
@ -1653,6 +1666,8 @@ static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave)
for (port = min_port; port <= max_port; port++) { for (port = min_port; port <= max_port; port++) {
if (!test_bit(port - 1, actv_ports.ports)) if (!test_bit(port - 1, actv_ports.ports))
continue; continue;
priv->mfunc.master.vf_oper[slave].smi_enabled[port] =
priv->mfunc.master.vf_admin[slave].enable_smi[port];
vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
vp_oper->state = *vp_admin; vp_oper->state = *vp_admin;
@ -1704,6 +1719,8 @@ static void mlx4_master_deactivate_admin_state(struct mlx4_priv *priv, int slave
for (port = min_port; port <= max_port; port++) { for (port = min_port; port <= max_port; port++) {
if (!test_bit(port - 1, actv_ports.ports)) if (!test_bit(port - 1, actv_ports.ports))
continue; continue;
priv->mfunc.master.vf_oper[slave].smi_enabled[port] =
MLX4_VF_SMI_DISABLED;
vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
if (NO_INDX != vp_oper->vlan_idx) { if (NO_INDX != vp_oper->vlan_idx) {
__mlx4_unregister_vlan(&priv->dev, __mlx4_unregister_vlan(&priv->dev,
@ -2537,3 +2554,50 @@ int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_stat
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(mlx4_set_vf_link_state); EXPORT_SYMBOL_GPL(mlx4_set_vf_link_state);
int mlx4_vf_smi_enabled(struct mlx4_dev *dev, int slave, int port)
{
struct mlx4_priv *priv = mlx4_priv(dev);
if (slave < 1 || slave >= dev->num_slaves ||
port < 1 || port > MLX4_MAX_PORTS)
return 0;
return priv->mfunc.master.vf_oper[slave].smi_enabled[port] ==
MLX4_VF_SMI_ENABLED;
}
EXPORT_SYMBOL_GPL(mlx4_vf_smi_enabled);
int mlx4_vf_get_enable_smi_admin(struct mlx4_dev *dev, int slave, int port)
{
struct mlx4_priv *priv = mlx4_priv(dev);
if (slave == mlx4_master_func_num(dev))
return 1;
if (slave < 1 || slave >= dev->num_slaves ||
port < 1 || port > MLX4_MAX_PORTS)
return 0;
return priv->mfunc.master.vf_admin[slave].enable_smi[port] ==
MLX4_VF_SMI_ENABLED;
}
EXPORT_SYMBOL_GPL(mlx4_vf_get_enable_smi_admin);
int mlx4_vf_set_enable_smi_admin(struct mlx4_dev *dev, int slave, int port,
int enabled)
{
struct mlx4_priv *priv = mlx4_priv(dev);
if (slave == mlx4_master_func_num(dev))
return 0;
if (slave < 1 || slave >= dev->num_slaves ||
port < 1 || port > MLX4_MAX_PORTS ||
enabled < 0 || enabled > 1)
return -EINVAL;
priv->mfunc.master.vf_admin[slave].enable_smi[port] = enabled;
return 0;
}
EXPORT_SYMBOL_GPL(mlx4_vf_set_enable_smi_admin);

View file

@ -173,11 +173,11 @@ int __mlx4_cq_alloc_icm(struct mlx4_dev *dev, int *cqn)
if (*cqn == -1) if (*cqn == -1)
return -ENOMEM; return -ENOMEM;
err = mlx4_table_get(dev, &cq_table->table, *cqn); err = mlx4_table_get(dev, &cq_table->table, *cqn, GFP_KERNEL);
if (err) if (err)
goto err_out; goto err_out;
err = mlx4_table_get(dev, &cq_table->cmpt_table, *cqn); err = mlx4_table_get(dev, &cq_table->cmpt_table, *cqn, GFP_KERNEL);
if (err) if (err)
goto err_put; goto err_put;
return 0; return 0;

View file

@ -972,7 +972,7 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn,
if (!context) if (!context)
return -ENOMEM; return -ENOMEM;
err = mlx4_qp_alloc(mdev->dev, qpn, qp); err = mlx4_qp_alloc(mdev->dev, qpn, qp, GFP_KERNEL);
if (err) { if (err) {
en_err(priv, "Failed to allocate qp #%x\n", qpn); en_err(priv, "Failed to allocate qp #%x\n", qpn);
goto out; goto out;
@ -1012,7 +1012,7 @@ int mlx4_en_create_drop_qp(struct mlx4_en_priv *priv)
en_err(priv, "Failed reserving drop qpn\n"); en_err(priv, "Failed reserving drop qpn\n");
return err; return err;
} }
err = mlx4_qp_alloc(priv->mdev->dev, qpn, &priv->drop_qp); err = mlx4_qp_alloc(priv->mdev->dev, qpn, &priv->drop_qp, GFP_KERNEL);
if (err) { if (err) {
en_err(priv, "Failed allocating drop qp\n"); en_err(priv, "Failed allocating drop qp\n");
mlx4_qp_release_range(priv->mdev->dev, qpn, 1); mlx4_qp_release_range(priv->mdev->dev, qpn, 1);
@ -1071,7 +1071,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
} }
/* Configure RSS indirection qp */ /* Configure RSS indirection qp */
err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp); err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp, GFP_KERNEL);
if (err) { if (err) {
en_err(priv, "Failed to allocate RSS indirection QP\n"); en_err(priv, "Failed to allocate RSS indirection QP\n");
goto rss_err; goto rss_err;

View file

@ -113,7 +113,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map); ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map);
ring->qpn = qpn; ring->qpn = qpn;
err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp); err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp, GFP_KERNEL);
if (err) { if (err) {
en_err(priv, "Failed allocating qp %d\n", ring->qpn); en_err(priv, "Failed allocating qp %d\n", ring->qpn);
goto err_map; goto err_map;

View file

@ -178,8 +178,8 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_cmd_info *cmd) struct mlx4_cmd_info *cmd)
{ {
struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_priv *priv = mlx4_priv(dev);
u8 field; u8 field, port;
u32 size; u32 size, proxy_qp, qkey;
int err = 0; int err = 0;
#define QUERY_FUNC_CAP_FLAGS_OFFSET 0x0 #define QUERY_FUNC_CAP_FLAGS_OFFSET 0x0
@ -209,6 +209,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
/* when opcode modifier = 1 */ /* when opcode modifier = 1 */
#define QUERY_FUNC_CAP_PHYS_PORT_OFFSET 0x3 #define QUERY_FUNC_CAP_PHYS_PORT_OFFSET 0x3
#define QUERY_FUNC_CAP_PRIV_VF_QKEY_OFFSET 0x4
#define QUERY_FUNC_CAP_FLAGS0_OFFSET 0x8 #define QUERY_FUNC_CAP_FLAGS0_OFFSET 0x8
#define QUERY_FUNC_CAP_FLAGS1_OFFSET 0xc #define QUERY_FUNC_CAP_FLAGS1_OFFSET 0xc
@ -221,6 +222,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
#define QUERY_FUNC_CAP_FLAGS1_FORCE_MAC 0x40 #define QUERY_FUNC_CAP_FLAGS1_FORCE_MAC 0x40
#define QUERY_FUNC_CAP_FLAGS1_FORCE_VLAN 0x80 #define QUERY_FUNC_CAP_FLAGS1_FORCE_VLAN 0x80
#define QUERY_FUNC_CAP_FLAGS1_NIC_INFO 0x10 #define QUERY_FUNC_CAP_FLAGS1_NIC_INFO 0x10
#define QUERY_FUNC_CAP_VF_ENABLE_QP0 0x08
#define QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID 0x80 #define QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID 0x80
@ -234,28 +236,35 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
return -EINVAL; return -EINVAL;
vhcr->in_modifier = converted_port; vhcr->in_modifier = converted_port;
/* Set nic_info bit to mark new fields support */
field = QUERY_FUNC_CAP_FLAGS1_NIC_INFO;
MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS1_OFFSET);
/* phys-port = logical-port */ /* phys-port = logical-port */
field = vhcr->in_modifier - field = vhcr->in_modifier -
find_first_bit(actv_ports.ports, dev->caps.num_ports); find_first_bit(actv_ports.ports, dev->caps.num_ports);
MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_PHYS_PORT_OFFSET); MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_PHYS_PORT_OFFSET);
field = vhcr->in_modifier; port = vhcr->in_modifier;
proxy_qp = dev->phys_caps.base_proxy_sqpn + 8 * slave + port - 1;
/* Set nic_info bit to mark new fields support */
field = QUERY_FUNC_CAP_FLAGS1_NIC_INFO;
if (mlx4_vf_smi_enabled(dev, slave, port) &&
!mlx4_get_parav_qkey(dev, proxy_qp, &qkey)) {
field |= QUERY_FUNC_CAP_VF_ENABLE_QP0;
MLX4_PUT(outbox->buf, qkey,
QUERY_FUNC_CAP_PRIV_VF_QKEY_OFFSET);
}
MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS1_OFFSET);
/* size is now the QP number */ /* size is now the QP number */
size = dev->phys_caps.base_tunnel_sqpn + 8 * slave + field - 1; size = dev->phys_caps.base_tunnel_sqpn + 8 * slave + port - 1;
MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP0_TUNNEL); MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP0_TUNNEL);
size += 2; size += 2;
MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP1_TUNNEL); MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP1_TUNNEL);
size = dev->phys_caps.base_proxy_sqpn + 8 * slave + field - 1; MLX4_PUT(outbox->buf, proxy_qp, QUERY_FUNC_CAP_QP0_PROXY);
MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP0_PROXY); proxy_qp += 2;
MLX4_PUT(outbox->buf, proxy_qp, QUERY_FUNC_CAP_QP1_PROXY);
size += 2;
MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP1_PROXY);
MLX4_PUT(outbox->buf, dev->caps.phys_port_id[vhcr->in_modifier], MLX4_PUT(outbox->buf, dev->caps.phys_port_id[vhcr->in_modifier],
QUERY_FUNC_CAP_PHYS_PORT_ID); QUERY_FUNC_CAP_PHYS_PORT_ID);
@ -326,7 +335,7 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port,
struct mlx4_cmd_mailbox *mailbox; struct mlx4_cmd_mailbox *mailbox;
u32 *outbox; u32 *outbox;
u8 field, op_modifier; u8 field, op_modifier;
u32 size; u32 size, qkey;
int err = 0, quotas = 0; int err = 0, quotas = 0;
op_modifier = !!gen_or_port; /* 0 = general, 1 = logical port */ op_modifier = !!gen_or_port; /* 0 = general, 1 = logical port */
@ -414,7 +423,7 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port,
MLX4_GET(func_cap->flags1, outbox, QUERY_FUNC_CAP_FLAGS1_OFFSET); MLX4_GET(func_cap->flags1, outbox, QUERY_FUNC_CAP_FLAGS1_OFFSET);
if (dev->caps.port_type[gen_or_port] == MLX4_PORT_TYPE_ETH) { if (dev->caps.port_type[gen_or_port] == MLX4_PORT_TYPE_ETH) {
if (func_cap->flags1 & QUERY_FUNC_CAP_FLAGS1_OFFSET) { if (func_cap->flags1 & QUERY_FUNC_CAP_FLAGS1_FORCE_VLAN) {
mlx4_err(dev, "VLAN is enforced on this port\n"); mlx4_err(dev, "VLAN is enforced on this port\n");
err = -EPROTONOSUPPORT; err = -EPROTONOSUPPORT;
goto out; goto out;
@ -442,6 +451,13 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port,
goto out; goto out;
} }
if (func_cap->flags1 & QUERY_FUNC_CAP_VF_ENABLE_QP0) {
MLX4_GET(qkey, outbox, QUERY_FUNC_CAP_PRIV_VF_QKEY_OFFSET);
func_cap->qp0_qkey = qkey;
} else {
func_cap->qp0_qkey = 0;
}
MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP0_TUNNEL); MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP0_TUNNEL);
func_cap->qp0_tunnel_qpn = size & 0xFFFFFF; func_cap->qp0_tunnel_qpn = size & 0xFFFFFF;

View file

@ -134,6 +134,7 @@ struct mlx4_func_cap {
int max_eq; int max_eq;
int reserved_eq; int reserved_eq;
int mcg_quota; int mcg_quota;
u32 qp0_qkey;
u32 qp0_tunnel_qpn; u32 qp0_tunnel_qpn;
u32 qp0_proxy_qpn; u32 qp0_proxy_qpn;
u32 qp1_tunnel_qpn; u32 qp1_tunnel_qpn;

View file

@ -245,7 +245,8 @@ int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev)
MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
} }
int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj) int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj,
gfp_t gfp)
{ {
u32 i = (obj & (table->num_obj - 1)) / u32 i = (obj & (table->num_obj - 1)) /
(MLX4_TABLE_CHUNK_SIZE / table->obj_size); (MLX4_TABLE_CHUNK_SIZE / table->obj_size);
@ -259,7 +260,7 @@ int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj)
} }
table->icm[i] = mlx4_alloc_icm(dev, MLX4_TABLE_CHUNK_SIZE >> PAGE_SHIFT, table->icm[i] = mlx4_alloc_icm(dev, MLX4_TABLE_CHUNK_SIZE >> PAGE_SHIFT,
(table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) | (table->lowmem ? gfp : GFP_HIGHUSER) |
__GFP_NOWARN, table->coherent); __GFP_NOWARN, table->coherent);
if (!table->icm[i]) { if (!table->icm[i]) {
ret = -ENOMEM; ret = -ENOMEM;
@ -356,7 +357,7 @@ int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
u32 i; u32 i;
for (i = start; i <= end; i += inc) { for (i = start; i <= end; i += inc) {
err = mlx4_table_get(dev, table, i); err = mlx4_table_get(dev, table, i, GFP_KERNEL);
if (err) if (err)
goto fail; goto fail;
} }

View file

@ -71,7 +71,8 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
gfp_t gfp_mask, int coherent); gfp_t gfp_mask, int coherent);
void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent); void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent);
int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj); int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj,
gfp_t gfp);
void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj); void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj);
int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
u32 start, u32 end); u32 start, u32 end);

View file

@ -666,13 +666,15 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
return -ENODEV; return -ENODEV;
} }
dev->caps.qp0_qkey = kcalloc(dev->caps.num_ports, sizeof(u32), GFP_KERNEL);
dev->caps.qp0_tunnel = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); dev->caps.qp0_tunnel = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL);
dev->caps.qp0_proxy = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); dev->caps.qp0_proxy = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL);
dev->caps.qp1_tunnel = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); dev->caps.qp1_tunnel = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL);
dev->caps.qp1_proxy = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); dev->caps.qp1_proxy = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL);
if (!dev->caps.qp0_tunnel || !dev->caps.qp0_proxy || if (!dev->caps.qp0_tunnel || !dev->caps.qp0_proxy ||
!dev->caps.qp1_tunnel || !dev->caps.qp1_proxy) { !dev->caps.qp1_tunnel || !dev->caps.qp1_proxy ||
!dev->caps.qp0_qkey) {
err = -ENOMEM; err = -ENOMEM;
goto err_mem; goto err_mem;
} }
@ -684,6 +686,7 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
" port %d, aborting (%d).\n", i, err); " port %d, aborting (%d).\n", i, err);
goto err_mem; goto err_mem;
} }
dev->caps.qp0_qkey[i - 1] = func_cap.qp0_qkey;
dev->caps.qp0_tunnel[i - 1] = func_cap.qp0_tunnel_qpn; dev->caps.qp0_tunnel[i - 1] = func_cap.qp0_tunnel_qpn;
dev->caps.qp0_proxy[i - 1] = func_cap.qp0_proxy_qpn; dev->caps.qp0_proxy[i - 1] = func_cap.qp0_proxy_qpn;
dev->caps.qp1_tunnel[i - 1] = func_cap.qp1_tunnel_qpn; dev->caps.qp1_tunnel[i - 1] = func_cap.qp1_tunnel_qpn;
@ -729,12 +732,16 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
return 0; return 0;
err_mem: err_mem:
kfree(dev->caps.qp0_qkey);
kfree(dev->caps.qp0_tunnel); kfree(dev->caps.qp0_tunnel);
kfree(dev->caps.qp0_proxy); kfree(dev->caps.qp0_proxy);
kfree(dev->caps.qp1_tunnel); kfree(dev->caps.qp1_tunnel);
kfree(dev->caps.qp1_proxy); kfree(dev->caps.qp1_proxy);
dev->caps.qp0_tunnel = dev->caps.qp0_proxy = dev->caps.qp0_qkey = NULL;
dev->caps.qp1_tunnel = dev->caps.qp1_proxy = NULL; dev->caps.qp0_tunnel = NULL;
dev->caps.qp0_proxy = NULL;
dev->caps.qp1_tunnel = NULL;
dev->caps.qp1_proxy = NULL;
return err; return err;
} }
@ -1696,6 +1703,14 @@ unmap_bf:
unmap_internal_clock(dev); unmap_internal_clock(dev);
unmap_bf_area(dev); unmap_bf_area(dev);
if (mlx4_is_slave(dev)) {
kfree(dev->caps.qp0_qkey);
kfree(dev->caps.qp0_tunnel);
kfree(dev->caps.qp0_proxy);
kfree(dev->caps.qp1_tunnel);
kfree(dev->caps.qp1_proxy);
}
err_close: err_close:
if (mlx4_is_slave(dev)) if (mlx4_is_slave(dev))
mlx4_slave_exit(dev); mlx4_slave_exit(dev);
@ -2566,6 +2581,14 @@ err_master_mfunc:
if (mlx4_is_master(dev)) if (mlx4_is_master(dev))
mlx4_multi_func_cleanup(dev); mlx4_multi_func_cleanup(dev);
if (mlx4_is_slave(dev)) {
kfree(dev->caps.qp0_qkey);
kfree(dev->caps.qp0_tunnel);
kfree(dev->caps.qp0_proxy);
kfree(dev->caps.qp1_tunnel);
kfree(dev->caps.qp1_proxy);
}
err_close: err_close:
if (dev->flags & MLX4_FLAG_MSI_X) if (dev->flags & MLX4_FLAG_MSI_X)
pci_disable_msix(pdev); pci_disable_msix(pdev);
@ -2689,6 +2712,7 @@ static void __mlx4_remove_one(struct pci_dev *pdev)
if (!mlx4_is_slave(dev)) if (!mlx4_is_slave(dev))
mlx4_free_ownership(dev); mlx4_free_ownership(dev);
kfree(dev->caps.qp0_qkey);
kfree(dev->caps.qp0_tunnel); kfree(dev->caps.qp0_tunnel);
kfree(dev->caps.qp0_proxy); kfree(dev->caps.qp0_proxy);
kfree(dev->caps.qp1_tunnel); kfree(dev->caps.qp1_tunnel);

View file

@ -133,6 +133,11 @@ enum {
MLX4_COMM_CMD_FLR = 254 MLX4_COMM_CMD_FLR = 254
}; };
enum {
MLX4_VF_SMI_DISABLED,
MLX4_VF_SMI_ENABLED
};
/*The flag indicates that the slave should delay the RESET cmd*/ /*The flag indicates that the slave should delay the RESET cmd*/
#define MLX4_DELAY_RESET_SLAVE 0xbbbbbbb #define MLX4_DELAY_RESET_SLAVE 0xbbbbbbb
/*indicates how many retries will be done if we are in the middle of FLR*/ /*indicates how many retries will be done if we are in the middle of FLR*/
@ -488,6 +493,7 @@ struct mlx4_vport_state {
struct mlx4_vf_admin_state { struct mlx4_vf_admin_state {
struct mlx4_vport_state vport[MLX4_MAX_PORTS + 1]; struct mlx4_vport_state vport[MLX4_MAX_PORTS + 1];
u8 enable_smi[MLX4_MAX_PORTS + 1];
}; };
struct mlx4_vport_oper_state { struct mlx4_vport_oper_state {
@ -495,8 +501,10 @@ struct mlx4_vport_oper_state {
int mac_idx; int mac_idx;
int vlan_idx; int vlan_idx;
}; };
struct mlx4_vf_oper_state { struct mlx4_vf_oper_state {
struct mlx4_vport_oper_state vport[MLX4_MAX_PORTS + 1]; struct mlx4_vport_oper_state vport[MLX4_MAX_PORTS + 1];
u8 smi_enabled[MLX4_MAX_PORTS + 1];
}; };
struct slave_list { struct slave_list {
@ -895,7 +903,7 @@ void mlx4_cleanup_cq_table(struct mlx4_dev *dev);
void mlx4_cleanup_qp_table(struct mlx4_dev *dev); void mlx4_cleanup_qp_table(struct mlx4_dev *dev);
void mlx4_cleanup_srq_table(struct mlx4_dev *dev); void mlx4_cleanup_srq_table(struct mlx4_dev *dev);
void mlx4_cleanup_mcg_table(struct mlx4_dev *dev); void mlx4_cleanup_mcg_table(struct mlx4_dev *dev);
int __mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn); int __mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn, gfp_t gfp);
void __mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn); void __mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn);
int __mlx4_cq_alloc_icm(struct mlx4_dev *dev, int *cqn); int __mlx4_cq_alloc_icm(struct mlx4_dev *dev, int *cqn);
void __mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn); void __mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn);
@ -903,7 +911,7 @@ int __mlx4_srq_alloc_icm(struct mlx4_dev *dev, int *srqn);
void __mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn); void __mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn);
int __mlx4_mpt_reserve(struct mlx4_dev *dev); int __mlx4_mpt_reserve(struct mlx4_dev *dev);
void __mlx4_mpt_release(struct mlx4_dev *dev, u32 index); void __mlx4_mpt_release(struct mlx4_dev *dev, u32 index);
int __mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index); int __mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index, gfp_t gfp);
void __mlx4_mpt_free_icm(struct mlx4_dev *dev, u32 index); void __mlx4_mpt_free_icm(struct mlx4_dev *dev, u32 index);
u32 __mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order); u32 __mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order);
void __mlx4_free_mtt_range(struct mlx4_dev *dev, u32 first_seg, int order); void __mlx4_free_mtt_range(struct mlx4_dev *dev, u32 first_seg, int order);

View file

@ -364,14 +364,14 @@ static void mlx4_mpt_release(struct mlx4_dev *dev, u32 index)
__mlx4_mpt_release(dev, index); __mlx4_mpt_release(dev, index);
} }
int __mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index) int __mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index, gfp_t gfp)
{ {
struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
return mlx4_table_get(dev, &mr_table->dmpt_table, index); return mlx4_table_get(dev, &mr_table->dmpt_table, index, gfp);
} }
static int mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index) static int mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index, gfp_t gfp)
{ {
u64 param = 0; u64 param = 0;
@ -382,7 +382,7 @@ static int mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index)
MLX4_CMD_TIME_CLASS_A, MLX4_CMD_TIME_CLASS_A,
MLX4_CMD_WRAPPED); MLX4_CMD_WRAPPED);
} }
return __mlx4_mpt_alloc_icm(dev, index); return __mlx4_mpt_alloc_icm(dev, index, gfp);
} }
void __mlx4_mpt_free_icm(struct mlx4_dev *dev, u32 index) void __mlx4_mpt_free_icm(struct mlx4_dev *dev, u32 index)
@ -469,7 +469,7 @@ int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr)
struct mlx4_mpt_entry *mpt_entry; struct mlx4_mpt_entry *mpt_entry;
int err; int err;
err = mlx4_mpt_alloc_icm(dev, key_to_hw_index(mr->key)); err = mlx4_mpt_alloc_icm(dev, key_to_hw_index(mr->key), GFP_KERNEL);
if (err) if (err)
return err; return err;
@ -627,13 +627,14 @@ int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
EXPORT_SYMBOL_GPL(mlx4_write_mtt); EXPORT_SYMBOL_GPL(mlx4_write_mtt);
int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
struct mlx4_buf *buf) struct mlx4_buf *buf, gfp_t gfp)
{ {
u64 *page_list; u64 *page_list;
int err; int err;
int i; int i;
page_list = kmalloc(buf->npages * sizeof *page_list, GFP_KERNEL); page_list = kmalloc(buf->npages * sizeof *page_list,
gfp);
if (!page_list) if (!page_list)
return -ENOMEM; return -ENOMEM;
@ -680,7 +681,7 @@ int mlx4_mw_enable(struct mlx4_dev *dev, struct mlx4_mw *mw)
struct mlx4_mpt_entry *mpt_entry; struct mlx4_mpt_entry *mpt_entry;
int err; int err;
err = mlx4_mpt_alloc_icm(dev, key_to_hw_index(mw->key)); err = mlx4_mpt_alloc_icm(dev, key_to_hw_index(mw->key), GFP_KERNEL);
if (err) if (err)
return err; return err;

View file

@ -272,29 +272,29 @@ void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt)
} }
EXPORT_SYMBOL_GPL(mlx4_qp_release_range); EXPORT_SYMBOL_GPL(mlx4_qp_release_range);
int __mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn) int __mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn, gfp_t gfp)
{ {
struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_qp_table *qp_table = &priv->qp_table; struct mlx4_qp_table *qp_table = &priv->qp_table;
int err; int err;
err = mlx4_table_get(dev, &qp_table->qp_table, qpn); err = mlx4_table_get(dev, &qp_table->qp_table, qpn, gfp);
if (err) if (err)
goto err_out; goto err_out;
err = mlx4_table_get(dev, &qp_table->auxc_table, qpn); err = mlx4_table_get(dev, &qp_table->auxc_table, qpn, gfp);
if (err) if (err)
goto err_put_qp; goto err_put_qp;
err = mlx4_table_get(dev, &qp_table->altc_table, qpn); err = mlx4_table_get(dev, &qp_table->altc_table, qpn, gfp);
if (err) if (err)
goto err_put_auxc; goto err_put_auxc;
err = mlx4_table_get(dev, &qp_table->rdmarc_table, qpn); err = mlx4_table_get(dev, &qp_table->rdmarc_table, qpn, gfp);
if (err) if (err)
goto err_put_altc; goto err_put_altc;
err = mlx4_table_get(dev, &qp_table->cmpt_table, qpn); err = mlx4_table_get(dev, &qp_table->cmpt_table, qpn, gfp);
if (err) if (err)
goto err_put_rdmarc; goto err_put_rdmarc;
@ -316,7 +316,7 @@ err_out:
return err; return err;
} }
static int mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn) static int mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn, gfp_t gfp)
{ {
u64 param = 0; u64 param = 0;
@ -326,7 +326,7 @@ static int mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn)
MLX4_CMD_ALLOC_RES, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_ALLOC_RES, MLX4_CMD_TIME_CLASS_A,
MLX4_CMD_WRAPPED); MLX4_CMD_WRAPPED);
} }
return __mlx4_qp_alloc_icm(dev, qpn); return __mlx4_qp_alloc_icm(dev, qpn, gfp);
} }
void __mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn) void __mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn)
@ -355,7 +355,7 @@ static void mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn)
__mlx4_qp_free_icm(dev, qpn); __mlx4_qp_free_icm(dev, qpn);
} }
int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp) int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp, gfp_t gfp)
{ {
struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_qp_table *qp_table = &priv->qp_table; struct mlx4_qp_table *qp_table = &priv->qp_table;
@ -366,7 +366,7 @@ int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp)
qp->qpn = qpn; qp->qpn = qpn;
err = mlx4_qp_alloc_icm(dev, qpn); err = mlx4_qp_alloc_icm(dev, qpn, gfp);
if (err) if (err)
return err; return err;

View file

@ -1533,7 +1533,7 @@ static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
return err; return err;
if (!fw_reserved(dev, qpn)) { if (!fw_reserved(dev, qpn)) {
err = __mlx4_qp_alloc_icm(dev, qpn); err = __mlx4_qp_alloc_icm(dev, qpn, GFP_KERNEL);
if (err) { if (err) {
res_abort_move(dev, slave, RES_QP, qpn); res_abort_move(dev, slave, RES_QP, qpn);
return err; return err;
@ -1620,7 +1620,7 @@ static int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
if (err) if (err)
return err; return err;
err = __mlx4_mpt_alloc_icm(dev, mpt->key); err = __mlx4_mpt_alloc_icm(dev, mpt->key, GFP_KERNEL);
if (err) { if (err) {
res_abort_move(dev, slave, RES_MPT, id); res_abort_move(dev, slave, RES_MPT, id);
return err; return err;
@ -2828,10 +2828,12 @@ static int get_containing_mtt(struct mlx4_dev *dev, int slave, int start,
} }
static int verify_qp_parameters(struct mlx4_dev *dev, static int verify_qp_parameters(struct mlx4_dev *dev,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox, struct mlx4_cmd_mailbox *inbox,
enum qp_transition transition, u8 slave) enum qp_transition transition, u8 slave)
{ {
u32 qp_type; u32 qp_type;
u32 qpn;
struct mlx4_qp_context *qp_ctx; struct mlx4_qp_context *qp_ctx;
enum mlx4_qp_optpar optpar; enum mlx4_qp_optpar optpar;
int port; int port;
@ -2874,8 +2876,22 @@ static int verify_qp_parameters(struct mlx4_dev *dev,
default: default:
break; break;
} }
break; break;
case MLX4_QP_ST_MLX:
qpn = vhcr->in_modifier & 0x7fffff;
port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
if (transition == QP_TRANS_INIT2RTR &&
slave != mlx4_master_func_num(dev) &&
mlx4_is_qp_reserved(dev, qpn) &&
!mlx4_vf_smi_enabled(dev, slave, port)) {
/* only enabled VFs may create MLX proxy QPs */
mlx4_err(dev, "%s: unprivileged slave %d attempting to create an MLX proxy special QP on port %d\n",
__func__, slave, port);
return -EPERM;
}
break;
default: default:
break; break;
} }
@ -3455,7 +3471,7 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
err = adjust_qp_sched_queue(dev, slave, qpc, inbox); err = adjust_qp_sched_queue(dev, slave, qpc, inbox);
if (err) if (err)
return err; return err;
err = verify_qp_parameters(dev, inbox, QP_TRANS_INIT2RTR, slave); err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_INIT2RTR, slave);
if (err) if (err)
return err; return err;
@ -3509,7 +3525,7 @@ int mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
err = adjust_qp_sched_queue(dev, slave, context, inbox); err = adjust_qp_sched_queue(dev, slave, context, inbox);
if (err) if (err)
return err; return err;
err = verify_qp_parameters(dev, inbox, QP_TRANS_RTR2RTS, slave); err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_RTR2RTS, slave);
if (err) if (err)
return err; return err;
@ -3531,7 +3547,7 @@ int mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
err = adjust_qp_sched_queue(dev, slave, context, inbox); err = adjust_qp_sched_queue(dev, slave, context, inbox);
if (err) if (err)
return err; return err;
err = verify_qp_parameters(dev, inbox, QP_TRANS_RTS2RTS, slave); err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_RTS2RTS, slave);
if (err) if (err)
return err; return err;
@ -3568,7 +3584,7 @@ int mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave,
err = adjust_qp_sched_queue(dev, slave, context, inbox); err = adjust_qp_sched_queue(dev, slave, context, inbox);
if (err) if (err)
return err; return err;
err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2SQD, slave); err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_SQD2SQD, slave);
if (err) if (err)
return err; return err;
@ -3590,7 +3606,7 @@ int mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
err = adjust_qp_sched_queue(dev, slave, context, inbox); err = adjust_qp_sched_queue(dev, slave, context, inbox);
if (err) if (err)
return err; return err;
err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2RTS, slave); err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_SQD2RTS, slave);
if (err) if (err)
return err; return err;

View file

@ -103,11 +103,11 @@ int __mlx4_srq_alloc_icm(struct mlx4_dev *dev, int *srqn)
if (*srqn == -1) if (*srqn == -1)
return -ENOMEM; return -ENOMEM;
err = mlx4_table_get(dev, &srq_table->table, *srqn); err = mlx4_table_get(dev, &srq_table->table, *srqn, GFP_KERNEL);
if (err) if (err)
goto err_out; goto err_out;
err = mlx4_table_get(dev, &srq_table->cmpt_table, *srqn); err = mlx4_table_get(dev, &srq_table->cmpt_table, *srqn, GFP_KERNEL);
if (err) if (err)
goto err_put; goto err_put;
return 0; return 0;

View file

@ -82,7 +82,11 @@ int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
return mlx5_cmd_status_to_err(&lout.hdr); return mlx5_cmd_status_to_err(&lout.hdr);
} }
mr->iova = be64_to_cpu(in->seg.start_addr);
mr->size = be64_to_cpu(in->seg.len);
mr->key = mlx5_idx_to_mkey(be32_to_cpu(lout.mkey) & 0xffffff) | key; mr->key = mlx5_idx_to_mkey(be32_to_cpu(lout.mkey) & 0xffffff) | key;
mr->pd = be32_to_cpu(in->seg.flags_pd) & 0xffffff;
mlx5_core_dbg(dev, "out 0x%x, key 0x%x, mkey 0x%x\n", mlx5_core_dbg(dev, "out 0x%x, key 0x%x, mkey 0x%x\n",
be32_to_cpu(lout.mkey), key, mr->key); be32_to_cpu(lout.mkey), key, mr->key);

View file

@ -401,6 +401,7 @@ struct mlx4_caps {
int max_rq_desc_sz; int max_rq_desc_sz;
int max_qp_init_rdma; int max_qp_init_rdma;
int max_qp_dest_rdma; int max_qp_dest_rdma;
u32 *qp0_qkey;
u32 *qp0_proxy; u32 *qp0_proxy;
u32 *qp1_proxy; u32 *qp1_proxy;
u32 *qp0_tunnel; u32 *qp0_tunnel;
@ -837,7 +838,7 @@ static inline int mlx4_is_slave(struct mlx4_dev *dev)
} }
int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
struct mlx4_buf *buf); struct mlx4_buf *buf, gfp_t gfp);
void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf); void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf);
static inline void *mlx4_buf_offset(struct mlx4_buf *buf, int offset) static inline void *mlx4_buf_offset(struct mlx4_buf *buf, int offset)
{ {
@ -874,9 +875,10 @@ int mlx4_mw_enable(struct mlx4_dev *dev, struct mlx4_mw *mw);
int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
int start_index, int npages, u64 *page_list); int start_index, int npages, u64 *page_list);
int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
struct mlx4_buf *buf); struct mlx4_buf *buf, gfp_t gfp);
int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order); int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order,
gfp_t gfp);
void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db); void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db);
int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres,
@ -892,7 +894,8 @@ void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq);
int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base); int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base);
void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt); void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt);
int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp); int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp,
gfp_t gfp);
void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp); void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp);
int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcdn, int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcdn,
@ -1234,4 +1237,8 @@ int mlx4_phys_to_slave_port(struct mlx4_dev *dev, int slave, int port);
int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port); int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port);
int mlx4_config_vxlan_port(struct mlx4_dev *dev, __be16 udp_port); int mlx4_config_vxlan_port(struct mlx4_dev *dev, __be16 udp_port);
int mlx4_vf_smi_enabled(struct mlx4_dev *dev, int slave, int port);
int mlx4_vf_get_enable_smi_admin(struct mlx4_dev *dev, int slave, int port);
int mlx4_vf_set_enable_smi_admin(struct mlx4_dev *dev, int slave, int port,
int enable);
#endif /* MLX4_DEVICE_H */ #endif /* MLX4_DEVICE_H */

View file

@ -427,7 +427,6 @@ struct mlx5_core_mr {
u64 size; u64 size;
u32 key; u32 key;
u32 pd; u32 pd;
u32 access;
}; };
struct mlx5_core_srq { struct mlx5_core_srq {

View file

@ -80,8 +80,8 @@ enum rdma_transport_type {
RDMA_TRANSPORT_USNIC_UDP RDMA_TRANSPORT_USNIC_UDP
}; };
enum rdma_transport_type __attribute_const__ enum rdma_transport_type
rdma_node_get_transport(enum rdma_node_type node_type) __attribute_const__; rdma_node_get_transport(enum rdma_node_type node_type);
enum rdma_link_layer { enum rdma_link_layer {
IB_LINK_LAYER_UNSPECIFIED, IB_LINK_LAYER_UNSPECIFIED,
@ -466,14 +466,14 @@ enum ib_rate {
* converted to 2, since 5 Gbit/sec is 2 * 2.5 Gbit/sec. * converted to 2, since 5 Gbit/sec is 2 * 2.5 Gbit/sec.
* @rate: rate to convert. * @rate: rate to convert.
*/ */
int ib_rate_to_mult(enum ib_rate rate) __attribute_const__; __attribute_const__ int ib_rate_to_mult(enum ib_rate rate);
/** /**
* ib_rate_to_mbps - Convert the IB rate enum to Mbps. * ib_rate_to_mbps - Convert the IB rate enum to Mbps.
* For example, IB_RATE_2_5_GBPS will be converted to 2500. * For example, IB_RATE_2_5_GBPS will be converted to 2500.
* @rate: rate to convert. * @rate: rate to convert.
*/ */
int ib_rate_to_mbps(enum ib_rate rate) __attribute_const__; __attribute_const__ int ib_rate_to_mbps(enum ib_rate rate);
enum ib_mr_create_flags { enum ib_mr_create_flags {
IB_MR_SIGNATURE_EN = 1, IB_MR_SIGNATURE_EN = 1,
@ -604,7 +604,7 @@ struct ib_mr_status {
* enum. * enum.
* @mult: multiple to convert. * @mult: multiple to convert.
*/ */
enum ib_rate mult_to_ib_rate(int mult) __attribute_const__; __attribute_const__ enum ib_rate mult_to_ib_rate(int mult);
struct ib_ah_attr { struct ib_ah_attr {
struct ib_global_route grh; struct ib_global_route grh;
@ -783,6 +783,7 @@ enum ib_qp_create_flags {
IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK = 1 << 1, IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK = 1 << 1,
IB_QP_CREATE_NETIF_QP = 1 << 5, IB_QP_CREATE_NETIF_QP = 1 << 5,
IB_QP_CREATE_SIGNATURE_EN = 1 << 6, IB_QP_CREATE_SIGNATURE_EN = 1 << 6,
IB_QP_CREATE_USE_GFP_NOIO = 1 << 7,
/* reserve bits 26-31 for low level drivers' internal use */ /* reserve bits 26-31 for low level drivers' internal use */
IB_QP_CREATE_RESERVED_START = 1 << 26, IB_QP_CREATE_RESERVED_START = 1 << 26,
IB_QP_CREATE_RESERVED_END = 1 << 31, IB_QP_CREATE_RESERVED_END = 1 << 31,

199
include/rdma/iw_portmap.h Normal file
View file

@ -0,0 +1,199 @@
/*
* Copyright (c) 2014 Intel Corporation. All rights reserved.
* Copyright (c) 2014 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _IW_PORTMAP_H
#define _IW_PORTMAP_H
#define IWPM_ULIBNAME_SIZE 32
#define IWPM_DEVNAME_SIZE 32
#define IWPM_IFNAME_SIZE 16
#define IWPM_IPADDR_SIZE 16
enum {
IWPM_INVALID_NLMSG_ERR = 10,
IWPM_CREATE_MAPPING_ERR,
IWPM_DUPLICATE_MAPPING_ERR,
IWPM_UNKNOWN_MAPPING_ERR,
IWPM_CLIENT_DEV_INFO_ERR,
IWPM_USER_LIB_INFO_ERR,
IWPM_REMOTE_QUERY_REJECT
};
struct iwpm_dev_data {
char dev_name[IWPM_DEVNAME_SIZE];
char if_name[IWPM_IFNAME_SIZE];
};
struct iwpm_sa_data {
struct sockaddr_storage loc_addr;
struct sockaddr_storage mapped_loc_addr;
struct sockaddr_storage rem_addr;
struct sockaddr_storage mapped_rem_addr;
};
/**
* iwpm_init - Allocate resources for the iwarp port mapper
*
* Should be called when network interface goes up.
*/
int iwpm_init(u8);
/**
* iwpm_exit - Deallocate resources for the iwarp port mapper
*
* Should be called when network interface goes down.
*/
int iwpm_exit(u8);
/**
* iwpm_valid_pid - Check if the userspace iwarp port mapper pid is valid
*
* Returns true if the pid is greater than zero, otherwise returns false
*/
int iwpm_valid_pid(void);
/**
* iwpm_register_pid - Send a netlink query to userspace
* to get the iwarp port mapper pid
* @pm_msg: Contains driver info to send to the userspace port mapper
* @nl_client: The index of the netlink client
*/
int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client);
/**
* iwpm_add_mapping - Send a netlink add mapping request to
* the userspace port mapper
* @pm_msg: Contains the local ip/tcp address info to send
* @nl_client: The index of the netlink client
*
* If the request is successful, the pm_msg stores
* the port mapper response (mapped address info)
*/
int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client);
/**
* iwpm_add_and_query_mapping - Send a netlink add and query mapping request
* to the userspace port mapper
* @pm_msg: Contains the local and remote ip/tcp address info to send
* @nl_client: The index of the netlink client
*
* If the request is successful, the pm_msg stores the
* port mapper response (mapped local and remote address info)
*/
int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client);
/**
* iwpm_remove_mapping - Send a netlink remove mapping request
* to the userspace port mapper
*
* @local_addr: Local ip/tcp address to remove
* @nl_client: The index of the netlink client
*/
int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client);
/**
* iwpm_register_pid_cb - Process the port mapper response to
* iwpm_register_pid query
* @skb:
* @cb: Contains the received message (payload and netlink header)
*
* If successful, the function receives the userspace port mapper pid
* which is used in future communication with the port mapper
*/
int iwpm_register_pid_cb(struct sk_buff *, struct netlink_callback *);
/**
* iwpm_add_mapping_cb - Process the port mapper response to
* iwpm_add_mapping request
* @skb:
* @cb: Contains the received message (payload and netlink header)
*/
int iwpm_add_mapping_cb(struct sk_buff *, struct netlink_callback *);
/**
* iwpm_add_and_query_mapping_cb - Process the port mapper response to
* iwpm_add_and_query_mapping request
* @skb:
* @cb: Contains the received message (payload and netlink header)
*/
int iwpm_add_and_query_mapping_cb(struct sk_buff *, struct netlink_callback *);
/**
* iwpm_mapping_error_cb - Process port mapper notification for error
*
* @skb:
* @cb: Contains the received message (payload and netlink header)
*/
int iwpm_mapping_error_cb(struct sk_buff *, struct netlink_callback *);
/**
* iwpm_mapping_info_cb - Process a notification that the userspace
* port mapper daemon is started
* @skb:
* @cb: Contains the received message (payload and netlink header)
*
* Using the received port mapper pid, send all the local mapping
* info records to the userspace port mapper
*/
int iwpm_mapping_info_cb(struct sk_buff *, struct netlink_callback *);
/**
* iwpm_ack_mapping_info_cb - Process the port mapper ack for
* the provided local mapping info records
* @skb:
* @cb: Contains the received message (payload and netlink header)
*/
int iwpm_ack_mapping_info_cb(struct sk_buff *, struct netlink_callback *);
/**
* iwpm_create_mapinfo - Store local and mapped IPv4/IPv6 address
* info in a hash table
* @local_addr: Local ip/tcp address
* @mapped_addr: Mapped local ip/tcp address
* @nl_client: The index of the netlink client
*/
int iwpm_create_mapinfo(struct sockaddr_storage *local_addr,
struct sockaddr_storage *mapped_addr, u8 nl_client);
/**
* iwpm_remove_mapinfo - Remove local and mapped IPv4/IPv6 address
* info from the hash table
* @local_addr: Local ip/tcp address
* @mapped_addr: Mapped local ip/tcp address
*
* Returns err code if mapping info is not found in the hash table,
* otherwise returns 0
*/
int iwpm_remove_mapinfo(struct sockaddr_storage *local_addr,
struct sockaddr_storage *mapped_addr);
#endif /* _IW_PORTMAP_H */

View file

@ -43,7 +43,7 @@ int ibnl_remove_client(int index);
* Returns the allocated buffer on success and NULL on failure. * Returns the allocated buffer on success and NULL on failure.
*/ */
void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq, void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq,
int len, int client, int op); int len, int client, int op, int flags);
/** /**
* Put a new attribute in a supplied skb. * Put a new attribute in a supplied skb.
* @skb: The netlink skb. * @skb: The netlink skb.
@ -56,4 +56,25 @@ void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq,
int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh, int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh,
int len, void *data, int type); int len, void *data, int type);
/**
* Send the supplied skb to a specific userspace PID.
* @skb: The netlink skb
* @nlh: Header of the netlink message to send
* @pid: Userspace netlink process ID
* Returns 0 on success or a negative error code.
*/
int ibnl_unicast(struct sk_buff *skb, struct nlmsghdr *nlh,
__u32 pid);
/**
* Send the supplied skb to a netlink group.
* @skb: The netlink skb
* @nlh: Header of the netlink message to send
* @group: Netlink group ID
* @flags: allocation flags
* Returns 0 on success or a negative error code.
*/
int ibnl_multicast(struct sk_buff *skb, struct nlmsghdr *nlh,
unsigned int group, gfp_t flags);
#endif /* _RDMA_NETLINK_H */ #endif /* _RDMA_NETLINK_H */

View file

@ -4,7 +4,16 @@
#include <linux/types.h> #include <linux/types.h>
enum { enum {
RDMA_NL_RDMA_CM = 1 RDMA_NL_RDMA_CM = 1,
RDMA_NL_NES,
RDMA_NL_C4IW,
RDMA_NL_NUM_CLIENTS
};
enum {
RDMA_NL_GROUP_CM = 1,
RDMA_NL_GROUP_IWPM,
RDMA_NL_NUM_GROUPS
}; };
#define RDMA_NL_GET_CLIENT(type) ((type & (((1 << 6) - 1) << 10)) >> 10) #define RDMA_NL_GET_CLIENT(type) ((type & (((1 << 6) - 1) << 10)) >> 10)
@ -22,6 +31,18 @@ enum {
RDMA_NL_RDMA_CM_NUM_ATTR, RDMA_NL_RDMA_CM_NUM_ATTR,
}; };
/* iwarp port mapper op-codes */
enum {
RDMA_NL_IWPM_REG_PID = 0,
RDMA_NL_IWPM_ADD_MAPPING,
RDMA_NL_IWPM_QUERY_MAPPING,
RDMA_NL_IWPM_REMOVE_MAPPING,
RDMA_NL_IWPM_HANDLE_ERR,
RDMA_NL_IWPM_MAPINFO,
RDMA_NL_IWPM_MAPINFO_NUM,
RDMA_NL_IWPM_NUM_OPS
};
struct rdma_cm_id_stats { struct rdma_cm_id_stats {
__u32 qp_num; __u32 qp_num;
__u32 bound_dev_if; __u32 bound_dev_if;
@ -33,5 +54,78 @@ struct rdma_cm_id_stats {
__u8 qp_type; __u8 qp_type;
}; };
enum {
IWPM_NLA_REG_PID_UNSPEC = 0,
IWPM_NLA_REG_PID_SEQ,
IWPM_NLA_REG_IF_NAME,
IWPM_NLA_REG_IBDEV_NAME,
IWPM_NLA_REG_ULIB_NAME,
IWPM_NLA_REG_PID_MAX
};
enum {
IWPM_NLA_RREG_PID_UNSPEC = 0,
IWPM_NLA_RREG_PID_SEQ,
IWPM_NLA_RREG_IBDEV_NAME,
IWPM_NLA_RREG_ULIB_NAME,
IWPM_NLA_RREG_ULIB_VER,
IWPM_NLA_RREG_PID_ERR,
IWPM_NLA_RREG_PID_MAX
};
enum {
IWPM_NLA_MANAGE_MAPPING_UNSPEC = 0,
IWPM_NLA_MANAGE_MAPPING_SEQ,
IWPM_NLA_MANAGE_ADDR,
IWPM_NLA_MANAGE_MAPPED_LOC_ADDR,
IWPM_NLA_RMANAGE_MAPPING_ERR,
IWPM_NLA_RMANAGE_MAPPING_MAX
};
#define IWPM_NLA_MANAGE_MAPPING_MAX 3
#define IWPM_NLA_QUERY_MAPPING_MAX 4
#define IWPM_NLA_MAPINFO_SEND_MAX 3
enum {
IWPM_NLA_QUERY_MAPPING_UNSPEC = 0,
IWPM_NLA_QUERY_MAPPING_SEQ,
IWPM_NLA_QUERY_LOCAL_ADDR,
IWPM_NLA_QUERY_REMOTE_ADDR,
IWPM_NLA_RQUERY_MAPPED_LOC_ADDR,
IWPM_NLA_RQUERY_MAPPED_REM_ADDR,
IWPM_NLA_RQUERY_MAPPING_ERR,
IWPM_NLA_RQUERY_MAPPING_MAX
};
enum {
IWPM_NLA_MAPINFO_REQ_UNSPEC = 0,
IWPM_NLA_MAPINFO_ULIB_NAME,
IWPM_NLA_MAPINFO_ULIB_VER,
IWPM_NLA_MAPINFO_REQ_MAX
};
enum {
IWPM_NLA_MAPINFO_UNSPEC = 0,
IWPM_NLA_MAPINFO_LOCAL_ADDR,
IWPM_NLA_MAPINFO_MAPPED_ADDR,
IWPM_NLA_MAPINFO_MAX
};
enum {
IWPM_NLA_MAPINFO_NUM_UNSPEC = 0,
IWPM_NLA_MAPINFO_SEQ,
IWPM_NLA_MAPINFO_SEND_NUM,
IWPM_NLA_MAPINFO_ACK_NUM,
IWPM_NLA_MAPINFO_NUM_MAX
};
enum {
IWPM_NLA_ERR_UNSPEC = 0,
IWPM_NLA_ERR_SEQ,
IWPM_NLA_ERR_CODE,
IWPM_NLA_ERR_MAX
};
#endif /* _UAPI_RDMA_NETLINK_H */ #endif /* _UAPI_RDMA_NETLINK_H */