aboutsummaryrefslogtreecommitdiffstats
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
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>
-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
-rw-r--r--drivers/scsi/scsi_transport_sas.c18
-rw-r--r--include/scsi/scsi_transport_sas.h5
5 files changed, 90 insertions, 4 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 *);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 9421bae8af1a..ab3bd0b5ffd9 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -652,9 +652,21 @@ sas_phy_linkerror_attr(running_disparity_error_count);
652sas_phy_linkerror_attr(loss_of_dword_sync_count); 652sas_phy_linkerror_attr(loss_of_dword_sync_count);
653sas_phy_linkerror_attr(phy_reset_problem_count); 653sas_phy_linkerror_attr(phy_reset_problem_count);
654 654
655static int sas_phy_setup(struct transport_container *tc, struct device *dev,
656 struct device *cdev)
657{
658 struct sas_phy *phy = dev_to_phy(dev);
659 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
660 struct sas_internal *i = to_sas_internal(shost->transportt);
661
662 if (i->f->phy_setup)
663 i->f->phy_setup(phy);
664
665 return 0;
666}
655 667
656static DECLARE_TRANSPORT_CLASS(sas_phy_class, 668static DECLARE_TRANSPORT_CLASS(sas_phy_class,
657 "sas_phy", NULL, NULL, NULL); 669 "sas_phy", sas_phy_setup, NULL, NULL);
658 670
659static int sas_phy_match(struct attribute_container *cont, struct device *dev) 671static int sas_phy_match(struct attribute_container *cont, struct device *dev)
660{ 672{
@@ -678,7 +690,11 @@ static int sas_phy_match(struct attribute_container *cont, struct device *dev)
678static void sas_phy_release(struct device *dev) 690static void sas_phy_release(struct device *dev)
679{ 691{
680 struct sas_phy *phy = dev_to_phy(dev); 692 struct sas_phy *phy = dev_to_phy(dev);
693 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
694 struct sas_internal *i = to_sas_internal(shost->transportt);
681 695
696 if (i->f->phy_release)
697 i->f->phy_release(phy);
682 put_device(dev->parent); 698 put_device(dev->parent);
683 kfree(phy); 699 kfree(phy);
684} 700}
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
index 6d14daac7589..42817facaeda 100644
--- a/include/scsi/scsi_transport_sas.h
+++ b/include/scsi/scsi_transport_sas.h
@@ -75,7 +75,8 @@ struct sas_phy {
75 /* for the list of phys belonging to a port */ 75 /* for the list of phys belonging to a port */
76 struct list_head port_siblings; 76 struct list_head port_siblings;
77 77
78 struct work_struct reset_work; 78 /* available to the lldd */
79 void *hostdata;
79}; 80};
80 81
81#define dev_to_phy(d) \ 82#define dev_to_phy(d) \
@@ -169,6 +170,8 @@ struct sas_function_template {
169 int (*get_bay_identifier)(struct sas_rphy *); 170 int (*get_bay_identifier)(struct sas_rphy *);
170 int (*phy_reset)(struct sas_phy *, int); 171 int (*phy_reset)(struct sas_phy *, int);
171 int (*phy_enable)(struct sas_phy *, int); 172 int (*phy_enable)(struct sas_phy *, int);
173 int (*phy_setup)(struct sas_phy *);
174 void (*phy_release)(struct sas_phy *);
172 int (*set_phy_speed)(struct sas_phy *, struct sas_phy_linkrates *); 175 int (*set_phy_speed)(struct sas_phy *, struct sas_phy_linkrates *);
173 int (*smp_handler)(struct Scsi_Host *, struct sas_rphy *, struct request *); 176 int (*smp_handler)(struct Scsi_Host *, struct sas_rphy *, struct request *);
174}; 177};