aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/ata/libata-eh.c1
-rw-r--r--drivers/ata/libata.h1
-rw-r--r--drivers/scsi/libsas/sas_ata.c11
-rw-r--r--drivers/scsi/libsas/sas_expander.c2
-rw-r--r--drivers/scsi/libsas/sas_init.c56
-rw-r--r--drivers/scsi/libsas/sas_internal.h1
-rw-r--r--include/linux/libata.h1
-rw-r--r--include/scsi/sas_ata.h4
8 files changed, 74 insertions, 3 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index a9b282038000..c61316e9d2f7 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -863,6 +863,7 @@ void ata_port_wait_eh(struct ata_port *ap)
863 goto retry; 863 goto retry;
864 } 864 }
865} 865}
866EXPORT_SYMBOL_GPL(ata_port_wait_eh);
866 867
867static int ata_eh_nr_in_flight(struct ata_port *ap) 868static int ata_eh_nr_in_flight(struct ata_port *ap)
868{ 869{
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 814486d35c44..1fab235ee516 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -151,7 +151,6 @@ extern void ata_eh_acquire(struct ata_port *ap);
151extern void ata_eh_release(struct ata_port *ap); 151extern void ata_eh_release(struct ata_port *ap);
152extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); 152extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
153extern void ata_scsi_error(struct Scsi_Host *host); 153extern void ata_scsi_error(struct Scsi_Host *host);
154extern void ata_port_wait_eh(struct ata_port *ap);
155extern void ata_eh_fastdrain_timerfn(unsigned long arg); 154extern void ata_eh_fastdrain_timerfn(unsigned long arg);
156extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); 155extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
157extern void ata_dev_disable(struct ata_device *dev); 156extern void ata_dev_disable(struct ata_device *dev);
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 48cadf88c399..03930a04a679 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -698,3 +698,14 @@ void sas_ata_schedule_reset(struct domain_device *dev)
698 ata_port_schedule_eh(ap); 698 ata_port_schedule_eh(ap);
699 spin_unlock_irqrestore(ap->lock, flags); 699 spin_unlock_irqrestore(ap->lock, flags);
700} 700}
701
702void sas_ata_wait_eh(struct domain_device *dev)
703{
704 struct ata_port *ap;
705
706 if (!dev_is_sata(dev))
707 return;
708
709 ap = dev->sata_dev.ap;
710 ata_port_wait_eh(ap);
711}
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index f4894b0f537b..d3c1a29b8a2a 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -228,7 +228,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
228} 228}
229 229
230/* check if we have an existing attached ata device on this expander phy */ 230/* check if we have an existing attached ata device on this expander phy */
231static struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id) 231struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id)
232{ 232{
233 struct ex_phy *ex_phy = &ex_dev->ex_dev.ex_phy[phy_id]; 233 struct ex_phy *ex_phy = &ex_dev->ex_dev.ex_phy[phy_id];
234 struct domain_device *dev; 234 struct domain_device *dev;
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index cb65adf4ab16..a15fb861daba 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -28,6 +28,7 @@
28#include <linux/init.h> 28#include <linux/init.h>
29#include <linux/device.h> 29#include <linux/device.h>
30#include <linux/spinlock.h> 30#include <linux/spinlock.h>
31#include <scsi/sas_ata.h>
31#include <scsi/scsi_host.h> 32#include <scsi/scsi_host.h>
32#include <scsi/scsi_device.h> 33#include <scsi/scsi_device.h>
33#include <scsi/scsi_transport.h> 34#include <scsi/scsi_transport.h>
@@ -195,6 +196,59 @@ static int sas_get_linkerrors(struct sas_phy *phy)
195 return sas_smp_get_phy_events(phy); 196 return sas_smp_get_phy_events(phy);
196} 197}
197 198
199/**
200 * transport_sas_phy_reset - reset a phy and permit libata to manage the link
201 *
202 * phy reset request via sysfs in host workqueue context so we know we
203 * can block on eh and safely traverse the domain_device topology
204 */
205static int transport_sas_phy_reset(struct sas_phy *phy, int hard_reset)
206{
207 int ret;
208 enum phy_func reset_type;
209
210 if (hard_reset)
211 reset_type = PHY_FUNC_HARD_RESET;
212 else
213 reset_type = PHY_FUNC_LINK_RESET;
214
215 if (scsi_is_sas_phy_local(phy)) {
216 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
217 struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
218 struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
219 struct sas_internal *i =
220 to_sas_internal(sas_ha->core.shost->transportt);
221 struct domain_device *dev = NULL;
222
223 if (asd_phy->port)
224 dev = asd_phy->port->port_dev;
225
226 /* validate that dev has been probed */
227 if (dev)
228 dev = sas_find_dev_by_rphy(dev->rphy);
229
230 if (dev && dev_is_sata(dev) && !hard_reset) {
231 sas_ata_schedule_reset(dev);
232 sas_ata_wait_eh(dev);
233 ret = 0;
234 } else
235 ret = i->dft->lldd_control_phy(asd_phy, reset_type, NULL);
236 } else {
237 struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
238 struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
239 struct domain_device *ata_dev = sas_ex_to_ata(ddev, phy->number);
240
241 if (ata_dev && !hard_reset) {
242 sas_ata_schedule_reset(ata_dev);
243 sas_ata_wait_eh(ata_dev);
244 ret = 0;
245 } else
246 ret = sas_smp_phy_control(ddev, phy->number, reset_type, NULL);
247 }
248
249 return ret;
250}
251
198int sas_phy_enable(struct sas_phy *phy, int enable) 252int sas_phy_enable(struct sas_phy *phy, int enable)
199{ 253{
200 int ret; 254 int ret;
@@ -300,7 +354,7 @@ static void phy_reset_work(struct work_struct *work)
300{ 354{
301 struct sas_phy_data *d = container_of(work, typeof(*d), reset_work); 355 struct sas_phy_data *d = container_of(work, typeof(*d), reset_work);
302 356
303 d->reset_result = sas_phy_reset(d->phy, d->hard_reset); 357 d->reset_result = transport_sas_phy_reset(d->phy, d->hard_reset);
304} 358}
305 359
306static int sas_phy_setup(struct sas_phy *phy) 360static int sas_phy_setup(struct sas_phy *phy)
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 9ba65e0c6f91..ae9698d9d857 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -85,6 +85,7 @@ int sas_smp_phy_control(struct domain_device *dev, int phy_id,
85int sas_smp_get_phy_events(struct sas_phy *phy); 85int sas_smp_get_phy_events(struct sas_phy *phy);
86 86
87struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); 87struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
88struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
88 89
89void sas_hae_reset(struct work_struct *work); 90void sas_hae_reset(struct work_struct *work);
90 91
diff --git a/include/linux/libata.h b/include/linux/libata.h
index cafc09a64fe4..aa4270477563 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -1147,6 +1147,7 @@ static inline int ata_acpi_cbl_80wire(struct ata_port *ap,
1147 * EH - drivers/ata/libata-eh.c 1147 * EH - drivers/ata/libata-eh.c
1148 */ 1148 */
1149extern void ata_port_schedule_eh(struct ata_port *ap); 1149extern void ata_port_schedule_eh(struct ata_port *ap);
1150extern void ata_port_wait_eh(struct ata_port *ap);
1150extern int ata_link_abort(struct ata_link *link); 1151extern int ata_link_abort(struct ata_link *link);
1151extern int ata_port_abort(struct ata_port *ap); 1152extern int ata_port_abort(struct ata_port *ap);
1152extern int ata_port_freeze(struct ata_port *ap); 1153extern int ata_port_freeze(struct ata_port *ap);
diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h
index c0bcd30eec56..da3f37727387 100644
--- a/include/scsi/sas_ata.h
+++ b/include/scsi/sas_ata.h
@@ -45,6 +45,7 @@ int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
45 struct list_head *done_q); 45 struct list_head *done_q);
46void sas_probe_sata(struct work_struct *work); 46void sas_probe_sata(struct work_struct *work);
47void sas_ata_schedule_reset(struct domain_device *dev); 47void sas_ata_schedule_reset(struct domain_device *dev);
48void sas_ata_wait_eh(struct domain_device *dev);
48#else 49#else
49 50
50 51
@@ -79,6 +80,9 @@ static inline void sas_ata_schedule_reset(struct domain_device *dev)
79{ 80{
80} 81}
81 82
83static inline void sas_ata_wait_eh(struct domain_device *dev)
84{
85}
82#endif 86#endif
83 87
84#endif /* _SAS_ATA_H_ */ 88#endif /* _SAS_ATA_H_ */