aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2012-01-11 16:13:44 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-29 16:25:32 -0500
commitab5266335ba1a43461443f9823276a2b44dd1ba7 (patch)
tree5ab3c7e21f27e0ecacb01117764d911c349b51c9 /drivers/scsi/libsas
parentd230ce691c7712c4f56ba3378d6d2f44628a49f1 (diff)
[SCSI] libsas: route local link resets through ata-eh
Similar to the conversion of the transport-class reset we want bsg initiated resets to be managed by libata. Reported-by: Jacek Danecki <jacek.danecki@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r--drivers/scsi/libsas/sas_host_smp.c11
-rw-r--r--drivers/scsi/libsas/sas_init.c45
-rw-r--r--drivers/scsi/libsas/sas_internal.h1
3 files changed, 37 insertions, 20 deletions
diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c
index bb8f49269a68..e921e5321764 100644
--- a/drivers/scsi/libsas/sas_host_smp.c
+++ b/drivers/scsi/libsas/sas_host_smp.c
@@ -187,11 +187,14 @@ static void sas_phy_control(struct sas_ha_struct *sas_ha, u8 phy_id,
187 struct sas_internal *i = 187 struct sas_internal *i =
188 to_sas_internal(sas_ha->core.shost->transportt); 188 to_sas_internal(sas_ha->core.shost->transportt);
189 struct sas_phy_linkrates rates; 189 struct sas_phy_linkrates rates;
190 struct asd_sas_phy *asd_phy;
190 191
191 if (phy_id >= sas_ha->num_phys) { 192 if (phy_id >= sas_ha->num_phys) {
192 resp_data[2] = SMP_RESP_NO_PHY; 193 resp_data[2] = SMP_RESP_NO_PHY;
193 return; 194 return;
194 } 195 }
196
197 asd_phy = sas_ha->sas_phy[phy_id];
195 switch (phy_op) { 198 switch (phy_op) {
196 case PHY_FUNC_NOP: 199 case PHY_FUNC_NOP:
197 case PHY_FUNC_LINK_RESET: 200 case PHY_FUNC_LINK_RESET:
@@ -210,7 +213,13 @@ static void sas_phy_control(struct sas_ha_struct *sas_ha, u8 phy_id,
210 rates.minimum_linkrate = min; 213 rates.minimum_linkrate = min;
211 rates.maximum_linkrate = max; 214 rates.maximum_linkrate = max;
212 215
213 if (i->dft->lldd_control_phy(sas_ha->sas_phy[phy_id], phy_op, &rates)) 216 /* filter reset requests through libata eh */
217 if (phy_op == PHY_FUNC_LINK_RESET && sas_try_ata_reset(asd_phy) == 0) {
218 resp_data[2] = SMP_RESP_FUNC_ACC;
219 return;
220 }
221
222 if (i->dft->lldd_control_phy(asd_phy, phy_op, &rates))
214 resp_data[2] = SMP_RESP_FUNC_FAILED; 223 resp_data[2] = SMP_RESP_FUNC_FAILED;
215 else 224 else
216 resp_data[2] = SMP_RESP_FUNC_ACC; 225 resp_data[2] = SMP_RESP_FUNC_ACC;
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index cf1b532b0e76..dc93e1181469 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -196,6 +196,27 @@ static int sas_get_linkerrors(struct sas_phy *phy)
196 return sas_smp_get_phy_events(phy); 196 return sas_smp_get_phy_events(phy);
197} 197}
198 198
199int sas_try_ata_reset(struct asd_sas_phy *asd_phy)
200{
201 struct domain_device *dev = NULL;
202
203 /* try to route user requested link resets through libata */
204 if (asd_phy->port)
205 dev = asd_phy->port->port_dev;
206
207 /* validate that dev has been probed */
208 if (dev)
209 dev = sas_find_dev_by_rphy(dev->rphy);
210
211 if (dev && dev_is_sata(dev)) {
212 sas_ata_schedule_reset(dev);
213 sas_ata_wait_eh(dev);
214 return 0;
215 }
216
217 return -ENODEV;
218}
219
199/** 220/**
200 * transport_sas_phy_reset - reset a phy and permit libata to manage the link 221 * transport_sas_phy_reset - reset a phy and permit libata to manage the link
201 * 222 *
@@ -204,7 +225,6 @@ static int sas_get_linkerrors(struct sas_phy *phy)
204 */ 225 */
205static int transport_sas_phy_reset(struct sas_phy *phy, int hard_reset) 226static int transport_sas_phy_reset(struct sas_phy *phy, int hard_reset)
206{ 227{
207 int ret;
208 enum phy_func reset_type; 228 enum phy_func reset_type;
209 229
210 if (hard_reset) 230 if (hard_reset)
@@ -218,21 +238,10 @@ static int transport_sas_phy_reset(struct sas_phy *phy, int hard_reset)
218 struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number]; 238 struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
219 struct sas_internal *i = 239 struct sas_internal *i =
220 to_sas_internal(sas_ha->core.shost->transportt); 240 to_sas_internal(sas_ha->core.shost->transportt);
221 struct domain_device *dev = NULL;
222
223 if (asd_phy->port)
224 dev = asd_phy->port->port_dev;
225
226 /* validate that dev has been probed */
227 if (dev)
228 dev = sas_find_dev_by_rphy(dev->rphy);
229 241
230 if (dev && dev_is_sata(dev) && !hard_reset) { 242 if (!hard_reset && sas_try_ata_reset(asd_phy) == 0)
231 sas_ata_schedule_reset(dev); 243 return 0;
232 sas_ata_wait_eh(dev); 244 return i->dft->lldd_control_phy(asd_phy, reset_type, NULL);
233 ret = 0;
234 } else
235 ret = i->dft->lldd_control_phy(asd_phy, reset_type, NULL);
236 } else { 245 } else {
237 struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); 246 struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
238 struct domain_device *ddev = sas_find_dev_by_rphy(rphy); 247 struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
@@ -241,12 +250,10 @@ static int transport_sas_phy_reset(struct sas_phy *phy, int hard_reset)
241 if (ata_dev && !hard_reset) { 250 if (ata_dev && !hard_reset) {
242 sas_ata_schedule_reset(ata_dev); 251 sas_ata_schedule_reset(ata_dev);
243 sas_ata_wait_eh(ata_dev); 252 sas_ata_wait_eh(ata_dev);
244 ret = 0; 253 return 0;
245 } else 254 } else
246 ret = sas_smp_phy_control(ddev, phy->number, reset_type, NULL); 255 return sas_smp_phy_control(ddev, phy->number, reset_type, NULL);
247 } 256 }
248
249 return ret;
250} 257}
251 258
252static int sas_phy_enable(struct sas_phy *phy, int enable) 259static int sas_phy_enable(struct sas_phy *phy, int enable)
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index c8febc71c40d..4157f6e1eda2 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -92,6 +92,7 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
92struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id); 92struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
93int sas_get_phy_attached_sas_addr(struct domain_device *dev, int phy_id, 93int sas_get_phy_attached_sas_addr(struct domain_device *dev, int phy_id,
94 u8 *attached_sas_addr); 94 u8 *attached_sas_addr);
95int sas_try_ata_reset(struct asd_sas_phy *phy);
95void sas_hae_reset(struct work_struct *work); 96void sas_hae_reset(struct work_struct *work);
96 97
97void sas_free_device(struct kref *kref); 98void sas_free_device(struct kref *kref);