aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas/sas_expander.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-12-01 02:23:33 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-19 15:09:32 -0500
commitb52df4174dff7e587f6fbfb21e3c2cb57109e5cf (patch)
tree1e53cb4a62519dda60babc240bbd3b7f69c5b1f4 /drivers/scsi/libsas/sas_expander.c
parent3a2cdf391b62919d3d2862cdce3d70b9a7a99673 (diff)
[SCSI] libsas: use libata-eh-reset for sata rediscovery fis transmit failures
Since sata devices can take several seconds to recover the link on reset the 0.5 seconds that libsas currently waits may not be enough. Instead if we are rediscovering a phy that was previously attached to a sata device let libata handle any resets to encourage the device to transmit the initial fis. Once sas_ata_hard_reset() and lldds learn how to honor 'deadline' libsas should stop encountering phys in an intermediate state, until then this will loop until the fis is transmitted or ->attached_sas_addr gets cleared, but in the more likely initial discovery case we keep existing behavior. Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas/sas_expander.c')
-rw-r--r--drivers/scsi/libsas/sas_expander.c44
1 files changed, 39 insertions, 5 deletions
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 */
231static 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
232static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req, 255static 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);