[SCSI] libsas: sas_phy_enable via transport_sas_phy_reset
authorDan Williams <dan.j.williams@intel.com>
Sun, 4 Dec 2011 08:06:57 +0000 (00:06 -0800)
committerJames Bottomley <JBottomley@Parallels.com>
Sun, 19 Feb 2012 20:18:01 +0000 (14:18 -0600)
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>
drivers/scsi/libsas/sas_init.c
drivers/scsi/libsas/sas_internal.h
drivers/scsi/libsas/sas_scsi_host.c
include/scsi/libsas.h

index a15fb861daba4ac1975add39c9891739761fb938..53ae893e8b0b0860199a89550a8dae8891e70683 100644 (file)
@@ -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,
index ae9698d9d857906112a2781a0c66d0de0c034ab7..9e960b2d535ad6140162feb2d4489bcbc2fb23ce 100644 (file)
@@ -45,6 +45,9 @@ struct sas_phy_data {
        int hard_reset;
        int reset_result;
        struct work_struct reset_work;
+       int enable;
+       int enable_result;
+       struct work_struct enable_work;
 };
 
 void sas_scsi_recover_host(struct Scsi_Host *shost);
index af71a6d0edae358258234218b2e82d8f1d52426a..5cc44fddfe9586e55b99632dc9b6ecdd3ab9c5e8 100644 (file)
@@ -1077,7 +1077,6 @@ EXPORT_SYMBOL_GPL(sas_change_queue_type);
 EXPORT_SYMBOL_GPL(sas_bios_param);
 EXPORT_SYMBOL_GPL(sas_task_abort);
 EXPORT_SYMBOL_GPL(sas_phy_reset);
-EXPORT_SYMBOL_GPL(sas_phy_enable);
 EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler);
 EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler);
 EXPORT_SYMBOL_GPL(sas_slave_alloc);
index 6b80310e08af9c4070fec18c0221dd3e142d92fe..f388ba53612871cd8a7fb52239f962157c19e02c 100644 (file)
@@ -634,7 +634,6 @@ extern int sas_unregister_ha(struct sas_ha_struct *);
 
 int sas_set_phy_speed(struct sas_phy *phy,
                      struct sas_phy_linkrates *rates);
-int sas_phy_enable(struct sas_phy *phy, int enabled);
 int sas_phy_reset(struct sas_phy *phy, int hard_reset);
 int sas_queue_up(struct sas_task *task);
 extern int sas_queuecommand(struct Scsi_Host * ,struct scsi_cmnd *);