diff options
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 19 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_expander.c | 44 |
2 files changed, 58 insertions, 5 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index a8ace8d24e66..48cadf88c399 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c | |||
@@ -679,3 +679,22 @@ int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q, | |||
679 | 679 | ||
680 | return rtn; | 680 | return rtn; |
681 | } | 681 | } |
682 | |||
683 | void sas_ata_schedule_reset(struct domain_device *dev) | ||
684 | { | ||
685 | struct ata_eh_info *ehi; | ||
686 | struct ata_port *ap; | ||
687 | unsigned long flags; | ||
688 | |||
689 | if (!dev_is_sata(dev)) | ||
690 | return; | ||
691 | |||
692 | ap = dev->sata_dev.ap; | ||
693 | ehi = &ap->link.eh_info; | ||
694 | |||
695 | spin_lock_irqsave(ap->lock, flags); | ||
696 | ehi->err_mask |= AC_ERR_TIMEOUT; | ||
697 | ehi->action |= ATA_EH_RESET; | ||
698 | ata_port_schedule_eh(ap); | ||
699 | spin_unlock_irqrestore(ap->lock, flags); | ||
700 | } | ||
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index e45b259dac4c..f4894b0f537b 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c | |||
@@ -28,6 +28,7 @@ | |||
28 | 28 | ||
29 | #include "sas_internal.h" | 29 | #include "sas_internal.h" |
30 | 30 | ||
31 | #include <scsi/sas_ata.h> | ||
31 | #include <scsi/scsi_transport.h> | 32 | #include <scsi/scsi_transport.h> |
32 | #include <scsi/scsi_transport_sas.h> | 33 | #include <scsi/scsi_transport_sas.h> |
33 | #include "../scsi_sas_internal.h" | 34 | #include "../scsi_sas_internal.h" |
@@ -226,12 +227,35 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, | |||
226 | return; | 227 | return; |
227 | } | 228 | } |
228 | 229 | ||
230 | /* check if we have an existing attached ata device on this expander phy */ | ||
231 | static struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id) | ||
232 | { | ||
233 | struct ex_phy *ex_phy = &ex_dev->ex_dev.ex_phy[phy_id]; | ||
234 | struct domain_device *dev; | ||
235 | struct sas_rphy *rphy; | ||
236 | |||
237 | if (!ex_phy->port) | ||
238 | return NULL; | ||
239 | |||
240 | rphy = ex_phy->port->rphy; | ||
241 | if (!rphy) | ||
242 | return NULL; | ||
243 | |||
244 | dev = sas_find_dev_by_rphy(rphy); | ||
245 | |||
246 | if (dev && dev_is_sata(dev)) | ||
247 | return dev; | ||
248 | |||
249 | return NULL; | ||
250 | } | ||
251 | |||
229 | #define DISCOVER_REQ_SIZE 16 | 252 | #define DISCOVER_REQ_SIZE 16 |
230 | #define DISCOVER_RESP_SIZE 56 | 253 | #define DISCOVER_RESP_SIZE 56 |
231 | 254 | ||
232 | static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req, | 255 | static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req, |
233 | u8 *disc_resp, int single) | 256 | u8 *disc_resp, int single) |
234 | { | 257 | { |
258 | struct domain_device *ata_dev = sas_ex_to_ata(dev, single); | ||
235 | int i, res; | 259 | int i, res; |
236 | 260 | ||
237 | disc_req[9] = single; | 261 | disc_req[9] = single; |
@@ -242,20 +266,30 @@ static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req, | |||
242 | disc_resp, DISCOVER_RESP_SIZE); | 266 | disc_resp, DISCOVER_RESP_SIZE); |
243 | if (res) | 267 | if (res) |
244 | return res; | 268 | return res; |
245 | /* This is detecting a failure to transmit initial | ||
246 | * dev to host FIS as described in section G.5 of | ||
247 | * sas-2 r 04b */ | ||
248 | dr = &((struct smp_resp *)disc_resp)->disc; | 269 | dr = &((struct smp_resp *)disc_resp)->disc; |
249 | if (memcmp(dev->sas_addr, dr->attached_sas_addr, | 270 | if (memcmp(dev->sas_addr, dr->attached_sas_addr, |
250 | SAS_ADDR_SIZE) == 0) { | 271 | SAS_ADDR_SIZE) == 0) { |
251 | sas_printk("Found loopback topology, just ignore it!\n"); | 272 | sas_printk("Found loopback topology, just ignore it!\n"); |
252 | return 0; | 273 | return 0; |
253 | } | 274 | } |
275 | |||
276 | /* This is detecting a failure to transmit initial | ||
277 | * dev to host FIS as described in section J.5 of | ||
278 | * sas-2 r16 | ||
279 | */ | ||
254 | if (!(dr->attached_dev_type == 0 && | 280 | if (!(dr->attached_dev_type == 0 && |
255 | dr->attached_sata_dev)) | 281 | dr->attached_sata_dev)) |
256 | break; | 282 | break; |
257 | /* In order to generate the dev to host FIS, we | 283 | |
258 | * send a link reset to the expander port */ | 284 | /* In order to generate the dev to host FIS, we send a |
285 | * link reset to the expander port. If a device was | ||
286 | * previously detected on this port we ask libata to | ||
287 | * manage the reset and link recovery. | ||
288 | */ | ||
289 | if (ata_dev) { | ||
290 | sas_ata_schedule_reset(ata_dev); | ||
291 | break; | ||
292 | } | ||
259 | sas_smp_phy_control(dev, single, PHY_FUNC_LINK_RESET, NULL); | 293 | sas_smp_phy_control(dev, single, PHY_FUNC_LINK_RESET, NULL); |
260 | /* Wait for the reset to trigger the negotiation */ | 294 | /* Wait for the reset to trigger the negotiation */ |
261 | msleep(500); | 295 | msleep(500); |