diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-12-04 00:06:57 -0800 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-02-19 14:18:01 -0600 |
commit | 2a559f4ba443265b4c58925b48296f1cf81b49f9 (patch) | |
tree | 79b2c0ea7e06ce19d00ca097e5df34595afea314 /drivers/scsi/libsas/sas_init.c | |
parent | 81c757bc696284f39f07766f0c2ca67af64ce9bd (diff) |
[SCSI] libsas: sas_phy_enable via transport_sas_phy_reset
Execute the link-reset triggered by sas_phy_enable via
transport_sas_phy_reset so that it can be managed by libata.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas/sas_init.c')
-rw-r--r-- | drivers/scsi/libsas/sas_init.c | 57 |
1 files changed, 49 insertions, 8 deletions
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index a15fb861dab..53ae893e8b0 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -249,15 +249,15 @@ static int transport_sas_phy_reset(struct sas_phy *phy, int hard_reset) return ret; } -int sas_phy_enable(struct sas_phy *phy, int enable) +static int sas_phy_enable(struct sas_phy *phy, int enable) { int ret; - enum phy_func command; + enum phy_func cmd; if (enable) - command = PHY_FUNC_LINK_RESET; + cmd = PHY_FUNC_LINK_RESET; else - command = PHY_FUNC_DISABLE; + cmd = PHY_FUNC_DISABLE; if (scsi_is_sas_phy_local(phy)) { struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); @@ -266,15 +266,21 @@ int sas_phy_enable(struct sas_phy *phy, int enable) struct sas_internal *i = to_sas_internal(sas_ha->core.shost->transportt); - if (!enable) { + if (enable) + ret = transport_sas_phy_reset(phy, 0); + else { sas_phy_disconnected(asd_phy); sas_ha->notify_phy_event(asd_phy, PHYE_LOSS_OF_SIGNAL); + ret = i->dft->lldd_control_phy(asd_phy, cmd, NULL); } - ret = i->dft->lldd_control_phy(asd_phy, command, NULL); } else { struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); struct domain_device *ddev = sas_find_dev_by_rphy(rphy); - ret = sas_smp_phy_control(ddev, phy->number, command, NULL); + + if (enable) + ret = transport_sas_phy_reset(phy, 0); + else + ret = sas_smp_phy_control(ddev, phy->number, cmd, NULL); } return ret; } @@ -357,6 +363,13 @@ static void phy_reset_work(struct work_struct *work) d->reset_result = transport_sas_phy_reset(d->phy, d->hard_reset); } +static void phy_enable_work(struct work_struct *work) +{ + struct sas_phy_data *d = container_of(work, typeof(*d), enable_work); + + d->enable_result = sas_phy_enable(d->phy, d->enable); +} + static int sas_phy_setup(struct sas_phy *phy) { struct sas_phy_data *d = kzalloc(sizeof(*d), GFP_KERNEL); @@ -366,6 +379,7 @@ static int sas_phy_setup(struct sas_phy *phy) mutex_init(&d->event_lock); INIT_WORK(&d->reset_work, phy_reset_work); + INIT_WORK(&d->enable_work, phy_enable_work); d->phy = phy; phy->hostdata = d; @@ -399,8 +413,35 @@ static int queue_phy_reset(struct sas_phy *phy, int hard_reset) return rc; } +static int queue_phy_enable(struct sas_phy *phy, int enable) +{ + struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); + struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); + struct sas_phy_data *d = phy->hostdata; + int rc; + + if (!d) + return -ENOMEM; + + /* libsas workqueue coordinates ata-eh reset with discovery */ + mutex_lock(&d->event_lock); + d->enable_result = 0; + d->enable = enable; + + spin_lock_irq(&ha->state_lock); + sas_queue_work(ha, &d->enable_work); + spin_unlock_irq(&ha->state_lock); + + rc = sas_drain_work(ha); + if (rc == 0) + rc = d->enable_result; + mutex_unlock(&d->event_lock); + + return rc; +} + static struct sas_function_template sft = { - .phy_enable = sas_phy_enable, + .phy_enable = queue_phy_enable, .phy_reset = queue_phy_reset, .phy_setup = sas_phy_setup, .phy_release = sas_phy_release, |