aboutsummaryrefslogtreecommitdiff
path: root/drivers/infiniband/ulp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband/ulp')
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h12
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c10
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c31
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c25
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c2
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c85
6 files changed, 128 insertions, 37 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 2f85a9a831b..1251f86ec85 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -217,10 +217,16 @@ struct ipoib_neigh {
struct list_head list;
};
+/*
+ * We stash a pointer to our private neighbour information after our
+ * hardware address in neigh->ha. The ALIGN() expression here makes
+ * sure that this pointer is stored aligned so that an unaligned
+ * load is not needed to dereference it.
+ */
static inline struct ipoib_neigh **to_ipoib_neigh(struct neighbour *neigh)
{
- return (struct ipoib_neigh **) (neigh->ha + 24 -
- (offsetof(struct neighbour, ha) & 4));
+ return (void*) neigh + ALIGN(offsetof(struct neighbour, ha) +
+ INFINIBAND_ALEN, sizeof(void *));
}
extern struct workqueue_struct *ipoib_workqueue;
@@ -253,7 +259,7 @@ void ipoib_ib_dev_cleanup(struct net_device *dev);
int ipoib_ib_dev_open(struct net_device *dev);
int ipoib_ib_dev_up(struct net_device *dev);
-int ipoib_ib_dev_down(struct net_device *dev);
+int ipoib_ib_dev_down(struct net_device *dev, int flush);
int ipoib_ib_dev_stop(struct net_device *dev);
int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 86bcdd72a10..a1f5a05f2f3 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -416,6 +416,7 @@ int ipoib_ib_dev_open(struct net_device *dev)
ret = ipoib_ib_post_receives(dev);
if (ret) {
ipoib_warn(priv, "ipoib_ib_post_receives returned %d\n", ret);
+ ipoib_ib_dev_stop(dev);
return -1;
}
@@ -434,7 +435,7 @@ int ipoib_ib_dev_up(struct net_device *dev)
return ipoib_mcast_start_thread(dev);
}
-int ipoib_ib_dev_down(struct net_device *dev)
+int ipoib_ib_dev_down(struct net_device *dev, int flush)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -449,10 +450,11 @@ int ipoib_ib_dev_down(struct net_device *dev)
set_bit(IPOIB_PKEY_STOP, &priv->flags);
cancel_delayed_work(&priv->pkey_task);
mutex_unlock(&pkey_mutex);
- flush_workqueue(ipoib_workqueue);
+ if (flush)
+ flush_workqueue(ipoib_workqueue);
}
- ipoib_mcast_stop_thread(dev, 1);
+ ipoib_mcast_stop_thread(dev, flush);
ipoib_mcast_dev_flush(dev);
ipoib_flush_paths(dev);
@@ -590,7 +592,7 @@ void ipoib_ib_dev_flush(void *_dev)
ipoib_dbg(priv, "flushing\n");
- ipoib_ib_dev_down(dev);
+ ipoib_ib_dev_down(dev, 0);
/*
* The device could have been brought down between the start and when
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index c3b5f79d116..37da8d3dc38 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -133,7 +133,13 @@ static int ipoib_stop(struct net_device *dev)
netif_stop_queue(dev);
- ipoib_ib_dev_down(dev);
+ /*
+ * Now flush workqueue to make sure a scheduled task doesn't
+ * bring our internal state back up.
+ */
+ flush_workqueue(ipoib_workqueue);
+
+ ipoib_ib_dev_down(dev, 1);
ipoib_ib_dev_stop(dev);
if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
@@ -247,7 +253,6 @@ static void path_free(struct net_device *dev, struct ipoib_path *path)
if (neigh->ah)
ipoib_put_ah(neigh->ah);
*to_ipoib_neigh(neigh->neighbour) = NULL;
- neigh->neighbour->ops->destructor = NULL;
kfree(neigh);
}
@@ -513,12 +518,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
be32_to_cpup((__be32 *) skb->dst->neighbour->ha));
} else {
neigh->ah = NULL;
- if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
- __skb_queue_tail(&neigh->queue, skb);
- } else {
- ++priv->stats.tx_dropped;
- dev_kfree_skb_any(skb);
- }
+ __skb_queue_tail(&neigh->queue, skb);
if (!path->query && path_rec_start(dev, path))
goto err;
@@ -530,7 +530,6 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
err:
*to_ipoib_neigh(skb->dst->neighbour) = NULL;
list_del(&neigh->list);
- neigh->neighbour->ops->destructor = NULL;
kfree(neigh);
++priv->stats.tx_dropped;
@@ -769,21 +768,9 @@ static void ipoib_neigh_destructor(struct neighbour *n)
ipoib_put_ah(ah);
}
-static int ipoib_neigh_setup(struct neighbour *neigh)
-{
- /*
- * Is this kosher? I can't find anybody in the kernel that
- * sets neigh->destructor, so we should be able to set it here
- * without trouble.
- */
- neigh->ops->destructor = ipoib_neigh_destructor;
-
- return 0;
-}
-
static int ipoib_neigh_setup_dev(struct net_device *dev, struct neigh_parms *parms)
{
- parms->neigh_setup = ipoib_neigh_setup;
+ parms->neigh_destructor = ipoib_neigh_destructor;
return 0;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index a2408d7ec59..93c462eaf4f 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -115,7 +115,6 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
if (neigh->ah)
ipoib_put_ah(neigh->ah);
*to_ipoib_neigh(neigh->neighbour) = NULL;
- neigh->neighbour->ops->destructor = NULL;
kfree(neigh);
}
@@ -213,6 +212,7 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
{
struct net_device *dev = mcast->dev;
struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ipoib_ah *ah;
int ret;
mcast->mcmember = *mcmember;
@@ -269,8 +269,8 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
av.static_rate, priv->local_rate,
ib_sa_rate_enum_to_int(mcast->mcmember.rate));
- mcast->ah = ipoib_create_ah(dev, priv->pd, &av);
- if (!mcast->ah) {
+ ah = ipoib_create_ah(dev, priv->pd, &av);
+ if (!ah) {
ipoib_warn(priv, "ib_address_create failed\n");
} else {
ipoib_dbg_mcast(priv, "MGID " IPOIB_GID_FMT
@@ -280,6 +280,10 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
be16_to_cpu(mcast->mcmember.mlid),
mcast->mcmember.sl);
}
+
+ spin_lock_irq(&priv->lock);
+ mcast->ah = ah;
+ spin_unlock_irq(&priv->lock);
}
/* actually send any queued packets */
@@ -432,9 +436,11 @@ static void ipoib_mcast_join_complete(int status,
if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;
+ mutex_lock(&mcast_mutex);
+
+ spin_lock_irq(&priv->lock);
mcast->query = NULL;
- mutex_lock(&mcast_mutex);
if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) {
if (status == -ETIMEDOUT)
queue_work(ipoib_workqueue, &priv->mcast_task);
@@ -443,6 +449,7 @@ static void ipoib_mcast_join_complete(int status,
mcast->backoff * HZ);
} else
complete(&mcast->done);
+ spin_unlock_irq(&priv->lock);
mutex_unlock(&mcast_mutex);
return;
@@ -630,21 +637,27 @@ int ipoib_mcast_stop_thread(struct net_device *dev, int flush)
if (flush)
flush_workqueue(ipoib_workqueue);
+ spin_lock_irq(&priv->lock);
if (priv->broadcast && priv->broadcast->query) {
ib_sa_cancel_query(priv->broadcast->query_id, priv->broadcast->query);
priv->broadcast->query = NULL;
+ spin_unlock_irq(&priv->lock);
ipoib_dbg_mcast(priv, "waiting for bcast\n");
wait_for_completion(&priv->broadcast->done);
- }
+ } else
+ spin_unlock_irq(&priv->lock);
list_for_each_entry(mcast, &priv->multicast_list, list) {
+ spin_lock_irq(&priv->lock);
if (mcast->query) {
ib_sa_cancel_query(mcast->query_id, mcast->query);
mcast->query = NULL;
+ spin_unlock_irq(&priv->lock);
ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n",
IPOIB_GID_ARG(mcast->mcmember.mgid));
wait_for_completion(&mcast->done);
- }
+ } else
+ spin_unlock_irq(&priv->lock);
}
return 0;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index faaf10e5fc7..18d2f53ec34 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -255,6 +255,6 @@ void ipoib_event(struct ib_event_handler *handler,
record->event == IB_EVENT_LID_CHANGE ||
record->event == IB_EVENT_SM_CHANGE) {
ipoib_dbg(priv, "Port active event\n");
- schedule_work(&priv->flush_task);
+ queue_work(ipoib_workqueue, &priv->flush_task);
}
}
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 960dae5c87d..a13dcdf90a4 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1237,6 +1237,87 @@ static int srp_reset_host(struct scsi_cmnd *scmnd)
return ret;
}
+static ssize_t show_id_ext(struct class_device *cdev, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+ if (target->state == SRP_TARGET_DEAD ||
+ target->state == SRP_TARGET_REMOVED)
+ return -ENODEV;
+
+ return sprintf(buf, "0x%016llx\n",
+ (unsigned long long) be64_to_cpu(target->id_ext));
+}
+
+static ssize_t show_ioc_guid(struct class_device *cdev, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+ if (target->state == SRP_TARGET_DEAD ||
+ target->state == SRP_TARGET_REMOVED)
+ return -ENODEV;
+
+ return sprintf(buf, "0x%016llx\n",
+ (unsigned long long) be64_to_cpu(target->ioc_guid));
+}
+
+static ssize_t show_service_id(struct class_device *cdev, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+ if (target->state == SRP_TARGET_DEAD ||
+ target->state == SRP_TARGET_REMOVED)
+ return -ENODEV;
+
+ return sprintf(buf, "0x%016llx\n",
+ (unsigned long long) be64_to_cpu(target->service_id));
+}
+
+static ssize_t show_pkey(struct class_device *cdev, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+ if (target->state == SRP_TARGET_DEAD ||
+ target->state == SRP_TARGET_REMOVED)
+ return -ENODEV;
+
+ return sprintf(buf, "0x%04x\n", be16_to_cpu(target->path.pkey));
+}
+
+static ssize_t show_dgid(struct class_device *cdev, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+ if (target->state == SRP_TARGET_DEAD ||
+ target->state == SRP_TARGET_REMOVED)
+ return -ENODEV;
+
+ return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[0]),
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[1]),
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[2]),
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[3]),
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[4]),
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[5]),
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[6]),
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[7]));
+}
+
+static CLASS_DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL);
+static CLASS_DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL);
+static CLASS_DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL);
+static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
+static CLASS_DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL);
+
+static struct class_device_attribute *srp_host_attrs[] = {
+ &class_device_attr_id_ext,
+ &class_device_attr_ioc_guid,
+ &class_device_attr_service_id,
+ &class_device_attr_pkey,
+ &class_device_attr_dgid,
+ NULL
+};
+
static struct scsi_host_template srp_template = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -1249,7 +1330,8 @@ static struct scsi_host_template srp_template = {
.this_id = -1,
.sg_tablesize = SRP_MAX_INDIRECT,
.cmd_per_lun = SRP_SQ_SIZE,
- .use_clustering = ENABLE_CLUSTERING
+ .use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = srp_host_attrs
};
static int srp_add_target(struct srp_host *host, struct srp_target_port *target)
@@ -1366,6 +1448,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
strlcpy(dgid, p + i * 2, 3);
target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16);
}
+ kfree(p);
break;
case SRP_OPT_PKEY: