aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/aic94xx/aic94xx.h2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c30
-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
-rw-r--r--include/scsi/libsas.h2
-rw-r--r--include/scsi/sas.h1
8 files changed, 95 insertions, 21 deletions
diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h
index cb7caf1c9ce1..1bd5b4ecf3d5 100644
--- a/drivers/scsi/aic94xx/aic94xx.h
+++ b/drivers/scsi/aic94xx/aic94xx.h
@@ -109,6 +109,6 @@ int asd_clear_nexus_port(struct asd_sas_port *port);
109int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha); 109int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha);
110 110
111/* ---------- Phy Management ---------- */ 111/* ---------- Phy Management ---------- */
112int asd_control_phy(struct asd_sas_phy *phy, enum phy_func func); 112int asd_control_phy(struct asd_sas_phy *phy, enum phy_func func, void *arg);
113 113
114#endif 114#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
index ef8ca08b545f..7ee49b51b724 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -52,6 +52,8 @@
52 52
53static inline void get_lrate_mode(struct asd_phy *phy, u8 oob_mode) 53static inline void get_lrate_mode(struct asd_phy *phy, u8 oob_mode)
54{ 54{
55 struct sas_phy *sas_phy = phy->sas_phy.phy;
56
55 switch (oob_mode & 7) { 57 switch (oob_mode & 7) {
56 case PHY_SPEED_60: 58 case PHY_SPEED_60:
57 /* FIXME: sas transport class doesn't have this */ 59 /* FIXME: sas transport class doesn't have this */
@@ -67,6 +69,12 @@ static inline void get_lrate_mode(struct asd_phy *phy, u8 oob_mode)
67 phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS; 69 phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
68 break; 70 break;
69 } 71 }
72 sas_phy->negotiated_linkrate = phy->sas_phy.linkrate;
73 sas_phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
74 sas_phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
75 sas_phy->maximum_linkrate = phy->phy_desc->max_sas_lrate;
76 sas_phy->minimum_linkrate = phy->phy_desc->min_sas_lrate;
77
70 if (oob_mode & SAS_MODE) 78 if (oob_mode & SAS_MODE)
71 phy->sas_phy.oob_mode = SAS_OOB_MODE; 79 phy->sas_phy.oob_mode = SAS_OOB_MODE;
72 else if (oob_mode & SATA_MODE) 80 else if (oob_mode & SATA_MODE)
@@ -710,14 +718,32 @@ static const int phy_func_table[] = {
710 [PHY_FUNC_RELEASE_SPINUP_HOLD] = RELEASE_SPINUP_HOLD, 718 [PHY_FUNC_RELEASE_SPINUP_HOLD] = RELEASE_SPINUP_HOLD,
711}; 719};
712 720
713int asd_control_phy(struct asd_sas_phy *phy, enum phy_func func) 721int asd_control_phy(struct asd_sas_phy *phy, enum phy_func func, void *arg)
714{ 722{
715 struct asd_ha_struct *asd_ha = phy->ha->lldd_ha; 723 struct asd_ha_struct *asd_ha = phy->ha->lldd_ha;
724 struct asd_phy_desc *pd = asd_ha->phys[phy->id].phy_desc;
716 struct asd_ascb *ascb; 725 struct asd_ascb *ascb;
726 struct sas_phy_linkrates *rates;
717 int res = 1; 727 int res = 1;
718 728
719 if (func == PHY_FUNC_CLEAR_ERROR_LOG) 729 switch (func) {
730 case PHY_FUNC_CLEAR_ERROR_LOG:
720 return -ENOSYS; 731 return -ENOSYS;
732 case PHY_FUNC_SET_LINK_RATE:
733 rates = arg;
734 if (rates->minimum_linkrate) {
735 pd->min_sas_lrate = rates->minimum_linkrate;
736 pd->min_sata_lrate = rates->minimum_linkrate;
737 }
738 if (rates->maximum_linkrate) {
739 pd->max_sas_lrate = rates->maximum_linkrate;
740 pd->max_sata_lrate = rates->maximum_linkrate;
741 }
742 func = PHY_FUNC_LINK_RESET;
743 break;
744 default:
745 break;
746 }
721 747
722 ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); 748 ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
723 if (!ascb) 749 if (!ascb)
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
406int sas_smp_phy_control(struct domain_device *dev, int phy_id, 406int 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);
1711out: 1717out:
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
171static 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
171static struct sas_function_template sft = { 210static 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 *);
70void sas_notify_lldd_dev_gone(struct domain_device *); 70void sas_notify_lldd_dev_gone(struct domain_device *);
71 71
72int sas_smp_phy_control(struct domain_device *dev, int phy_id, 72int 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 *);
74int sas_smp_get_phy_events(struct sas_phy *phy); 74int sas_smp_get_phy_events(struct sas_phy *phy);
75 75
76struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); 76struct 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);
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 8d91313dd888..8e39982fc3db 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -586,7 +586,7 @@ struct sas_domain_function_template {
586 int (*lldd_clear_nexus_ha)(struct sas_ha_struct *); 586 int (*lldd_clear_nexus_ha)(struct sas_ha_struct *);
587 587
588 /* Phy management */ 588 /* Phy management */
589 int (*lldd_control_phy)(struct asd_sas_phy *, enum phy_func); 589 int (*lldd_control_phy)(struct asd_sas_phy *, enum phy_func, void *);
590}; 590};
591 591
592extern int sas_register_ha(struct sas_ha_struct *); 592extern int sas_register_ha(struct sas_ha_struct *);
diff --git a/include/scsi/sas.h b/include/scsi/sas.h
index 9c8a5b91ae64..2f4b6afa34fc 100644
--- a/include/scsi/sas.h
+++ b/include/scsi/sas.h
@@ -121,6 +121,7 @@ enum phy_func {
121 PHY_FUNC_CLEAR_AFFIL, 121 PHY_FUNC_CLEAR_AFFIL,
122 PHY_FUNC_TX_SATA_PS_SIGNAL, 122 PHY_FUNC_TX_SATA_PS_SIGNAL,
123 PHY_FUNC_RELEASE_SPINUP_HOLD = 0x10, /* LOCAL PORT ONLY! */ 123 PHY_FUNC_RELEASE_SPINUP_HOLD = 0x10, /* LOCAL PORT ONLY! */
124 PHY_FUNC_SET_LINK_RATE,
124}; 125};
125 126
126/* SAS LLDD would need to report only _very_few_ of those, like BROADCAST. 127/* SAS LLDD would need to report only _very_few_ of those, like BROADCAST.