diff options
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r-- | drivers/scsi/libsas/sas_expander.c | 20 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_init.c | 44 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_internal.h | 2 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_phy.c | 15 |
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, | |||
187 | phy->phy->identify.initiator_port_protocols = phy->attached_iproto; | 187 | phy->phy->identify.initiator_port_protocols = phy->attached_iproto; |
188 | phy->phy->identify.target_port_protocols = phy->attached_tproto; | 188 | phy->phy->identify.target_port_protocols = phy->attached_tproto; |
189 | phy->phy->identify.phy_identifier = phy_id; | 189 | phy->phy->identify.phy_identifier = phy_id; |
190 | phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; | 190 | phy->phy->minimum_linkrate_hw = dr->hmin_linkrate; |
191 | phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; | 191 | phy->phy->maximum_linkrate_hw = dr->hmax_linkrate; |
192 | phy->phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; | 192 | phy->phy->minimum_linkrate = dr->pmin_linkrate; |
193 | phy->phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS; | 193 | phy->phy->maximum_linkrate = dr->pmax_linkrate; |
194 | phy->phy->negotiated_linkrate = phy->linkrate; | 194 | phy->phy->negotiated_linkrate = phy->linkrate; |
195 | 195 | ||
196 | if (!rediscover) | 196 | if (!rediscover) |
@@ -404,7 +404,8 @@ out: | |||
404 | #define PC_RESP_SIZE 8 | 404 | #define PC_RESP_SIZE 8 |
405 | 405 | ||
406 | int sas_smp_phy_control(struct domain_device *dev, int phy_id, | 406 | int sas_smp_phy_control(struct domain_device *dev, int phy_id, |
407 | enum phy_func phy_func) | 407 | enum phy_func phy_func, |
408 | struct sas_phy_linkrates *rates) | ||
408 | { | 409 | { |
409 | u8 *pc_req; | 410 | u8 *pc_req; |
410 | u8 *pc_resp; | 411 | u8 *pc_resp; |
@@ -423,6 +424,10 @@ int sas_smp_phy_control(struct domain_device *dev, int phy_id, | |||
423 | pc_req[1] = SMP_PHY_CONTROL; | 424 | pc_req[1] = SMP_PHY_CONTROL; |
424 | pc_req[9] = phy_id; | 425 | pc_req[9] = phy_id; |
425 | pc_req[10]= phy_func; | 426 | pc_req[10]= phy_func; |
427 | if (rates) { | ||
428 | pc_req[32] = rates->minimum_linkrate << 4; | ||
429 | pc_req[33] = rates->maximum_linkrate << 4; | ||
430 | } | ||
426 | 431 | ||
427 | res = smp_execute_task(dev, pc_req, PC_REQ_SIZE, pc_resp,PC_RESP_SIZE); | 432 | res = smp_execute_task(dev, pc_req, PC_REQ_SIZE, pc_resp,PC_RESP_SIZE); |
428 | 433 | ||
@@ -436,7 +441,7 @@ static void sas_ex_disable_phy(struct domain_device *dev, int phy_id) | |||
436 | struct expander_device *ex = &dev->ex_dev; | 441 | struct expander_device *ex = &dev->ex_dev; |
437 | struct ex_phy *phy = &ex->ex_phy[phy_id]; | 442 | struct ex_phy *phy = &ex->ex_phy[phy_id]; |
438 | 443 | ||
439 | sas_smp_phy_control(dev, phy_id, PHY_FUNC_DISABLE); | 444 | sas_smp_phy_control(dev, phy_id, PHY_FUNC_DISABLE, NULL); |
440 | phy->linkrate = SAS_PHY_DISABLED; | 445 | phy->linkrate = SAS_PHY_DISABLED; |
441 | } | 446 | } |
442 | 447 | ||
@@ -731,7 +736,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) | |||
731 | 736 | ||
732 | /* Phy state */ | 737 | /* Phy state */ |
733 | if (ex_phy->linkrate == SAS_SATA_SPINUP_HOLD) { | 738 | if (ex_phy->linkrate == SAS_SATA_SPINUP_HOLD) { |
734 | if (!sas_smp_phy_control(dev, phy_id, PHY_FUNC_LINK_RESET)) | 739 | if (!sas_smp_phy_control(dev, phy_id, PHY_FUNC_LINK_RESET, NULL)) |
735 | res = sas_ex_phy_discover(dev, phy_id); | 740 | res = sas_ex_phy_discover(dev, phy_id); |
736 | if (res) | 741 | if (res) |
737 | return res; | 742 | return res; |
@@ -1706,6 +1711,7 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id) | |||
1706 | SAS_ADDR(phy->attached_sas_addr)) { | 1711 | SAS_ADDR(phy->attached_sas_addr)) { |
1707 | SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter\n", | 1712 | SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter\n", |
1708 | SAS_ADDR(dev->sas_addr), phy_id); | 1713 | SAS_ADDR(dev->sas_addr), phy_id); |
1714 | sas_ex_phy_discover(dev, phy_id); | ||
1709 | } else | 1715 | } else |
1710 | res = sas_discover_new(dev, phy_id); | 1716 | res = sas_discover_new(dev, phy_id); |
1711 | out: | 1717 | 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) | |||
159 | struct sas_internal *i = | 159 | struct sas_internal *i = |
160 | to_sas_internal(sas_ha->core.shost->transportt); | 160 | to_sas_internal(sas_ha->core.shost->transportt); |
161 | 161 | ||
162 | ret = i->dft->lldd_control_phy(asd_phy, reset_type); | 162 | ret = i->dft->lldd_control_phy(asd_phy, reset_type, NULL); |
163 | } else { | 163 | } else { |
164 | struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); | 164 | struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); |
165 | struct domain_device *ddev = sas_find_dev_by_rphy(rphy); | 165 | struct domain_device *ddev = sas_find_dev_by_rphy(rphy); |
166 | ret = sas_smp_phy_control(ddev, phy->number, reset_type); | 166 | ret = sas_smp_phy_control(ddev, phy->number, reset_type, NULL); |
167 | } | 167 | } |
168 | return ret; | 168 | return ret; |
169 | } | 169 | } |
170 | 170 | ||
171 | static int sas_set_phy_speed(struct sas_phy *phy, | ||
172 | struct sas_phy_linkrates *rates) | ||
173 | { | ||
174 | int ret; | ||
175 | |||
176 | if ((rates->minimum_linkrate && | ||
177 | rates->minimum_linkrate > phy->maximum_linkrate) || | ||
178 | (rates->maximum_linkrate && | ||
179 | rates->maximum_linkrate < phy->minimum_linkrate)) | ||
180 | return -EINVAL; | ||
181 | |||
182 | if (rates->minimum_linkrate && | ||
183 | rates->minimum_linkrate < phy->minimum_linkrate_hw) | ||
184 | rates->minimum_linkrate = phy->minimum_linkrate_hw; | ||
185 | |||
186 | if (rates->maximum_linkrate && | ||
187 | rates->maximum_linkrate > phy->maximum_linkrate_hw) | ||
188 | rates->maximum_linkrate = phy->maximum_linkrate_hw; | ||
189 | |||
190 | if (scsi_is_sas_phy_local(phy)) { | ||
191 | struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); | ||
192 | struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); | ||
193 | struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number]; | ||
194 | struct sas_internal *i = | ||
195 | to_sas_internal(sas_ha->core.shost->transportt); | ||
196 | |||
197 | ret = i->dft->lldd_control_phy(asd_phy, PHY_FUNC_SET_LINK_RATE, | ||
198 | rates); | ||
199 | } else { | ||
200 | struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); | ||
201 | struct domain_device *ddev = sas_find_dev_by_rphy(rphy); | ||
202 | ret = sas_smp_phy_control(ddev, phy->number, | ||
203 | PHY_FUNC_LINK_RESET, rates); | ||
204 | |||
205 | } | ||
206 | |||
207 | return ret; | ||
208 | } | ||
209 | |||
171 | static struct sas_function_template sft = { | 210 | static struct sas_function_template sft = { |
172 | .phy_reset = sas_phy_reset, | 211 | .phy_reset = sas_phy_reset, |
212 | .set_phy_speed = sas_set_phy_speed, | ||
173 | .get_linkerrors = sas_get_linkerrors, | 213 | .get_linkerrors = sas_get_linkerrors, |
174 | }; | 214 | }; |
175 | 215 | ||
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 *); | |||
70 | void sas_notify_lldd_dev_gone(struct domain_device *); | 70 | void sas_notify_lldd_dev_gone(struct domain_device *); |
71 | 71 | ||
72 | int sas_smp_phy_control(struct domain_device *dev, int phy_id, | 72 | int sas_smp_phy_control(struct domain_device *dev, int phy_id, |
73 | enum phy_func phy_func); | 73 | enum phy_func phy_func, struct sas_phy_linkrates *); |
74 | int sas_smp_get_phy_events(struct sas_phy *phy); | 74 | int sas_smp_get_phy_events(struct sas_phy *phy); |
75 | 75 | ||
76 | struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); | 76 | 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) | |||
67 | switch (phy->error) { | 67 | switch (phy->error) { |
68 | case 1: | 68 | case 1: |
69 | case 2: | 69 | case 2: |
70 | i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET); | 70 | i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET, |
71 | NULL); | ||
71 | break; | 72 | break; |
72 | case 3: | 73 | case 3: |
73 | default: | 74 | default: |
74 | phy->error = 0; | 75 | phy->error = 0; |
75 | phy->enabled = 0; | 76 | phy->enabled = 0; |
76 | i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE); | 77 | i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL); |
77 | break; | 78 | break; |
78 | } | 79 | } |
79 | } | 80 | } |
@@ -90,7 +91,7 @@ static void sas_phye_spinup_hold(void *data) | |||
90 | &phy->phy_events_pending); | 91 | &phy->phy_events_pending); |
91 | 92 | ||
92 | phy->error = 0; | 93 | phy->error = 0; |
93 | i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD); | 94 | i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL); |
94 | } | 95 | } |
95 | 96 | ||
96 | /* ---------- Phy class registration ---------- */ | 97 | /* ---------- Phy class registration ---------- */ |
@@ -144,10 +145,10 @@ int sas_register_phys(struct sas_ha_struct *sas_ha) | |||
144 | phy->phy->identify.target_port_protocols = phy->tproto; | 145 | phy->phy->identify.target_port_protocols = phy->tproto; |
145 | phy->phy->identify.sas_address = SAS_ADDR(sas_ha->sas_addr); | 146 | phy->phy->identify.sas_address = SAS_ADDR(sas_ha->sas_addr); |
146 | phy->phy->identify.phy_identifier = i; | 147 | phy->phy->identify.phy_identifier = i; |
147 | phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; | 148 | phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; |
148 | phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; | 149 | phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; |
149 | phy->phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; | 150 | phy->phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN; |
150 | phy->phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS; | 151 | phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN; |
151 | phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; | 152 | phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; |
152 | 153 | ||
153 | sas_phy_add(phy->phy); | 154 | sas_phy_add(phy->phy); |