summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas/sas_event.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2012-04-14 13:18:27 +0200
committerIngo Molnar <mingo@kernel.org>2012-04-14 13:19:04 +0200
commit6ac1ef482d7ae0c690f1640bf6eb818ff9a2d91e (patch)
tree021cc9f6b477146fcebe6f3be4752abfa2ba18a9 /drivers/scsi/libsas/sas_event.c
parent682968e0c425c60f0dde37977e5beb2b12ddc4cc (diff)
parenta385ec4f11bdcf81af094c03e2444ee9b7fad2e5 (diff)
Merge branch 'perf/core' into perf/uprobes
Merge in latest upstream (and the latest perf development tree), to prepare for tooling changes, and also to pick up v3.4 MM changes that the uprobes code needs to take care of. Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'drivers/scsi/libsas/sas_event.c')
-rw-r--r--drivers/scsi/libsas/sas_event.c96
1 files changed, 91 insertions, 5 deletions
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index 9db30fb5caf..16639bbae62 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -22,15 +22,103 @@
*
*/
+#include <linux/export.h>
#include <scsi/scsi_host.h>
#include "sas_internal.h"
#include "sas_dump.h"
+void sas_queue_work(struct sas_ha_struct *ha, struct work_struct *work)
+{
+ if (!test_bit(SAS_HA_REGISTERED, &ha->state))
+ return;
+
+ if (test_bit(SAS_HA_DRAINING, &ha->state))
+ list_add(&work->entry, &ha->defer_q);
+ else
+ scsi_queue_work(ha->core.shost, work);
+}
+
+static void sas_queue_event(int event, unsigned long *pending,
+ struct work_struct *work,
+ struct sas_ha_struct *ha)
+{
+ if (!test_and_set_bit(event, pending)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->state_lock, flags);
+ sas_queue_work(ha, work);
+ spin_unlock_irqrestore(&ha->state_lock, flags);
+ }
+}
+
+
+void __sas_drain_work(struct sas_ha_struct *ha)
+{
+ struct workqueue_struct *wq = ha->core.shost->work_q;
+ struct work_struct *w, *_w;
+
+ set_bit(SAS_HA_DRAINING, &ha->state);
+ /* flush submitters */
+ spin_lock_irq(&ha->state_lock);
+ spin_unlock_irq(&ha->state_lock);
+
+ drain_workqueue(wq);
+
+ spin_lock_irq(&ha->state_lock);
+ clear_bit(SAS_HA_DRAINING, &ha->state);
+ list_for_each_entry_safe(w, _w, &ha->defer_q, entry) {
+ list_del_init(&w->entry);
+ sas_queue_work(ha, w);
+ }
+ spin_unlock_irq(&ha->state_lock);
+}
+
+int sas_drain_work(struct sas_ha_struct *ha)
+{
+ int err;
+
+ err = mutex_lock_interruptible(&ha->drain_mutex);
+ if (err)
+ return err;
+ if (test_bit(SAS_HA_REGISTERED, &ha->state))
+ __sas_drain_work(ha);
+ mutex_unlock(&ha->drain_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sas_drain_work);
+
+void sas_disable_revalidation(struct sas_ha_struct *ha)
+{
+ mutex_lock(&ha->disco_mutex);
+ set_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state);
+ mutex_unlock(&ha->disco_mutex);
+}
+
+void sas_enable_revalidation(struct sas_ha_struct *ha)
+{
+ int i;
+
+ mutex_lock(&ha->disco_mutex);
+ clear_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state);
+ for (i = 0; i < ha->num_phys; i++) {
+ struct asd_sas_port *port = ha->sas_port[i];
+ const int ev = DISCE_REVALIDATE_DOMAIN;
+ struct sas_discovery *d = &port->disc;
+
+ if (!test_and_clear_bit(ev, &d->pending))
+ continue;
+
+ sas_queue_event(ev, &d->pending, &d->disc_work[ev].work, ha);
+ }
+ mutex_unlock(&ha->disco_mutex);
+}
+
static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
{
BUG_ON(event >= HA_NUM_EVENTS);
- sas_queue_event(event, &sas_ha->event_lock, &sas_ha->pending,
+ sas_queue_event(event, &sas_ha->pending,
&sas_ha->ha_events[event].work, sas_ha);
}
@@ -40,7 +128,7 @@ static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
BUG_ON(event >= PORT_NUM_EVENTS);
- sas_queue_event(event, &ha->event_lock, &phy->port_events_pending,
+ sas_queue_event(event, &phy->port_events_pending,
&phy->port_events[event].work, ha);
}
@@ -50,7 +138,7 @@ static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
BUG_ON(event >= PHY_NUM_EVENTS);
- sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending,
+ sas_queue_event(event, &phy->phy_events_pending,
&phy->phy_events[event].work, ha);
}
@@ -62,8 +150,6 @@ int sas_init_events(struct sas_ha_struct *sas_ha)
int i;
- spin_lock_init(&sas_ha->event_lock);
-
for (i = 0; i < HA_NUM_EVENTS; i++) {
INIT_WORK(&sas_ha->ha_events[i].work, sas_ha_event_fns[i]);
sas_ha->ha_events[i].ha = sas_ha;