diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c index bb8f49269a68dfc307ca178e1effd95fd72ef3ee..e921e5321764bd8aaffe6ac6777983ddff9211fd 100644 --- a/drivers/scsi/libsas/sas_host_smp.c +++ b/drivers/scsi/libsas/sas_host_smp.c @@ -187,11 +187,14 @@ static void sas_phy_control(struct sas_ha_struct *sas_ha, u8 phy_id, struct sas_internal *i = to_sas_internal(sas_ha->core.shost->transportt); struct sas_phy_linkrates rates; + struct asd_sas_phy *asd_phy; if (phy_id >= sas_ha->num_phys) { resp_data[2] = SMP_RESP_NO_PHY; return; } + + asd_phy = sas_ha->sas_phy[phy_id]; switch (phy_op) { case PHY_FUNC_NOP: case PHY_FUNC_LINK_RESET: @@ -210,7 +213,13 @@ static void sas_phy_control(struct sas_ha_struct *sas_ha, u8 phy_id, rates.minimum_linkrate = min; rates.maximum_linkrate = max; - if (i->dft->lldd_control_phy(sas_ha->sas_phy[phy_id], phy_op, &rates)) + /* filter reset requests through libata eh */ + if (phy_op == PHY_FUNC_LINK_RESET && sas_try_ata_reset(asd_phy) == 0) { + resp_data[2] = SMP_RESP_FUNC_ACC; + return; + } + + if (i->dft->lldd_control_phy(asd_phy, phy_op, &rates)) resp_data[2] = SMP_RESP_FUNC_FAILED; else resp_data[2] = SMP_RESP_FUNC_ACC; diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index cf1b532b0e7653ce9f3fec0779b6f0b4e7f6f650..dc93e1181469f5d23810cc8141b8c1c8fbf678c1 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -196,6 +196,27 @@ static int sas_get_linkerrors(struct sas_phy *phy) return sas_smp_get_phy_events(phy); } +int sas_try_ata_reset(struct asd_sas_phy *asd_phy) +{ + struct domain_device *dev = NULL; + + /* try to route user requested link resets through libata */ + if (asd_phy->port) + dev = asd_phy->port->port_dev; + + /* validate that dev has been probed */ + if (dev) + dev = sas_find_dev_by_rphy(dev->rphy); + + if (dev && dev_is_sata(dev)) { + sas_ata_schedule_reset(dev); + sas_ata_wait_eh(dev); + return 0; + } + + return -ENODEV; +} + /** * transport_sas_phy_reset - reset a phy and permit libata to manage the link * @@ -204,7 +225,6 @@ static int sas_get_linkerrors(struct sas_phy *phy) */ static int transport_sas_phy_reset(struct sas_phy *phy, int hard_reset) { - int ret; enum phy_func reset_type; if (hard_reset) @@ -218,21 +238,10 @@ static int transport_sas_phy_reset(struct sas_phy *phy, int hard_reset) struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number]; struct sas_internal *i = to_sas_internal(sas_ha->core.shost->transportt); - struct domain_device *dev = NULL; - - if (asd_phy->port) - dev = asd_phy->port->port_dev; - - /* validate that dev has been probed */ - if (dev) - dev = sas_find_dev_by_rphy(dev->rphy); - if (dev && dev_is_sata(dev) && !hard_reset) { - sas_ata_schedule_reset(dev); - sas_ata_wait_eh(dev); - ret = 0; - } else - ret = i->dft->lldd_control_phy(asd_phy, reset_type, NULL); + if (!hard_reset && sas_try_ata_reset(asd_phy) == 0) + return 0; + return i->dft->lldd_control_phy(asd_phy, reset_type, NULL); } else { struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); struct domain_device *ddev = sas_find_dev_by_rphy(rphy); @@ -241,12 +250,10 @@ static int transport_sas_phy_reset(struct sas_phy *phy, int hard_reset) if (ata_dev && !hard_reset) { sas_ata_schedule_reset(ata_dev); sas_ata_wait_eh(ata_dev); - ret = 0; + return 0; } else - ret = sas_smp_phy_control(ddev, phy->number, reset_type, NULL); + return sas_smp_phy_control(ddev, phy->number, reset_type, NULL); } - - return ret; } static int sas_phy_enable(struct sas_phy *phy, int enable) diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index c8febc71c40dae217801d7fe830f74c9b6165753..4157f6e1eda29f148e547da5936d1cde682763cc 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -92,6 +92,7 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id); int sas_get_phy_attached_sas_addr(struct domain_device *dev, int phy_id, u8 *attached_sas_addr); +int sas_try_ata_reset(struct asd_sas_phy *phy); void sas_hae_reset(struct work_struct *work); void sas_free_device(struct kref *kref);