diff options
author | Dan Williams <dan.j.williams@intel.com> | 2012-03-09 14:00:06 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-04-23 07:03:39 -0400 |
commit | 22b9153faa2263aa89625de25e71c7d44c8dbd16 (patch) | |
tree | 1157d64a9c63c5b7b48b4a5b3610965d8d4c9624 | |
parent | f8fc75dc576eac0c996e4a792a4701819d999260 (diff) |
[SCSI] libsas: introduce sas_work to fix sas_drain_work vs sas_queue_work
When requeuing work to a draining workqueue the last work instance may
not be idle, so sas_queue_work() must not touch work->entry. Introduce
sas_work with a drain_node list_head to have a private list for
collecting work deferred due to drain collision.
Fixes reports like:
BUG: unable to handle kernel NULL pointer dereference at (null)
IP: [<ffffffff810410d4>] process_one_work+0x2e/0x338
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r-- | drivers/scsi/libsas/sas_discover.c | 28 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_event.c | 24 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_init.c | 11 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_internal.h | 6 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_phy.c | 21 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_port.c | 15 | ||||
-rw-r--r-- | include/scsi/libsas.h | 40 |
7 files changed, 83 insertions, 62 deletions
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 364679675602..c7ac88288bf1 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c | |||
@@ -205,8 +205,7 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev) | |||
205 | static void sas_probe_devices(struct work_struct *work) | 205 | static void sas_probe_devices(struct work_struct *work) |
206 | { | 206 | { |
207 | struct domain_device *dev, *n; | 207 | struct domain_device *dev, *n; |
208 | struct sas_discovery_event *ev = | 208 | struct sas_discovery_event *ev = to_sas_discovery_event(work); |
209 | container_of(work, struct sas_discovery_event, work); | ||
210 | struct asd_sas_port *port = ev->port; | 209 | struct asd_sas_port *port = ev->port; |
211 | 210 | ||
212 | clear_bit(DISCE_PROBE, &port->disc.pending); | 211 | clear_bit(DISCE_PROBE, &port->disc.pending); |
@@ -291,8 +290,7 @@ static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_d | |||
291 | static void sas_destruct_devices(struct work_struct *work) | 290 | static void sas_destruct_devices(struct work_struct *work) |
292 | { | 291 | { |
293 | struct domain_device *dev, *n; | 292 | struct domain_device *dev, *n; |
294 | struct sas_discovery_event *ev = | 293 | struct sas_discovery_event *ev = to_sas_discovery_event(work); |
295 | container_of(work, struct sas_discovery_event, work); | ||
296 | struct asd_sas_port *port = ev->port; | 294 | struct asd_sas_port *port = ev->port; |
297 | 295 | ||
298 | clear_bit(DISCE_DESTRUCT, &port->disc.pending); | 296 | clear_bit(DISCE_DESTRUCT, &port->disc.pending); |
@@ -377,8 +375,7 @@ static void sas_discover_domain(struct work_struct *work) | |||
377 | { | 375 | { |
378 | struct domain_device *dev; | 376 | struct domain_device *dev; |
379 | int error = 0; | 377 | int error = 0; |
380 | struct sas_discovery_event *ev = | 378 | struct sas_discovery_event *ev = to_sas_discovery_event(work); |
381 | container_of(work, struct sas_discovery_event, work); | ||
382 | struct asd_sas_port *port = ev->port; | 379 | struct asd_sas_port *port = ev->port; |
383 | 380 | ||
384 | clear_bit(DISCE_DISCOVER_DOMAIN, &port->disc.pending); | 381 | clear_bit(DISCE_DISCOVER_DOMAIN, &port->disc.pending); |
@@ -437,8 +434,7 @@ static void sas_discover_domain(struct work_struct *work) | |||
437 | static void sas_revalidate_domain(struct work_struct *work) | 434 | static void sas_revalidate_domain(struct work_struct *work) |
438 | { | 435 | { |
439 | int res = 0; | 436 | int res = 0; |
440 | struct sas_discovery_event *ev = | 437 | struct sas_discovery_event *ev = to_sas_discovery_event(work); |
441 | container_of(work, struct sas_discovery_event, work); | ||
442 | struct asd_sas_port *port = ev->port; | 438 | struct asd_sas_port *port = ev->port; |
443 | struct sas_ha_struct *ha = port->ha; | 439 | struct sas_ha_struct *ha = port->ha; |
444 | 440 | ||
@@ -466,21 +462,25 @@ static void sas_revalidate_domain(struct work_struct *work) | |||
466 | 462 | ||
467 | /* ---------- Events ---------- */ | 463 | /* ---------- Events ---------- */ |
468 | 464 | ||
469 | static void sas_chain_work(struct sas_ha_struct *ha, struct work_struct *work) | 465 | static void sas_chain_work(struct sas_ha_struct *ha, struct sas_work *sw) |
470 | { | 466 | { |
471 | /* chained work is not subject to SA_HA_DRAINING or SAS_HA_REGISTERED */ | 467 | /* chained work is not subject to SA_HA_DRAINING or |
472 | scsi_queue_work(ha->core.shost, work); | 468 | * SAS_HA_REGISTERED, because it is either submitted in the |
469 | * workqueue, or known to be submitted from a context that is | ||
470 | * not racing against draining | ||
471 | */ | ||
472 | scsi_queue_work(ha->core.shost, &sw->work); | ||
473 | } | 473 | } |
474 | 474 | ||
475 | static void sas_chain_event(int event, unsigned long *pending, | 475 | static void sas_chain_event(int event, unsigned long *pending, |
476 | struct work_struct *work, | 476 | struct sas_work *sw, |
477 | struct sas_ha_struct *ha) | 477 | struct sas_ha_struct *ha) |
478 | { | 478 | { |
479 | if (!test_and_set_bit(event, pending)) { | 479 | if (!test_and_set_bit(event, pending)) { |
480 | unsigned long flags; | 480 | unsigned long flags; |
481 | 481 | ||
482 | spin_lock_irqsave(&ha->state_lock, flags); | 482 | spin_lock_irqsave(&ha->state_lock, flags); |
483 | sas_chain_work(ha, work); | 483 | sas_chain_work(ha, sw); |
484 | spin_unlock_irqrestore(&ha->state_lock, flags); | 484 | spin_unlock_irqrestore(&ha->state_lock, flags); |
485 | } | 485 | } |
486 | } | 486 | } |
@@ -519,7 +519,7 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port) | |||
519 | 519 | ||
520 | disc->pending = 0; | 520 | disc->pending = 0; |
521 | for (i = 0; i < DISC_NUM_EVENTS; i++) { | 521 | for (i = 0; i < DISC_NUM_EVENTS; i++) { |
522 | INIT_WORK(&disc->disc_work[i].work, sas_event_fns[i]); | 522 | INIT_SAS_WORK(&disc->disc_work[i].work, sas_event_fns[i]); |
523 | disc->disc_work[i].port = port; | 523 | disc->disc_work[i].port = port; |
524 | } | 524 | } |
525 | } | 525 | } |
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index 16639bbae629..4e4292d210c1 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c | |||
@@ -27,19 +27,21 @@ | |||
27 | #include "sas_internal.h" | 27 | #include "sas_internal.h" |
28 | #include "sas_dump.h" | 28 | #include "sas_dump.h" |
29 | 29 | ||
30 | void sas_queue_work(struct sas_ha_struct *ha, struct work_struct *work) | 30 | void sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw) |
31 | { | 31 | { |
32 | if (!test_bit(SAS_HA_REGISTERED, &ha->state)) | 32 | if (!test_bit(SAS_HA_REGISTERED, &ha->state)) |
33 | return; | 33 | return; |
34 | 34 | ||
35 | if (test_bit(SAS_HA_DRAINING, &ha->state)) | 35 | if (test_bit(SAS_HA_DRAINING, &ha->state)) { |
36 | list_add(&work->entry, &ha->defer_q); | 36 | /* add it to the defer list, if not already pending */ |
37 | else | 37 | if (list_empty(&sw->drain_node)) |
38 | scsi_queue_work(ha->core.shost, work); | 38 | list_add(&sw->drain_node, &ha->defer_q); |
39 | } else | ||
40 | scsi_queue_work(ha->core.shost, &sw->work); | ||
39 | } | 41 | } |
40 | 42 | ||
41 | static void sas_queue_event(int event, unsigned long *pending, | 43 | static void sas_queue_event(int event, unsigned long *pending, |
42 | struct work_struct *work, | 44 | struct sas_work *work, |
43 | struct sas_ha_struct *ha) | 45 | struct sas_ha_struct *ha) |
44 | { | 46 | { |
45 | if (!test_and_set_bit(event, pending)) { | 47 | if (!test_and_set_bit(event, pending)) { |
@@ -55,7 +57,7 @@ static void sas_queue_event(int event, unsigned long *pending, | |||
55 | void __sas_drain_work(struct sas_ha_struct *ha) | 57 | void __sas_drain_work(struct sas_ha_struct *ha) |
56 | { | 58 | { |
57 | struct workqueue_struct *wq = ha->core.shost->work_q; | 59 | struct workqueue_struct *wq = ha->core.shost->work_q; |
58 | struct work_struct *w, *_w; | 60 | struct sas_work *sw, *_sw; |
59 | 61 | ||
60 | set_bit(SAS_HA_DRAINING, &ha->state); | 62 | set_bit(SAS_HA_DRAINING, &ha->state); |
61 | /* flush submitters */ | 63 | /* flush submitters */ |
@@ -66,9 +68,9 @@ void __sas_drain_work(struct sas_ha_struct *ha) | |||
66 | 68 | ||
67 | spin_lock_irq(&ha->state_lock); | 69 | spin_lock_irq(&ha->state_lock); |
68 | clear_bit(SAS_HA_DRAINING, &ha->state); | 70 | clear_bit(SAS_HA_DRAINING, &ha->state); |
69 | list_for_each_entry_safe(w, _w, &ha->defer_q, entry) { | 71 | list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { |
70 | list_del_init(&w->entry); | 72 | list_del_init(&sw->drain_node); |
71 | sas_queue_work(ha, w); | 73 | sas_queue_work(ha, sw); |
72 | } | 74 | } |
73 | spin_unlock_irq(&ha->state_lock); | 75 | spin_unlock_irq(&ha->state_lock); |
74 | } | 76 | } |
@@ -151,7 +153,7 @@ int sas_init_events(struct sas_ha_struct *sas_ha) | |||
151 | int i; | 153 | int i; |
152 | 154 | ||
153 | for (i = 0; i < HA_NUM_EVENTS; i++) { | 155 | for (i = 0; i < HA_NUM_EVENTS; i++) { |
154 | INIT_WORK(&sas_ha->ha_events[i].work, sas_ha_event_fns[i]); | 156 | INIT_SAS_WORK(&sas_ha->ha_events[i].work, sas_ha_event_fns[i]); |
155 | sas_ha->ha_events[i].ha = sas_ha; | 157 | sas_ha->ha_events[i].ha = sas_ha; |
156 | } | 158 | } |
157 | 159 | ||
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 120bff64be30..10cb5ae30977 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c | |||
@@ -94,8 +94,7 @@ void sas_hash_addr(u8 *hashed, const u8 *sas_addr) | |||
94 | 94 | ||
95 | void sas_hae_reset(struct work_struct *work) | 95 | void sas_hae_reset(struct work_struct *work) |
96 | { | 96 | { |
97 | struct sas_ha_event *ev = | 97 | struct sas_ha_event *ev = to_sas_ha_event(work); |
98 | container_of(work, struct sas_ha_event, work); | ||
99 | struct sas_ha_struct *ha = ev->ha; | 98 | struct sas_ha_struct *ha = ev->ha; |
100 | 99 | ||
101 | clear_bit(HAE_RESET, &ha->pending); | 100 | clear_bit(HAE_RESET, &ha->pending); |
@@ -369,14 +368,14 @@ static void sas_phy_release(struct sas_phy *phy) | |||
369 | 368 | ||
370 | static void phy_reset_work(struct work_struct *work) | 369 | static void phy_reset_work(struct work_struct *work) |
371 | { | 370 | { |
372 | struct sas_phy_data *d = container_of(work, typeof(*d), reset_work); | 371 | struct sas_phy_data *d = container_of(work, typeof(*d), reset_work.work); |
373 | 372 | ||
374 | d->reset_result = transport_sas_phy_reset(d->phy, d->hard_reset); | 373 | d->reset_result = transport_sas_phy_reset(d->phy, d->hard_reset); |
375 | } | 374 | } |
376 | 375 | ||
377 | static void phy_enable_work(struct work_struct *work) | 376 | static void phy_enable_work(struct work_struct *work) |
378 | { | 377 | { |
379 | struct sas_phy_data *d = container_of(work, typeof(*d), enable_work); | 378 | struct sas_phy_data *d = container_of(work, typeof(*d), enable_work.work); |
380 | 379 | ||
381 | d->enable_result = sas_phy_enable(d->phy, d->enable); | 380 | d->enable_result = sas_phy_enable(d->phy, d->enable); |
382 | } | 381 | } |
@@ -389,8 +388,8 @@ static int sas_phy_setup(struct sas_phy *phy) | |||
389 | return -ENOMEM; | 388 | return -ENOMEM; |
390 | 389 | ||
391 | mutex_init(&d->event_lock); | 390 | mutex_init(&d->event_lock); |
392 | INIT_WORK(&d->reset_work, phy_reset_work); | 391 | INIT_SAS_WORK(&d->reset_work, phy_reset_work); |
393 | INIT_WORK(&d->enable_work, phy_enable_work); | 392 | INIT_SAS_WORK(&d->enable_work, phy_enable_work); |
394 | d->phy = phy; | 393 | d->phy = phy; |
395 | phy->hostdata = d; | 394 | phy->hostdata = d; |
396 | 395 | ||
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index f05c63879949..507e4cf12e56 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h | |||
@@ -45,10 +45,10 @@ struct sas_phy_data { | |||
45 | struct mutex event_lock; | 45 | struct mutex event_lock; |
46 | int hard_reset; | 46 | int hard_reset; |
47 | int reset_result; | 47 | int reset_result; |
48 | struct work_struct reset_work; | 48 | struct sas_work reset_work; |
49 | int enable; | 49 | int enable; |
50 | int enable_result; | 50 | int enable_result; |
51 | struct work_struct enable_work; | 51 | struct sas_work enable_work; |
52 | }; | 52 | }; |
53 | 53 | ||
54 | void sas_scsi_recover_host(struct Scsi_Host *shost); | 54 | void sas_scsi_recover_host(struct Scsi_Host *shost); |
@@ -80,7 +80,7 @@ void sas_porte_broadcast_rcvd(struct work_struct *work); | |||
80 | void sas_porte_link_reset_err(struct work_struct *work); | 80 | void sas_porte_link_reset_err(struct work_struct *work); |
81 | void sas_porte_timer_event(struct work_struct *work); | 81 | void sas_porte_timer_event(struct work_struct *work); |
82 | void sas_porte_hard_reset(struct work_struct *work); | 82 | void sas_porte_hard_reset(struct work_struct *work); |
83 | void sas_queue_work(struct sas_ha_struct *ha, struct work_struct *work); | 83 | void sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw); |
84 | 84 | ||
85 | int sas_notify_lldd_dev_found(struct domain_device *); | 85 | int sas_notify_lldd_dev_found(struct domain_device *); |
86 | void sas_notify_lldd_dev_gone(struct domain_device *); | 86 | void sas_notify_lldd_dev_gone(struct domain_device *); |
diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c index dcfd4a9105c5..521422e857ab 100644 --- a/drivers/scsi/libsas/sas_phy.c +++ b/drivers/scsi/libsas/sas_phy.c | |||
@@ -32,8 +32,7 @@ | |||
32 | 32 | ||
33 | static void sas_phye_loss_of_signal(struct work_struct *work) | 33 | static void sas_phye_loss_of_signal(struct work_struct *work) |
34 | { | 34 | { |
35 | struct asd_sas_event *ev = | 35 | struct asd_sas_event *ev = to_asd_sas_event(work); |
36 | container_of(work, struct asd_sas_event, work); | ||
37 | struct asd_sas_phy *phy = ev->phy; | 36 | struct asd_sas_phy *phy = ev->phy; |
38 | 37 | ||
39 | clear_bit(PHYE_LOSS_OF_SIGNAL, &phy->phy_events_pending); | 38 | clear_bit(PHYE_LOSS_OF_SIGNAL, &phy->phy_events_pending); |
@@ -43,8 +42,7 @@ static void sas_phye_loss_of_signal(struct work_struct *work) | |||
43 | 42 | ||
44 | static void sas_phye_oob_done(struct work_struct *work) | 43 | static void sas_phye_oob_done(struct work_struct *work) |
45 | { | 44 | { |
46 | struct asd_sas_event *ev = | 45 | struct asd_sas_event *ev = to_asd_sas_event(work); |
47 | container_of(work, struct asd_sas_event, work); | ||
48 | struct asd_sas_phy *phy = ev->phy; | 46 | struct asd_sas_phy *phy = ev->phy; |
49 | 47 | ||
50 | clear_bit(PHYE_OOB_DONE, &phy->phy_events_pending); | 48 | clear_bit(PHYE_OOB_DONE, &phy->phy_events_pending); |
@@ -53,8 +51,7 @@ static void sas_phye_oob_done(struct work_struct *work) | |||
53 | 51 | ||
54 | static void sas_phye_oob_error(struct work_struct *work) | 52 | static void sas_phye_oob_error(struct work_struct *work) |
55 | { | 53 | { |
56 | struct asd_sas_event *ev = | 54 | struct asd_sas_event *ev = to_asd_sas_event(work); |
57 | container_of(work, struct asd_sas_event, work); | ||
58 | struct asd_sas_phy *phy = ev->phy; | 55 | struct asd_sas_phy *phy = ev->phy; |
59 | struct sas_ha_struct *sas_ha = phy->ha; | 56 | struct sas_ha_struct *sas_ha = phy->ha; |
60 | struct asd_sas_port *port = phy->port; | 57 | struct asd_sas_port *port = phy->port; |
@@ -85,8 +82,7 @@ static void sas_phye_oob_error(struct work_struct *work) | |||
85 | 82 | ||
86 | static void sas_phye_spinup_hold(struct work_struct *work) | 83 | static void sas_phye_spinup_hold(struct work_struct *work) |
87 | { | 84 | { |
88 | struct asd_sas_event *ev = | 85 | struct asd_sas_event *ev = to_asd_sas_event(work); |
89 | container_of(work, struct asd_sas_event, work); | ||
90 | struct asd_sas_phy *phy = ev->phy; | 86 | struct asd_sas_phy *phy = ev->phy; |
91 | struct sas_ha_struct *sas_ha = phy->ha; | 87 | struct sas_ha_struct *sas_ha = phy->ha; |
92 | struct sas_internal *i = | 88 | struct sas_internal *i = |
@@ -127,14 +123,12 @@ int sas_register_phys(struct sas_ha_struct *sas_ha) | |||
127 | phy->error = 0; | 123 | phy->error = 0; |
128 | INIT_LIST_HEAD(&phy->port_phy_el); | 124 | INIT_LIST_HEAD(&phy->port_phy_el); |
129 | for (k = 0; k < PORT_NUM_EVENTS; k++) { | 125 | for (k = 0; k < PORT_NUM_EVENTS; k++) { |
130 | INIT_WORK(&phy->port_events[k].work, | 126 | INIT_SAS_WORK(&phy->port_events[k].work, sas_port_event_fns[k]); |
131 | sas_port_event_fns[k]); | ||
132 | phy->port_events[k].phy = phy; | 127 | phy->port_events[k].phy = phy; |
133 | } | 128 | } |
134 | 129 | ||
135 | for (k = 0; k < PHY_NUM_EVENTS; k++) { | 130 | for (k = 0; k < PHY_NUM_EVENTS; k++) { |
136 | INIT_WORK(&phy->phy_events[k].work, | 131 | INIT_SAS_WORK(&phy->phy_events[k].work, sas_phy_event_fns[k]); |
137 | sas_phy_event_fns[k]); | ||
138 | phy->phy_events[k].phy = phy; | 132 | phy->phy_events[k].phy = phy; |
139 | } | 133 | } |
140 | 134 | ||
@@ -144,8 +138,7 @@ int sas_register_phys(struct sas_ha_struct *sas_ha) | |||
144 | spin_lock_init(&phy->sas_prim_lock); | 138 | spin_lock_init(&phy->sas_prim_lock); |
145 | phy->frame_rcvd_size = 0; | 139 | phy->frame_rcvd_size = 0; |
146 | 140 | ||
147 | phy->phy = sas_phy_alloc(&sas_ha->core.shost->shost_gendev, | 141 | phy->phy = sas_phy_alloc(&sas_ha->core.shost->shost_gendev, i); |
148 | i); | ||
149 | if (!phy->phy) | 142 | if (!phy->phy) |
150 | return -ENOMEM; | 143 | return -ENOMEM; |
151 | 144 | ||
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index eb19c016d500..1cf7d75ad5eb 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c | |||
@@ -208,8 +208,7 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone) | |||
208 | 208 | ||
209 | void sas_porte_bytes_dmaed(struct work_struct *work) | 209 | void sas_porte_bytes_dmaed(struct work_struct *work) |
210 | { | 210 | { |
211 | struct asd_sas_event *ev = | 211 | struct asd_sas_event *ev = to_asd_sas_event(work); |
212 | container_of(work, struct asd_sas_event, work); | ||
213 | struct asd_sas_phy *phy = ev->phy; | 212 | struct asd_sas_phy *phy = ev->phy; |
214 | 213 | ||
215 | clear_bit(PORTE_BYTES_DMAED, &phy->port_events_pending); | 214 | clear_bit(PORTE_BYTES_DMAED, &phy->port_events_pending); |
@@ -219,8 +218,7 @@ void sas_porte_bytes_dmaed(struct work_struct *work) | |||
219 | 218 | ||
220 | void sas_porte_broadcast_rcvd(struct work_struct *work) | 219 | void sas_porte_broadcast_rcvd(struct work_struct *work) |
221 | { | 220 | { |
222 | struct asd_sas_event *ev = | 221 | struct asd_sas_event *ev = to_asd_sas_event(work); |
223 | container_of(work, struct asd_sas_event, work); | ||
224 | struct asd_sas_phy *phy = ev->phy; | 222 | struct asd_sas_phy *phy = ev->phy; |
225 | unsigned long flags; | 223 | unsigned long flags; |
226 | u32 prim; | 224 | u32 prim; |
@@ -237,8 +235,7 @@ void sas_porte_broadcast_rcvd(struct work_struct *work) | |||
237 | 235 | ||
238 | void sas_porte_link_reset_err(struct work_struct *work) | 236 | void sas_porte_link_reset_err(struct work_struct *work) |
239 | { | 237 | { |
240 | struct asd_sas_event *ev = | 238 | struct asd_sas_event *ev = to_asd_sas_event(work); |
241 | container_of(work, struct asd_sas_event, work); | ||
242 | struct asd_sas_phy *phy = ev->phy; | 239 | struct asd_sas_phy *phy = ev->phy; |
243 | 240 | ||
244 | clear_bit(PORTE_LINK_RESET_ERR, &phy->port_events_pending); | 241 | clear_bit(PORTE_LINK_RESET_ERR, &phy->port_events_pending); |
@@ -248,8 +245,7 @@ void sas_porte_link_reset_err(struct work_struct *work) | |||
248 | 245 | ||
249 | void sas_porte_timer_event(struct work_struct *work) | 246 | void sas_porte_timer_event(struct work_struct *work) |
250 | { | 247 | { |
251 | struct asd_sas_event *ev = | 248 | struct asd_sas_event *ev = to_asd_sas_event(work); |
252 | container_of(work, struct asd_sas_event, work); | ||
253 | struct asd_sas_phy *phy = ev->phy; | 249 | struct asd_sas_phy *phy = ev->phy; |
254 | 250 | ||
255 | clear_bit(PORTE_TIMER_EVENT, &phy->port_events_pending); | 251 | clear_bit(PORTE_TIMER_EVENT, &phy->port_events_pending); |
@@ -259,8 +255,7 @@ void sas_porte_timer_event(struct work_struct *work) | |||
259 | 255 | ||
260 | void sas_porte_hard_reset(struct work_struct *work) | 256 | void sas_porte_hard_reset(struct work_struct *work) |
261 | { | 257 | { |
262 | struct asd_sas_event *ev = | 258 | struct asd_sas_event *ev = to_asd_sas_event(work); |
263 | container_of(work, struct asd_sas_event, work); | ||
264 | struct asd_sas_phy *phy = ev->phy; | 259 | struct asd_sas_phy *phy = ev->phy; |
265 | 260 | ||
266 | clear_bit(PORTE_HARD_RESET, &phy->port_events_pending); | 261 | clear_bit(PORTE_HARD_RESET, &phy->port_events_pending); |
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 5f5ed1b8b41b..f4f1c96dca72 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h | |||
@@ -217,11 +217,29 @@ struct domain_device { | |||
217 | struct kref kref; | 217 | struct kref kref; |
218 | }; | 218 | }; |
219 | 219 | ||
220 | struct sas_discovery_event { | 220 | struct sas_work { |
221 | struct list_head drain_node; | ||
221 | struct work_struct work; | 222 | struct work_struct work; |
223 | }; | ||
224 | |||
225 | static inline void INIT_SAS_WORK(struct sas_work *sw, void (*fn)(struct work_struct *)) | ||
226 | { | ||
227 | INIT_WORK(&sw->work, fn); | ||
228 | INIT_LIST_HEAD(&sw->drain_node); | ||
229 | } | ||
230 | |||
231 | struct sas_discovery_event { | ||
232 | struct sas_work work; | ||
222 | struct asd_sas_port *port; | 233 | struct asd_sas_port *port; |
223 | }; | 234 | }; |
224 | 235 | ||
236 | static inline struct sas_discovery_event *to_sas_discovery_event(struct work_struct *work) | ||
237 | { | ||
238 | struct sas_discovery_event *ev = container_of(work, typeof(*ev), work.work); | ||
239 | |||
240 | return ev; | ||
241 | } | ||
242 | |||
225 | struct sas_discovery { | 243 | struct sas_discovery { |
226 | struct sas_discovery_event disc_work[DISC_NUM_EVENTS]; | 244 | struct sas_discovery_event disc_work[DISC_NUM_EVENTS]; |
227 | unsigned long pending; | 245 | unsigned long pending; |
@@ -244,7 +262,7 @@ struct asd_sas_port { | |||
244 | struct list_head destroy_list; | 262 | struct list_head destroy_list; |
245 | enum sas_linkrate linkrate; | 263 | enum sas_linkrate linkrate; |
246 | 264 | ||
247 | struct work_struct work; | 265 | struct sas_work work; |
248 | 266 | ||
249 | /* public: */ | 267 | /* public: */ |
250 | int id; | 268 | int id; |
@@ -270,10 +288,17 @@ struct asd_sas_port { | |||
270 | }; | 288 | }; |
271 | 289 | ||
272 | struct asd_sas_event { | 290 | struct asd_sas_event { |
273 | struct work_struct work; | 291 | struct sas_work work; |
274 | struct asd_sas_phy *phy; | 292 | struct asd_sas_phy *phy; |
275 | }; | 293 | }; |
276 | 294 | ||
295 | static inline struct asd_sas_event *to_asd_sas_event(struct work_struct *work) | ||
296 | { | ||
297 | struct asd_sas_event *ev = container_of(work, typeof(*ev), work.work); | ||
298 | |||
299 | return ev; | ||
300 | } | ||
301 | |||
277 | /* The phy pretty much is controlled by the LLDD. | 302 | /* The phy pretty much is controlled by the LLDD. |
278 | * The class only reads those fields. | 303 | * The class only reads those fields. |
279 | */ | 304 | */ |
@@ -333,10 +358,17 @@ struct scsi_core { | |||
333 | }; | 358 | }; |
334 | 359 | ||
335 | struct sas_ha_event { | 360 | struct sas_ha_event { |
336 | struct work_struct work; | 361 | struct sas_work work; |
337 | struct sas_ha_struct *ha; | 362 | struct sas_ha_struct *ha; |
338 | }; | 363 | }; |
339 | 364 | ||
365 | static inline struct sas_ha_event *to_sas_ha_event(struct work_struct *work) | ||
366 | { | ||
367 | struct sas_ha_event *ev = container_of(work, typeof(*ev), work.work); | ||
368 | |||
369 | return ev; | ||
370 | } | ||
371 | |||
340 | enum sas_ha_state { | 372 | enum sas_ha_state { |
341 | SAS_HA_REGISTERED, | 373 | SAS_HA_REGISTERED, |
342 | SAS_HA_DRAINING, | 374 | SAS_HA_DRAINING, |