summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r--drivers/scsi/libsas/sas_expander.c20
-rw-r--r--drivers/scsi/libsas/sas_init.c44
-rw-r--r--drivers/scsi/libsas/sas_internal.h2
-rw-r--r--drivers/scsi/libsas/sas_phy.c15
4 files changed, 64 insertions, 17 deletions
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 02e796ee027e..30b8014bcc7a 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -187,10 +187,10 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
phy->phy->identify.initiator_port_protocols = phy->attached_iproto;
phy->phy->identify.target_port_protocols = phy->attached_tproto;
phy->phy->identify.phy_identifier = phy_id;
- phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
- phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
- phy->phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
- phy->phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
+ phy->phy->minimum_linkrate_hw = dr->hmin_linkrate;
+ phy->phy->maximum_linkrate_hw = dr->hmax_linkrate;
+ phy->phy->minimum_linkrate = dr->pmin_linkrate;
+ phy->phy->maximum_linkrate = dr->pmax_linkrate;
phy->phy->negotiated_linkrate = phy->linkrate;
if (!rediscover)
@@ -404,7 +404,8 @@ out:
#define PC_RESP_SIZE 8
int sas_smp_phy_control(struct domain_device *dev, int phy_id,
- enum phy_func phy_func)
+ enum phy_func phy_func,
+ struct sas_phy_linkrates *rates)
{
u8 *pc_req;
u8 *pc_resp;
@@ -423,6 +424,10 @@ int sas_smp_phy_control(struct domain_device *dev, int phy_id,
pc_req[1] = SMP_PHY_CONTROL;
pc_req[9] = phy_id;
pc_req[10]= phy_func;
+ if (rates) {
+ pc_req[32] = rates->minimum_linkrate << 4;
+ pc_req[33] = rates->maximum_linkrate << 4;
+ }
res = smp_execute_task(dev, pc_req, PC_REQ_SIZE, pc_resp,PC_RESP_SIZE);
@@ -436,7 +441,7 @@ static void sas_ex_disable_phy(struct domain_device *dev, int phy_id)
struct expander_device *ex = &dev->ex_dev;
struct ex_phy *phy = &ex->ex_phy[phy_id];
- sas_smp_phy_control(dev, phy_id, PHY_FUNC_DISABLE);
+ sas_smp_phy_control(dev, phy_id, PHY_FUNC_DISABLE, NULL);
phy->linkrate = SAS_PHY_DISABLED;
}
@@ -731,7 +736,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
/* Phy state */
if (ex_phy->linkrate == SAS_SATA_SPINUP_HOLD) {
- if (!sas_smp_phy_control(dev, phy_id, PHY_FUNC_LINK_RESET))
+ if (!sas_smp_phy_control(dev, phy_id, PHY_FUNC_LINK_RESET, NULL))
res = sas_ex_phy_discover(dev, phy_id);
if (res)
return res;
@@ -1706,6 +1711,7 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id)
SAS_ADDR(phy->attached_sas_addr)) {
SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter\n",
SAS_ADDR(dev->sas_addr), phy_id);
+ sas_ex_phy_discover(dev, phy_id);
} else
res = sas_discover_new(dev, phy_id);
out:
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index b961664b8106..c836a237fb79 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -159,17 +159,57 @@ static int sas_phy_reset(struct sas_phy *phy, int hard_reset)
struct sas_internal *i =
to_sas_internal(sas_ha->core.shost->transportt);
- ret = i->dft->lldd_control_phy(asd_phy, reset_type);
+ ret = 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);
- ret = sas_smp_phy_control(ddev, phy->number, reset_type);
+ ret = sas_smp_phy_control(ddev, phy->number, reset_type, NULL);
}
return ret;
}
+static int sas_set_phy_speed(struct sas_phy *phy,
+ struct sas_phy_linkrates *rates)
+{
+ int ret;
+
+ if ((rates->minimum_linkrate &&
+ rates->minimum_linkrate > phy->maximum_linkrate) ||
+ (rates->maximum_linkrate &&
+ rates->maximum_linkrate < phy->minimum_linkrate))
+ return -EINVAL;
+
+ if (rates->minimum_linkrate &&
+ rates->minimum_linkrate < phy->minimum_linkrate_hw)
+ rates->minimum_linkrate = phy->minimum_linkrate_hw;
+
+ if (rates->maximum_linkrate &&
+ rates->maximum_linkrate > phy->maximum_linkrate_hw)
+ rates->maximum_linkrate = phy->maximum_linkrate_hw;
+
+ if (scsi_is_sas_phy_local(phy)) {
+ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+ struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
+ struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
+ struct sas_internal *i =
+ to_sas_internal(sas_ha->core.shost->transportt);
+
+ ret = i->dft->lldd_control_phy(asd_phy, PHY_FUNC_SET_LINK_RATE,
+ rates);
+ } 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,
+ PHY_FUNC_LINK_RESET, rates);
+
+ }
+
+ return ret;
+}
+
static struct sas_function_template sft = {
.phy_reset = sas_phy_reset,
+ .set_phy_speed = sas_set_phy_speed,
.get_linkerrors = sas_get_linkerrors,
};
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 0d69ede4b944..bffcee474921 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -70,7 +70,7 @@ int sas_notify_lldd_dev_found(struct domain_device *);
void sas_notify_lldd_dev_gone(struct domain_device *);
int sas_smp_phy_control(struct domain_device *dev, int phy_id,
- enum phy_func phy_func);
+ enum phy_func phy_func, struct sas_phy_linkrates *);
int sas_smp_get_phy_events(struct sas_phy *phy);
struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c
index 024ab00e70d2..9340cdbae4a3 100644
--- a/drivers/scsi/libsas/sas_phy.c
+++ b/drivers/scsi/libsas/sas_phy.c
@@ -67,13 +67,14 @@ static void sas_phye_oob_error(void *data)
switch (phy->error) {
case 1:
case 2:
- i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET);
+ i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET,
+ NULL);
break;
case 3:
default:
phy->error = 0;
phy->enabled = 0;
- i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE);
+ i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
break;
}
}
@@ -90,7 +91,7 @@ static void sas_phye_spinup_hold(void *data)
&phy->phy_events_pending);
phy->error = 0;
- i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD);
+ i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
}
/* ---------- Phy class registration ---------- */
@@ -144,10 +145,10 @@ int sas_register_phys(struct sas_ha_struct *sas_ha)
phy->phy->identify.target_port_protocols = phy->tproto;
phy->phy->identify.sas_address = SAS_ADDR(sas_ha->sas_addr);
phy->phy->identify.phy_identifier = i;
- phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
- phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
- phy->phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
- phy->phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
+ phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
+ phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
+ phy->phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN;
+ phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
sas_phy_add(phy->phy);