aboutsummaryrefslogtreecommitdiff
path: root/drivers/infiniband
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/core/addr.c30
-rw-r--r--drivers/infiniband/core/cm.c4
-rw-r--r--drivers/infiniband/core/uverbs.h2
-rw-r--r--drivers/infiniband/core/uverbs_main.c8
-rw-r--r--drivers/infiniband/hw/mthca/mthca_allocator.c15
-rw-r--r--drivers/infiniband/ulp/ipoib/Kconfig3
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c19
7 files changed, 52 insertions, 29 deletions
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index d294bbc42f0..1205e802782 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -35,6 +35,7 @@
#include <net/arp.h>
#include <net/neighbour.h>
#include <net/route.h>
+#include <net/netevent.h>
#include <rdma/ib_addr.h>
MODULE_AUTHOR("Sean Hefty");
@@ -326,25 +327,22 @@ void rdma_addr_cancel(struct rdma_dev_addr *addr)
}
EXPORT_SYMBOL(rdma_addr_cancel);
-static int addr_arp_recv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pkt, struct net_device *orig_dev)
+static int netevent_callback(struct notifier_block *self, unsigned long event,
+ void *ctx)
{
- struct arphdr *arp_hdr;
+ if (event == NETEVENT_NEIGH_UPDATE) {
+ struct neighbour *neigh = ctx;
- arp_hdr = (struct arphdr *) skb->nh.raw;
-
- if (arp_hdr->ar_op == htons(ARPOP_REQUEST) ||
- arp_hdr->ar_op == htons(ARPOP_REPLY))
- set_timeout(jiffies);
-
- kfree_skb(skb);
+ if (neigh->dev->type == ARPHRD_INFINIBAND &&
+ (neigh->nud_state & NUD_VALID)) {
+ set_timeout(jiffies);
+ }
+ }
return 0;
}
-static struct packet_type addr_arp = {
- .type = __constant_htons(ETH_P_ARP),
- .func = addr_arp_recv,
- .af_packet_priv = (void*) 1,
+static struct notifier_block nb = {
+ .notifier_call = netevent_callback
};
static int addr_init(void)
@@ -353,13 +351,13 @@ static int addr_init(void)
if (!addr_wq)
return -ENOMEM;
- dev_add_pack(&addr_arp);
+ register_netevent_notifier(&nb);
return 0;
}
static void addr_cleanup(void)
{
- dev_remove_pack(&addr_arp);
+ unregister_netevent_notifier(&nb);
destroy_workqueue(addr_wq);
}
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index f85c97f7500..0de335b7bfc 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -975,8 +975,10 @@ int ib_send_cm_req(struct ib_cm_id *cm_id,
cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv->
id.local_id);
- if (IS_ERR(cm_id_priv->timewait_info))
+ if (IS_ERR(cm_id_priv->timewait_info)) {
+ ret = PTR_ERR(cm_id_priv->timewait_info);
goto out;
+ }
ret = cm_init_av_by_path(param->primary_path, &cm_id_priv->av);
if (ret)
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index bb9bee56a82..102a59c033f 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -42,6 +42,7 @@
#include <linux/kref.h>
#include <linux/idr.h>
#include <linux/mutex.h>
+#include <linux/completion.h>
#include <rdma/ib_verbs.h>
#include <rdma/ib_user_verbs.h>
@@ -69,6 +70,7 @@
struct ib_uverbs_device {
struct kref ref;
+ struct completion comp;
int devnum;
struct cdev *dev;
struct class_device *class_dev;
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index e725cccc7cd..4e16314e8e6 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -122,7 +122,7 @@ static void ib_uverbs_release_dev(struct kref *ref)
struct ib_uverbs_device *dev =
container_of(ref, struct ib_uverbs_device, ref);
- kfree(dev);
+ complete(&dev->comp);
}
void ib_uverbs_release_ucq(struct ib_uverbs_file *file,
@@ -740,6 +740,7 @@ static void ib_uverbs_add_one(struct ib_device *device)
return;
kref_init(&uverbs_dev->ref);
+ init_completion(&uverbs_dev->comp);
spin_lock(&map_lock);
uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES);
@@ -793,6 +794,8 @@ err_cdev:
err:
kref_put(&uverbs_dev->ref, ib_uverbs_release_dev);
+ wait_for_completion(&uverbs_dev->comp);
+ kfree(uverbs_dev);
return;
}
@@ -812,7 +815,10 @@ static void ib_uverbs_remove_one(struct ib_device *device)
spin_unlock(&map_lock);
clear_bit(uverbs_dev->devnum, dev_map);
+
kref_put(&uverbs_dev->ref, ib_uverbs_release_dev);
+ wait_for_completion(&uverbs_dev->comp);
+ kfree(uverbs_dev);
}
static int uverbs_event_get_sb(struct file_system_type *fs_type, int flags,
diff --git a/drivers/infiniband/hw/mthca/mthca_allocator.c b/drivers/infiniband/hw/mthca/mthca_allocator.c
index 9ba3211cef7..25157f57a6d 100644
--- a/drivers/infiniband/hw/mthca/mthca_allocator.c
+++ b/drivers/infiniband/hw/mthca/mthca_allocator.c
@@ -108,14 +108,15 @@ void mthca_alloc_cleanup(struct mthca_alloc *alloc)
* serialize access to the array.
*/
+#define MTHCA_ARRAY_MASK (PAGE_SIZE / sizeof (void *) - 1)
+
void *mthca_array_get(struct mthca_array *array, int index)
{
int p = (index * sizeof (void *)) >> PAGE_SHIFT;
- if (array->page_list[p].page) {
- int i = index & (PAGE_SIZE / sizeof (void *) - 1);
- return array->page_list[p].page[i];
- } else
+ if (array->page_list[p].page)
+ return array->page_list[p].page[index & MTHCA_ARRAY_MASK];
+ else
return NULL;
}
@@ -130,8 +131,7 @@ int mthca_array_set(struct mthca_array *array, int index, void *value)
if (!array->page_list[p].page)
return -ENOMEM;
- array->page_list[p].page[index & (PAGE_SIZE / sizeof (void *) - 1)] =
- value;
+ array->page_list[p].page[index & MTHCA_ARRAY_MASK] = value;
++array->page_list[p].used;
return 0;
@@ -144,7 +144,8 @@ void mthca_array_clear(struct mthca_array *array, int index)
if (--array->page_list[p].used == 0) {
free_page((unsigned long) array->page_list[p].page);
array->page_list[p].page = NULL;
- }
+ } else
+ array->page_list[p].page[index & MTHCA_ARRAY_MASK] = NULL;
if (array->page_list[p].used < 0)
pr_debug("Array %p index %d page %d with ref count %d < 0\n",
diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig
index 13d6d01c72c..d74653d7de1 100644
--- a/drivers/infiniband/ulp/ipoib/Kconfig
+++ b/drivers/infiniband/ulp/ipoib/Kconfig
@@ -6,8 +6,7 @@ config INFINIBAND_IPOIB
transports IP packets over InfiniBand so you can use your IB
device as a fancy NIC.
- The IPoIB protocol is defined by the IETF ipoib working
- group: <http://www.ietf.org/html.charters/ipoib-charter.html>.
+ See Documentation/infiniband/ipoib.txt for more information
config INFINIBAND_IPOIB_DEBUG
bool "IP-over-InfiniBand debugging" if EMBEDDED
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 8f472e7113b..8257d5a2c8f 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -77,6 +77,14 @@ MODULE_PARM_DESC(topspin_workarounds,
static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad };
+static int mellanox_workarounds = 1;
+
+module_param(mellanox_workarounds, int, 0444);
+MODULE_PARM_DESC(mellanox_workarounds,
+ "Enable workarounds for Mellanox SRP target bugs if != 0");
+
+static const u8 mellanox_oui[3] = { 0x00, 0x02, 0xc9 };
+
static void srp_add_one(struct ib_device *device);
static void srp_remove_one(struct ib_device *device);
static void srp_completion(struct ib_cq *cq, void *target_ptr);
@@ -526,8 +534,10 @@ static int srp_reconnect_target(struct srp_target_port *target)
while (ib_poll_cq(target->cq, 1, &wc) > 0)
; /* nothing */
+ spin_lock_irq(target->scsi_host->host_lock);
list_for_each_entry_safe(req, tmp, &target->req_queue, list)
srp_reset_req(target, req);
+ spin_unlock_irq(target->scsi_host->host_lock);
target->rx_head = 0;
target->tx_head = 0;
@@ -567,7 +577,7 @@ err:
return ret;
}
-static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
+static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat,
int sg_cnt, struct srp_request *req,
struct srp_direct_buf *buf)
{
@@ -577,10 +587,15 @@ static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
int page_cnt;
int i, j;
int ret;
+ struct srp_device *dev = target->srp_host->dev;
if (!dev->fmr_pool)
return -ENODEV;
+ if ((sg_dma_address(&scat[0]) & ~dev->fmr_page_mask) &&
+ mellanox_workarounds && !memcmp(&target->ioc_guid, mellanox_oui, 3))
+ return -EINVAL;
+
len = page_cnt = 0;
for (i = 0; i < sg_cnt; ++i) {
if (sg_dma_address(&scat[i]) & ~dev->fmr_page_mask) {
@@ -683,7 +698,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
buf->va = cpu_to_be64(sg_dma_address(scat));
buf->key = cpu_to_be32(target->srp_host->dev->mr->rkey);
buf->len = cpu_to_be32(sg_dma_len(scat));
- } else if (srp_map_fmr(target->srp_host->dev, scat, count, req,
+ } else if (srp_map_fmr(target, scat, count, req,
(void *) cmd->add_data)) {
/*
* FMR mapping failed, and the scatterlist has more