forked from Minki/linux
[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>
This commit is contained in:
parent
3a2cdf391b
commit
b52df4174d
@ -679,3 +679,22 @@ int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
|
|||||||
|
|
||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sas_ata_schedule_reset(struct domain_device *dev)
|
||||||
|
{
|
||||||
|
struct ata_eh_info *ehi;
|
||||||
|
struct ata_port *ap;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (!dev_is_sata(dev))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ap = dev->sata_dev.ap;
|
||||||
|
ehi = &ap->link.eh_info;
|
||||||
|
|
||||||
|
spin_lock_irqsave(ap->lock, flags);
|
||||||
|
ehi->err_mask |= AC_ERR_TIMEOUT;
|
||||||
|
ehi->action |= ATA_EH_RESET;
|
||||||
|
ata_port_schedule_eh(ap);
|
||||||
|
spin_unlock_irqrestore(ap->lock, flags);
|
||||||
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include "sas_internal.h"
|
#include "sas_internal.h"
|
||||||
|
|
||||||
|
#include <scsi/sas_ata.h>
|
||||||
#include <scsi/scsi_transport.h>
|
#include <scsi/scsi_transport.h>
|
||||||
#include <scsi/scsi_transport_sas.h>
|
#include <scsi/scsi_transport_sas.h>
|
||||||
#include "../scsi_sas_internal.h"
|
#include "../scsi_sas_internal.h"
|
||||||
@ -226,12 +227,35 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check if we have an existing attached ata device on this expander phy */
|
||||||
|
static struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id)
|
||||||
|
{
|
||||||
|
struct ex_phy *ex_phy = &ex_dev->ex_dev.ex_phy[phy_id];
|
||||||
|
struct domain_device *dev;
|
||||||
|
struct sas_rphy *rphy;
|
||||||
|
|
||||||
|
if (!ex_phy->port)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
rphy = ex_phy->port->rphy;
|
||||||
|
if (!rphy)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
dev = sas_find_dev_by_rphy(rphy);
|
||||||
|
|
||||||
|
if (dev && dev_is_sata(dev))
|
||||||
|
return dev;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#define DISCOVER_REQ_SIZE 16
|
#define DISCOVER_REQ_SIZE 16
|
||||||
#define DISCOVER_RESP_SIZE 56
|
#define DISCOVER_RESP_SIZE 56
|
||||||
|
|
||||||
static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req,
|
static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req,
|
||||||
u8 *disc_resp, int single)
|
u8 *disc_resp, int single)
|
||||||
{
|
{
|
||||||
|
struct domain_device *ata_dev = sas_ex_to_ata(dev, single);
|
||||||
int i, res;
|
int i, res;
|
||||||
|
|
||||||
disc_req[9] = single;
|
disc_req[9] = single;
|
||||||
@ -242,20 +266,30 @@ static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req,
|
|||||||
disc_resp, DISCOVER_RESP_SIZE);
|
disc_resp, DISCOVER_RESP_SIZE);
|
||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
/* This is detecting a failure to transmit initial
|
|
||||||
* dev to host FIS as described in section G.5 of
|
|
||||||
* sas-2 r 04b */
|
|
||||||
dr = &((struct smp_resp *)disc_resp)->disc;
|
dr = &((struct smp_resp *)disc_resp)->disc;
|
||||||
if (memcmp(dev->sas_addr, dr->attached_sas_addr,
|
if (memcmp(dev->sas_addr, dr->attached_sas_addr,
|
||||||
SAS_ADDR_SIZE) == 0) {
|
SAS_ADDR_SIZE) == 0) {
|
||||||
sas_printk("Found loopback topology, just ignore it!\n");
|
sas_printk("Found loopback topology, just ignore it!\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This is detecting a failure to transmit initial
|
||||||
|
* dev to host FIS as described in section J.5 of
|
||||||
|
* sas-2 r16
|
||||||
|
*/
|
||||||
if (!(dr->attached_dev_type == 0 &&
|
if (!(dr->attached_dev_type == 0 &&
|
||||||
dr->attached_sata_dev))
|
dr->attached_sata_dev))
|
||||||
break;
|
break;
|
||||||
/* In order to generate the dev to host FIS, we
|
|
||||||
* send a link reset to the expander port */
|
/* In order to generate the dev to host FIS, we send a
|
||||||
|
* link reset to the expander port. If a device was
|
||||||
|
* previously detected on this port we ask libata to
|
||||||
|
* manage the reset and link recovery.
|
||||||
|
*/
|
||||||
|
if (ata_dev) {
|
||||||
|
sas_ata_schedule_reset(ata_dev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
sas_smp_phy_control(dev, single, PHY_FUNC_LINK_RESET, NULL);
|
sas_smp_phy_control(dev, single, PHY_FUNC_LINK_RESET, NULL);
|
||||||
/* Wait for the reset to trigger the negotiation */
|
/* Wait for the reset to trigger the negotiation */
|
||||||
msleep(500);
|
msleep(500);
|
||||||
|
@ -44,7 +44,7 @@ void sas_ata_strategy_handler(struct Scsi_Host *shost);
|
|||||||
int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
|
int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
|
||||||
struct list_head *done_q);
|
struct list_head *done_q);
|
||||||
void sas_probe_sata(struct work_struct *work);
|
void sas_probe_sata(struct work_struct *work);
|
||||||
|
void sas_ata_schedule_reset(struct domain_device *dev);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
||||||
@ -75,6 +75,10 @@ static inline void sas_probe_sata(struct work_struct *work)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void sas_ata_schedule_reset(struct domain_device *dev)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _SAS_ATA_H_ */
|
#endif /* _SAS_ATA_H_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user