diff options
-rw-r--r-- | drivers/scsi/libsas/sas_event.c | 74 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_init.c | 27 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_internal.h | 6 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_phy.c | 44 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_port.c | 18 | ||||
-rw-r--r-- | include/scsi/libsas.h | 17 |
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 | ||
30 | int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw) | 30 | int 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 | ||
47 | static int sas_queue_event(int event, unsigned long *pending, | 48 | static 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 | |||
129 | static 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 | |||
137 | static 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 | |||
127 | static int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event) | 145 | static 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 | ||
137 | int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) | 166 | int 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 | ||
147 | int sas_init_events(struct sas_ha_struct *sas_ha) | 187 | int 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 | ||
41 | static struct kmem_cache *sas_task_cache; | 41 | static struct kmem_cache *sas_task_cache; |
42 | static struct kmem_cache *sas_event_cache; | ||
42 | 43 | ||
43 | struct sas_task *sas_alloc_task(gfp_t flags) | 44 | struct 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 | } |
556 | EXPORT_SYMBOL_GPL(sas_domain_attach_transport); | 555 | EXPORT_SYMBOL_GPL(sas_domain_attach_transport); |
557 | 556 | ||
557 | |||
558 | struct 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 | |||
565 | void 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 | ||
560 | static int __init sas_class_init(void) | 572 | static 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; |
583 | free_task_kmem: | ||
584 | kmem_cache_destroy(sas_task_cache); | ||
585 | out: | ||
586 | return -ENOMEM; | ||
567 | } | 587 | } |
568 | 588 | ||
569 | static void __exit sas_class_exit(void) | 589 | static 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 | ||
574 | MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>"); | 595 | MODULE_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); | |||
61 | int sas_register_phys(struct sas_ha_struct *sas_ha); | 61 | int sas_register_phys(struct sas_ha_struct *sas_ha); |
62 | void sas_unregister_phys(struct sas_ha_struct *sas_ha); | 62 | void sas_unregister_phys(struct sas_ha_struct *sas_ha); |
63 | 63 | ||
64 | struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy); | ||
65 | void sas_free_event(struct asd_sas_event *event); | ||
66 | |||
64 | int sas_register_ports(struct sas_ha_struct *sas_ha); | 67 | int sas_register_ports(struct sas_ha_struct *sas_ha); |
65 | void sas_unregister_ports(struct sas_ha_struct *sas_ha); | 68 | void 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 | ||
100 | void sas_free_device(struct kref *kref); | 103 | void sas_free_device(struct kref *kref); |
101 | 104 | ||
105 | extern const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS]; | ||
106 | extern 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 |
103 | extern void sas_smp_host_handler(struct bsg_job *job, struct Scsi_Host *shost); | 109 | extern 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 | |||
148 | const 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 | |||
347 | const 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 { | |||
292 | struct asd_sas_event { | 292 | struct 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 | ||
297 | static inline struct asd_sas_event *to_asd_sas_event(struct work_struct *work) | 298 | static 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 | ||
305 | static 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 | */ |
307 | struct asd_sas_phy { | 318 | struct 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 | ||