aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas/sas_event.c
diff options
context:
space:
mode:
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 @@
22 * 22 *
23 */ 23 */
24 24
25#include <linux/export.h>
25#include <scsi/scsi_host.h> 26#include <scsi/scsi_host.h>
26#include "sas_internal.h" 27#include "sas_internal.h"
27#include "sas_dump.h" 28#include "sas_dump.h"
28 29
30void sas_queue_work(struct sas_ha_struct *ha, struct work_struct *work)
31{
32 if (!test_bit(SAS_HA_REGISTERED, &ha->state))
33 return;
34
35 if (test_bit(SAS_HA_DRAINING, &ha->state))
36 list_add(&work->entry, &ha->defer_q);
37 else
38 scsi_queue_work(ha->core.shost, work);
39}
40
41static void sas_queue_event(int event, unsigned long *pending,
42 struct work_struct *work,
43 struct sas_ha_struct *ha)
44{
45 if (!test_and_set_bit(event, pending)) {
46 unsigned long flags;
47
48 spin_lock_irqsave(&ha->state_lock, flags);
49 sas_queue_work(ha, work);
50 spin_unlock_irqrestore(&ha->state_lock, flags);
51 }
52}
53
54
55void __sas_drain_work(struct sas_ha_struct *ha)
56{
57 struct workqueue_struct *wq = ha->core.shost->work_q;
58 struct work_struct *w, *_w;
59
60 set_bit(SAS_HA_DRAINING, &ha->state);
61 /* flush submitters */
62 spin_lock_irq(&ha->state_lock);
63 spin_unlock_irq(&ha->state_lock);
64
65 drain_workqueue(wq);
66
67 spin_lock_irq(&ha->state_lock);
68 clear_bit(SAS_HA_DRAINING, &ha->state);
69 list_for_each_entry_safe(w, _w, &ha->defer_q, entry) {
70 list_del_init(&w->entry);
71 sas_queue_work(ha, w);
72 }
73 spin_unlock_irq(&ha->state_lock);
74}
75
76int sas_drain_work(struct sas_ha_struct *ha)
77{
78 int err;
79
80 err = mutex_lock_interruptible(&ha->drain_mutex);
81 if (err)
82 return err;
83 if (test_bit(SAS_HA_REGISTERED, &ha->state))
84 __sas_drain_work(ha);
85 mutex_unlock(&ha->drain_mutex);
86
87 return 0;
88}
89EXPORT_SYMBOL_GPL(sas_drain_work);
90
91void sas_disable_revalidation(struct sas_ha_struct *ha)
92{
93 mutex_lock(&ha->disco_mutex);
94 set_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state);
95 mutex_unlock(&ha->disco_mutex);
96}
97
98void sas_enable_revalidation(struct sas_ha_struct *ha)
99{
100 int i;
101
102 mutex_lock(&ha->disco_mutex);
103 clear_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state);
104 for (i = 0; i < ha->num_phys; i++) {
105 struct asd_sas_port *port = ha->sas_port[i];
106 const int ev = DISCE_REVALIDATE_DOMAIN;
107 struct sas_discovery *d = &port->disc;
108
109 if (!test_and_clear_bit(ev, &d->pending))
110 continue;
111
112 sas_queue_event(ev, &d->pending, &d->disc_work[ev].work, ha);
113 }
114 mutex_unlock(&ha->disco_mutex);
115}
116
29static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event) 117static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
30{ 118{
31 BUG_ON(event >= HA_NUM_EVENTS); 119 BUG_ON(event >= HA_NUM_EVENTS);
32 120
33 sas_queue_event(event, &sas_ha->event_lock, &sas_ha->pending, 121 sas_queue_event(event, &sas_ha->pending,
34 &sas_ha->ha_events[event].work, sas_ha); 122 &sas_ha->ha_events[event].work, sas_ha);
35} 123}
36 124
@@ -40,7 +128,7 @@ static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
40 128
41 BUG_ON(event >= PORT_NUM_EVENTS); 129 BUG_ON(event >= PORT_NUM_EVENTS);
42 130
43 sas_queue_event(event, &ha->event_lock, &phy->port_events_pending, 131 sas_queue_event(event, &phy->port_events_pending,
44 &phy->port_events[event].work, ha); 132 &phy->port_events[event].work, ha);
45} 133}
46 134
@@ -50,7 +138,7 @@ static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
50 138
51 BUG_ON(event >= PHY_NUM_EVENTS); 139 BUG_ON(event >= PHY_NUM_EVENTS);
52 140
53 sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending, 141 sas_queue_event(event, &phy->phy_events_pending,
54 &phy->phy_events[event].work, ha); 142 &phy->phy_events[event].work, ha);
55} 143}
56 144
@@ -62,8 +150,6 @@ int sas_init_events(struct sas_ha_struct *sas_ha)
62 150
63 int i; 151 int i;
64 152
65 spin_lock_init(&sas_ha->event_lock);
66
67 for (i = 0; i < HA_NUM_EVENTS; i++) { 153 for (i = 0; i < HA_NUM_EVENTS; i++) {
68 INIT_WORK(&sas_ha->ha_events[i].work, sas_ha_event_fns[i]); 154 INIT_WORK(&sas_ha->ha_events[i].work, sas_ha_event_fns[i]);
69 sas_ha->ha_events[i].ha = sas_ha; 155 sas_ha->ha_events[i].ha = sas_ha;