aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/libsas/sas_event.c74
-rw-r--r--drivers/scsi/libsas/sas_init.c27
-rw-r--r--drivers/scsi/libsas/sas_internal.h6
-rw-r--r--drivers/scsi/libsas/sas_phy.c44
-rw-r--r--drivers/scsi/libsas/sas_port.c18
-rw-r--r--include/scsi/libsas.h17
6 files changed, 115 insertions, 71 deletions
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index 0bb9eefc08c8..5d7254aa2dd2 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -29,7 +29,8 @@
29 29
30int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw) 30int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw)
31{ 31{
32 int rc = 0; 32 /* it's added to the defer_q when draining so return succeed */
33 int rc = 1;
33 34
34 if (!test_bit(SAS_HA_REGISTERED, &ha->state)) 35 if (!test_bit(SAS_HA_REGISTERED, &ha->state))
35 return 0; 36 return 0;
@@ -44,19 +45,15 @@ int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw)
44 return rc; 45 return rc;
45} 46}
46 47
47static int sas_queue_event(int event, unsigned long *pending, 48static int sas_queue_event(int event, struct sas_work *work,
48 struct sas_work *work,
49 struct sas_ha_struct *ha) 49 struct sas_ha_struct *ha)
50{ 50{
51 int rc = 0; 51 unsigned long flags;
52 int rc;
52 53
53 if (!test_and_set_bit(event, pending)) { 54 spin_lock_irqsave(&ha->lock, flags);
54 unsigned long flags; 55 rc = sas_queue_work(ha, work);
55 56 spin_unlock_irqrestore(&ha->lock, flags);
56 spin_lock_irqsave(&ha->lock, flags);
57 rc = sas_queue_work(ha, work);
58 spin_unlock_irqrestore(&ha->lock, flags);
59 }
60 57
61 return rc; 58 return rc;
62} 59}
@@ -66,6 +63,7 @@ void __sas_drain_work(struct sas_ha_struct *ha)
66{ 63{
67 struct workqueue_struct *wq = ha->core.shost->work_q; 64 struct workqueue_struct *wq = ha->core.shost->work_q;
68 struct sas_work *sw, *_sw; 65 struct sas_work *sw, *_sw;
66 int ret;
69 67
70 set_bit(SAS_HA_DRAINING, &ha->state); 68 set_bit(SAS_HA_DRAINING, &ha->state);
71 /* flush submitters */ 69 /* flush submitters */
@@ -78,7 +76,10 @@ void __sas_drain_work(struct sas_ha_struct *ha)
78 clear_bit(SAS_HA_DRAINING, &ha->state); 76 clear_bit(SAS_HA_DRAINING, &ha->state);
79 list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { 77 list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) {
80 list_del_init(&sw->drain_node); 78 list_del_init(&sw->drain_node);
81 sas_queue_work(ha, sw); 79 ret = sas_queue_work(ha, sw);
80 if (ret != 1)
81 sas_free_event(to_asd_sas_event(&sw->work));
82
82 } 83 }
83 spin_unlock_irq(&ha->lock); 84 spin_unlock_irq(&ha->lock);
84} 85}
@@ -119,29 +120,68 @@ void sas_enable_revalidation(struct sas_ha_struct *ha)
119 if (!test_and_clear_bit(ev, &d->pending)) 120 if (!test_and_clear_bit(ev, &d->pending))
120 continue; 121 continue;
121 122
122 sas_queue_event(ev, &d->pending, &d->disc_work[ev].work, ha); 123 sas_queue_event(ev, &d->disc_work[ev].work, ha);
123 } 124 }
124 mutex_unlock(&ha->disco_mutex); 125 mutex_unlock(&ha->disco_mutex);
125} 126}
126 127
128
129static void sas_port_event_worker(struct work_struct *work)
130{
131 struct asd_sas_event *ev = to_asd_sas_event(work);
132
133 sas_port_event_fns[ev->event](work);
134 sas_free_event(ev);
135}
136
137static void sas_phy_event_worker(struct work_struct *work)
138{
139 struct asd_sas_event *ev = to_asd_sas_event(work);
140
141 sas_phy_event_fns[ev->event](work);
142 sas_free_event(ev);
143}
144
127static int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event) 145static int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event)
128{ 146{
147 struct asd_sas_event *ev;
129 struct sas_ha_struct *ha = phy->ha; 148 struct sas_ha_struct *ha = phy->ha;
149 int ret;
130 150
131 BUG_ON(event >= PORT_NUM_EVENTS); 151 BUG_ON(event >= PORT_NUM_EVENTS);
132 152
133 return sas_queue_event(event, &phy->port_events_pending, 153 ev = sas_alloc_event(phy);
134 &phy->port_events[event].work, ha); 154 if (!ev)
155 return -ENOMEM;
156
157 INIT_SAS_EVENT(ev, sas_port_event_worker, phy, event);
158
159 ret = sas_queue_event(event, &ev->work, ha);
160 if (ret != 1)
161 sas_free_event(ev);
162
163 return ret;
135} 164}
136 165
137int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) 166int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
138{ 167{
168 struct asd_sas_event *ev;
139 struct sas_ha_struct *ha = phy->ha; 169 struct sas_ha_struct *ha = phy->ha;
170 int ret;
140 171
141 BUG_ON(event >= PHY_NUM_EVENTS); 172 BUG_ON(event >= PHY_NUM_EVENTS);
142 173
143 return sas_queue_event(event, &phy->phy_events_pending, 174 ev = sas_alloc_event(phy);
144 &phy->phy_events[event].work, ha); 175 if (!ev)
176 return -ENOMEM;
177
178 INIT_SAS_EVENT(ev, sas_phy_event_worker, phy, event);
179
180 ret = sas_queue_event(event, &ev->work, ha);
181 if (ret != 1)
182 sas_free_event(ev);
183
184 return ret;
145} 185}
146 186
147int sas_init_events(struct sas_ha_struct *sas_ha) 187int sas_init_events(struct sas_ha_struct *sas_ha)
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 64fa6f53cb8b..e04f6d6f5aff 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -39,6 +39,7 @@
39#include "../scsi_sas_internal.h" 39#include "../scsi_sas_internal.h"
40 40
41static struct kmem_cache *sas_task_cache; 41static struct kmem_cache *sas_task_cache;
42static struct kmem_cache *sas_event_cache;
42 43
43struct sas_task *sas_alloc_task(gfp_t flags) 44struct sas_task *sas_alloc_task(gfp_t flags)
44{ 45{
@@ -364,8 +365,6 @@ void sas_prep_resume_ha(struct sas_ha_struct *ha)
364 struct asd_sas_phy *phy = ha->sas_phy[i]; 365 struct asd_sas_phy *phy = ha->sas_phy[i];
365 366
366 memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE); 367 memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
367 phy->port_events_pending = 0;
368 phy->phy_events_pending = 0;
369 phy->frame_rcvd_size = 0; 368 phy->frame_rcvd_size = 0;
370 } 369 }
371} 370}
@@ -555,20 +554,42 @@ sas_domain_attach_transport(struct sas_domain_function_template *dft)
555} 554}
556EXPORT_SYMBOL_GPL(sas_domain_attach_transport); 555EXPORT_SYMBOL_GPL(sas_domain_attach_transport);
557 556
557
558struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy)
559{
560 gfp_t flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
561
562 return kmem_cache_zalloc(sas_event_cache, flags);
563}
564
565void sas_free_event(struct asd_sas_event *event)
566{
567 kmem_cache_free(sas_event_cache, event);
568}
569
558/* ---------- SAS Class register/unregister ---------- */ 570/* ---------- SAS Class register/unregister ---------- */
559 571
560static int __init sas_class_init(void) 572static int __init sas_class_init(void)
561{ 573{
562 sas_task_cache = KMEM_CACHE(sas_task, SLAB_HWCACHE_ALIGN); 574 sas_task_cache = KMEM_CACHE(sas_task, SLAB_HWCACHE_ALIGN);
563 if (!sas_task_cache) 575 if (!sas_task_cache)
564 return -ENOMEM; 576 goto out;
577
578 sas_event_cache = KMEM_CACHE(asd_sas_event, SLAB_HWCACHE_ALIGN);
579 if (!sas_event_cache)
580 goto free_task_kmem;
565 581
566 return 0; 582 return 0;
583free_task_kmem:
584 kmem_cache_destroy(sas_task_cache);
585out:
586 return -ENOMEM;
567} 587}
568 588
569static void __exit sas_class_exit(void) 589static void __exit sas_class_exit(void)
570{ 590{
571 kmem_cache_destroy(sas_task_cache); 591 kmem_cache_destroy(sas_task_cache);
592 kmem_cache_destroy(sas_event_cache);
572} 593}
573 594
574MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>"); 595MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>");
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index c07e08136491..d8826a747690 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -61,6 +61,9 @@ int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf);
61int sas_register_phys(struct sas_ha_struct *sas_ha); 61int sas_register_phys(struct sas_ha_struct *sas_ha);
62void sas_unregister_phys(struct sas_ha_struct *sas_ha); 62void sas_unregister_phys(struct sas_ha_struct *sas_ha);
63 63
64struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy);
65void sas_free_event(struct asd_sas_event *event);
66
64int sas_register_ports(struct sas_ha_struct *sas_ha); 67int sas_register_ports(struct sas_ha_struct *sas_ha);
65void sas_unregister_ports(struct sas_ha_struct *sas_ha); 68void sas_unregister_ports(struct sas_ha_struct *sas_ha);
66 69
@@ -99,6 +102,9 @@ void sas_hae_reset(struct work_struct *work);
99 102
100void sas_free_device(struct kref *kref); 103void sas_free_device(struct kref *kref);
101 104
105extern const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS];
106extern const work_func_t sas_port_event_fns[PORT_NUM_EVENTS];
107
102#ifdef CONFIG_SCSI_SAS_HOST_SMP 108#ifdef CONFIG_SCSI_SAS_HOST_SMP
103extern void sas_smp_host_handler(struct bsg_job *job, struct Scsi_Host *shost); 109extern void sas_smp_host_handler(struct bsg_job *job, struct Scsi_Host *shost);
104#else 110#else
diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c
index cdee446c29e1..59f82929b0a3 100644
--- a/drivers/scsi/libsas/sas_phy.c
+++ b/drivers/scsi/libsas/sas_phy.c
@@ -35,7 +35,6 @@ static void sas_phye_loss_of_signal(struct work_struct *work)
35 struct asd_sas_event *ev = to_asd_sas_event(work); 35 struct asd_sas_event *ev = to_asd_sas_event(work);
36 struct asd_sas_phy *phy = ev->phy; 36 struct asd_sas_phy *phy = ev->phy;
37 37
38 clear_bit(PHYE_LOSS_OF_SIGNAL, &phy->phy_events_pending);
39 phy->error = 0; 38 phy->error = 0;
40 sas_deform_port(phy, 1); 39 sas_deform_port(phy, 1);
41} 40}
@@ -45,7 +44,6 @@ static void sas_phye_oob_done(struct work_struct *work)
45 struct asd_sas_event *ev = to_asd_sas_event(work); 44 struct asd_sas_event *ev = to_asd_sas_event(work);
46 struct asd_sas_phy *phy = ev->phy; 45 struct asd_sas_phy *phy = ev->phy;
47 46
48 clear_bit(PHYE_OOB_DONE, &phy->phy_events_pending);
49 phy->error = 0; 47 phy->error = 0;
50} 48}
51 49
@@ -58,8 +56,6 @@ static void sas_phye_oob_error(struct work_struct *work)
58 struct sas_internal *i = 56 struct sas_internal *i =
59 to_sas_internal(sas_ha->core.shost->transportt); 57 to_sas_internal(sas_ha->core.shost->transportt);
60 58
61 clear_bit(PHYE_OOB_ERROR, &phy->phy_events_pending);
62
63 sas_deform_port(phy, 1); 59 sas_deform_port(phy, 1);
64 60
65 if (!port && phy->enabled && i->dft->lldd_control_phy) { 61 if (!port && phy->enabled && i->dft->lldd_control_phy) {
@@ -88,8 +84,6 @@ static void sas_phye_spinup_hold(struct work_struct *work)
88 struct sas_internal *i = 84 struct sas_internal *i =
89 to_sas_internal(sas_ha->core.shost->transportt); 85 to_sas_internal(sas_ha->core.shost->transportt);
90 86
91 clear_bit(PHYE_SPINUP_HOLD, &phy->phy_events_pending);
92
93 phy->error = 0; 87 phy->error = 0;
94 i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL); 88 i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
95} 89}
@@ -99,8 +93,6 @@ static void sas_phye_resume_timeout(struct work_struct *work)
99 struct asd_sas_event *ev = to_asd_sas_event(work); 93 struct asd_sas_event *ev = to_asd_sas_event(work);
100 struct asd_sas_phy *phy = ev->phy; 94 struct asd_sas_phy *phy = ev->phy;
101 95
102 clear_bit(PHYE_RESUME_TIMEOUT, &phy->phy_events_pending);
103
104 /* phew, lldd got the phy back in the nick of time */ 96 /* phew, lldd got the phy back in the nick of time */
105 if (!phy->suspended) { 97 if (!phy->suspended) {
106 dev_info(&phy->phy->dev, "resume timeout cancelled\n"); 98 dev_info(&phy->phy->dev, "resume timeout cancelled\n");
@@ -119,39 +111,12 @@ int sas_register_phys(struct sas_ha_struct *sas_ha)
119{ 111{
120 int i; 112 int i;
121 113
122 static const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = {
123 [PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal,
124 [PHYE_OOB_DONE] = sas_phye_oob_done,
125 [PHYE_OOB_ERROR] = sas_phye_oob_error,
126 [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
127 [PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
128
129 };
130
131 static const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = {
132 [PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed,
133 [PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd,
134 [PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err,
135 [PORTE_TIMER_EVENT] = sas_porte_timer_event,
136 [PORTE_HARD_RESET] = sas_porte_hard_reset,
137 };
138
139 /* Now register the phys. */ 114 /* Now register the phys. */
140 for (i = 0; i < sas_ha->num_phys; i++) { 115 for (i = 0; i < sas_ha->num_phys; i++) {
141 int k;
142 struct asd_sas_phy *phy = sas_ha->sas_phy[i]; 116 struct asd_sas_phy *phy = sas_ha->sas_phy[i];
143 117
144 phy->error = 0; 118 phy->error = 0;
145 INIT_LIST_HEAD(&phy->port_phy_el); 119 INIT_LIST_HEAD(&phy->port_phy_el);
146 for (k = 0; k < PORT_NUM_EVENTS; k++) {
147 INIT_SAS_WORK(&phy->port_events[k].work, sas_port_event_fns[k]);
148 phy->port_events[k].phy = phy;
149 }
150
151 for (k = 0; k < PHY_NUM_EVENTS; k++) {
152 INIT_SAS_WORK(&phy->phy_events[k].work, sas_phy_event_fns[k]);
153 phy->phy_events[k].phy = phy;
154 }
155 120
156 phy->port = NULL; 121 phy->port = NULL;
157 phy->ha = sas_ha; 122 phy->ha = sas_ha;
@@ -179,3 +144,12 @@ int sas_register_phys(struct sas_ha_struct *sas_ha)
179 144
180 return 0; 145 return 0;
181} 146}
147
148const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = {
149 [PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal,
150 [PHYE_OOB_DONE] = sas_phye_oob_done,
151 [PHYE_OOB_ERROR] = sas_phye_oob_error,
152 [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
153 [PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
154
155};
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index d3c5297c6c89..93266283f51f 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -261,8 +261,6 @@ void sas_porte_bytes_dmaed(struct work_struct *work)
261 struct asd_sas_event *ev = to_asd_sas_event(work); 261 struct asd_sas_event *ev = to_asd_sas_event(work);
262 struct asd_sas_phy *phy = ev->phy; 262 struct asd_sas_phy *phy = ev->phy;
263 263
264 clear_bit(PORTE_BYTES_DMAED, &phy->port_events_pending);
265
266 sas_form_port(phy); 264 sas_form_port(phy);
267} 265}
268 266
@@ -273,8 +271,6 @@ void sas_porte_broadcast_rcvd(struct work_struct *work)
273 unsigned long flags; 271 unsigned long flags;
274 u32 prim; 272 u32 prim;
275 273
276 clear_bit(PORTE_BROADCAST_RCVD, &phy->port_events_pending);
277
278 spin_lock_irqsave(&phy->sas_prim_lock, flags); 274 spin_lock_irqsave(&phy->sas_prim_lock, flags);
279 prim = phy->sas_prim; 275 prim = phy->sas_prim;
280 spin_unlock_irqrestore(&phy->sas_prim_lock, flags); 276 spin_unlock_irqrestore(&phy->sas_prim_lock, flags);
@@ -288,8 +284,6 @@ void sas_porte_link_reset_err(struct work_struct *work)
288 struct asd_sas_event *ev = to_asd_sas_event(work); 284 struct asd_sas_event *ev = to_asd_sas_event(work);
289 struct asd_sas_phy *phy = ev->phy; 285 struct asd_sas_phy *phy = ev->phy;
290 286
291 clear_bit(PORTE_LINK_RESET_ERR, &phy->port_events_pending);
292
293 sas_deform_port(phy, 1); 287 sas_deform_port(phy, 1);
294} 288}
295 289
@@ -298,8 +292,6 @@ void sas_porte_timer_event(struct work_struct *work)
298 struct asd_sas_event *ev = to_asd_sas_event(work); 292 struct asd_sas_event *ev = to_asd_sas_event(work);
299 struct asd_sas_phy *phy = ev->phy; 293 struct asd_sas_phy *phy = ev->phy;
300 294
301 clear_bit(PORTE_TIMER_EVENT, &phy->port_events_pending);
302
303 sas_deform_port(phy, 1); 295 sas_deform_port(phy, 1);
304} 296}
305 297
@@ -308,8 +300,6 @@ void sas_porte_hard_reset(struct work_struct *work)
308 struct asd_sas_event *ev = to_asd_sas_event(work); 300 struct asd_sas_event *ev = to_asd_sas_event(work);
309 struct asd_sas_phy *phy = ev->phy; 301 struct asd_sas_phy *phy = ev->phy;
310 302
311 clear_bit(PORTE_HARD_RESET, &phy->port_events_pending);
312
313 sas_deform_port(phy, 1); 303 sas_deform_port(phy, 1);
314} 304}
315 305
@@ -353,3 +343,11 @@ void sas_unregister_ports(struct sas_ha_struct *sas_ha)
353 sas_deform_port(sas_ha->sas_phy[i], 0); 343 sas_deform_port(sas_ha->sas_phy[i], 0);
354 344
355} 345}
346
347const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = {
348 [PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed,
349 [PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd,
350 [PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err,
351 [PORTE_TIMER_EVENT] = sas_porte_timer_event,
352 [PORTE_HARD_RESET] = sas_porte_hard_reset,
353};
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 0f9cbf96c093..ee1b25299dd6 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -292,6 +292,7 @@ struct asd_sas_port {
292struct asd_sas_event { 292struct asd_sas_event {
293 struct sas_work work; 293 struct sas_work work;
294 struct asd_sas_phy *phy; 294 struct asd_sas_phy *phy;
295 int event;
295}; 296};
296 297
297static inline struct asd_sas_event *to_asd_sas_event(struct work_struct *work) 298static inline struct asd_sas_event *to_asd_sas_event(struct work_struct *work)
@@ -301,17 +302,21 @@ static inline struct asd_sas_event *to_asd_sas_event(struct work_struct *work)
301 return ev; 302 return ev;
302} 303}
303 304
305static inline void INIT_SAS_EVENT(struct asd_sas_event *ev,
306 void (*fn)(struct work_struct *),
307 struct asd_sas_phy *phy, int event)
308{
309 INIT_SAS_WORK(&ev->work, fn);
310 ev->phy = phy;
311 ev->event = event;
312}
313
314
304/* The phy pretty much is controlled by the LLDD. 315/* The phy pretty much is controlled by the LLDD.
305 * The class only reads those fields. 316 * The class only reads those fields.
306 */ 317 */
307struct asd_sas_phy { 318struct asd_sas_phy {
308/* private: */ 319/* private: */
309 struct asd_sas_event port_events[PORT_NUM_EVENTS];
310 struct asd_sas_event phy_events[PHY_NUM_EVENTS];
311
312 unsigned long port_events_pending;
313 unsigned long phy_events_pending;
314
315 int error; 320 int error;
316 int suspended; 321 int suspended;
317 322