aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-12-20 04:03:48 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-19 15:11:33 -0500
commit0b3e09da1350397f3f8b6fd839ab455b0b587451 (patch)
treef822bb4dcaa52d5d568104932ee55ee136dcf039 /drivers/scsi/libsas
parentb52df4174dff7e587f6fbfb21e3c2cb57109e5cf (diff)
[SCSI] libsas: perform sas-transport resets in shost->workq context
Extend the sas transport class to allow transport users to attach extra data to a sas_phy (->hostdata). Use this area in libsas to move resets to workq context in preparation for scheduling ata device resets through libata-eh. Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r--drivers/scsi/libsas/sas_event.c2
-rw-r--r--drivers/scsi/libsas/sas_init.c59
-rw-r--r--drivers/scsi/libsas/sas_internal.h10
3 files changed, 69 insertions, 2 deletions
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index 933d757499b5..dbfaceeea0f7 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -27,7 +27,7 @@
27#include "sas_internal.h" 27#include "sas_internal.h"
28#include "sas_dump.h" 28#include "sas_dump.h"
29 29
30static void sas_queue_work(struct sas_ha_struct *ha, struct work_struct *work) 30void sas_queue_work(struct sas_ha_struct *ha, struct work_struct *work)
31{ 31{
32 if (!test_bit(SAS_HA_REGISTERED, &ha->state)) 32 if (!test_bit(SAS_HA_REGISTERED, &ha->state))
33 return; 33 return;
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index e17fe35af30c..cb65adf4ab16 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -290,9 +290,66 @@ int sas_set_phy_speed(struct sas_phy *phy,
290 return ret; 290 return ret;
291} 291}
292 292
293static void sas_phy_release(struct sas_phy *phy)
294{
295 kfree(phy->hostdata);
296 phy->hostdata = NULL;
297}
298
299static void phy_reset_work(struct work_struct *work)
300{
301 struct sas_phy_data *d = container_of(work, typeof(*d), reset_work);
302
303 d->reset_result = sas_phy_reset(d->phy, d->hard_reset);
304}
305
306static int sas_phy_setup(struct sas_phy *phy)
307{
308 struct sas_phy_data *d = kzalloc(sizeof(*d), GFP_KERNEL);
309
310 if (!d)
311 return -ENOMEM;
312
313 mutex_init(&d->event_lock);
314 INIT_WORK(&d->reset_work, phy_reset_work);
315 d->phy = phy;
316 phy->hostdata = d;
317
318 return 0;
319}
320
321static int queue_phy_reset(struct sas_phy *phy, int hard_reset)
322{
323 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
324 struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
325 struct sas_phy_data *d = phy->hostdata;
326 int rc;
327
328 if (!d)
329 return -ENOMEM;
330
331 /* libsas workqueue coordinates ata-eh reset with discovery */
332 mutex_lock(&d->event_lock);
333 d->reset_result = 0;
334 d->hard_reset = hard_reset;
335
336 spin_lock_irq(&ha->state_lock);
337 sas_queue_work(ha, &d->reset_work);
338 spin_unlock_irq(&ha->state_lock);
339
340 rc = sas_drain_work(ha);
341 if (rc == 0)
342 rc = d->reset_result;
343 mutex_unlock(&d->event_lock);
344
345 return rc;
346}
347
293static struct sas_function_template sft = { 348static struct sas_function_template sft = {
294 .phy_enable = sas_phy_enable, 349 .phy_enable = sas_phy_enable,
295 .phy_reset = sas_phy_reset, 350 .phy_reset = queue_phy_reset,
351 .phy_setup = sas_phy_setup,
352 .phy_release = sas_phy_release,
296 .set_phy_speed = sas_set_phy_speed, 353 .set_phy_speed = sas_set_phy_speed,
297 .get_linkerrors = sas_get_linkerrors, 354 .get_linkerrors = sas_get_linkerrors,
298 .smp_handler = sas_smp_handler, 355 .smp_handler = sas_smp_handler,
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 662ffcba99d2..9ba65e0c6f91 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -38,6 +38,15 @@
38#define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble) 38#define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble)
39#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0) 39#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
40 40
41struct sas_phy_data {
42 /* let reset be performed in sas_queue_work() context */
43 struct sas_phy *phy;
44 struct mutex event_lock;
45 int hard_reset;
46 int reset_result;
47 struct work_struct reset_work;
48};
49
41void sas_scsi_recover_host(struct Scsi_Host *shost); 50void sas_scsi_recover_host(struct Scsi_Host *shost);
42 51
43int sas_show_class(enum sas_class class, char *buf); 52int sas_show_class(enum sas_class class, char *buf);
@@ -66,6 +75,7 @@ void sas_porte_broadcast_rcvd(struct work_struct *work);
66void sas_porte_link_reset_err(struct work_struct *work); 75void sas_porte_link_reset_err(struct work_struct *work);
67void sas_porte_timer_event(struct work_struct *work); 76void sas_porte_timer_event(struct work_struct *work);
68void sas_porte_hard_reset(struct work_struct *work); 77void sas_porte_hard_reset(struct work_struct *work);
78void sas_queue_work(struct sas_ha_struct *ha, struct work_struct *work);
69 79
70int sas_notify_lldd_dev_found(struct domain_device *); 80int sas_notify_lldd_dev_found(struct domain_device *);
71void sas_notify_lldd_dev_gone(struct domain_device *); 81void sas_notify_lldd_dev_gone(struct domain_device *);