[PATCH 3/12] libata-pmp: implement ATA_LFLAG_DISABLED

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Implement ATA_LFLAG_DISABLED.  The flag indicates the link is disabled
due to EH recovery failure.  While a link is disabled, no EH action is
taken on the link and suspend/resume become noop too.  For host port,
this doesn't introduce any behavior change other than not invoking
hotplug sequence on failed ports on resume and this behavior change is
intended.

This will be used by PMP links to manage failed links.

Signed-off-by: Tejun Heo <htejun@xxxxxxxxx>
---
 drivers/ata/libata-eh.c   |   29 ++++++++++++++++++++++++++++-
 drivers/ata/libata-scsi.c |   10 ++++++----
 include/linux/libata.h    |    6 +++++-
 3 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 2c302c9..228240a 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1058,6 +1058,7 @@ static void ata_eh_analyze_serror(struct
 	struct ata_eh_context *ehc = &link->eh_context;
 	u32 serror = ehc->i.serror;
 	unsigned int err_mask = 0, action = 0;
+	u32 hotplug_mask;
 
 	if (serror & SERR_PERSISTENT) {
 		err_mask |= AC_ERR_ATA_BUS;
@@ -1076,7 +1077,22 @@ static void ata_eh_analyze_serror(struct
 		err_mask |= AC_ERR_SYSTEM;
 		action |= ATA_EH_SOFTRESET;
 	}
-	if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
+
+	/* Determine whether a hotplug event has occurred.  Both
+	 * SError.N/X are considered hotplug events for enabled links.
+	 * For disabled host links, hp-poll is responsible for hotplug
+	 * event detection and thus both N/X bits are ignored.  For
+	 * disabled PMP links, only N bit is considered as X bit is
+	 * left at 1 for link plugging.
+	 */
+	hotplug_mask = 0;
+
+	if (!(link->flags & ATA_LFLAG_DISABLED))
+		hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG;
+	else if (!ata_is_host_link(link))
+		hotplug_mask = SERR_PHYRDY_CHG;
+
+	if (serror & hotplug_mask)
 		ata_ehi_hotplugged(&ehc->i);
 
 	ehc->i.err_mask |= err_mask;
@@ -1968,6 +1984,10 @@ static int ata_eh_skip_recovery(struct a
 	struct ata_eh_context *ehc = &link->eh_context;
 	struct ata_device *dev;
 
+	/* skip disabled links */
+	if (link->flags & ATA_LFLAG_DISABLED)
+		return 1;
+
 	/* skip if all possible devices are suspended */
 	ata_link_for_each_dev(dev, link) {
 		if (!(dev->flags & ATA_DFLAG_SUSPENDED))
@@ -2079,6 +2099,13 @@ int ata_eh_recover(struct ata_port *ap, 
 	ata_port_for_each_link(link, ap) {
 		struct ata_eh_context *ehc = &link->eh_context;
 
+		/* re-enable link? */
+		if (ehc->i.action & ATA_EH_ENABLE_LINK) {
+			ata_eh_about_to_do(link, NULL, ATA_EH_ENABLE_LINK);
+			link->flags &= ~ATA_LFLAG_DISABLED;
+			ata_eh_done(link, NULL, ATA_EH_ENABLE_LINK);
+		}
+
 		ata_link_for_each_dev(dev, link) {
 			ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
 
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index c62992f..64777e1 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -463,9 +463,10 @@ int ata_scsi_device_suspend(struct scsi_
 		spin_lock_irqsave(ap->lock, flags);
 	}
 
-	/* if @sdev is already detached, nothing to do */
+	/* if @sdev is already detached or link is disabled, nothing to do */
 	if (sdev->sdev_state == SDEV_OFFLINE ||
-	    sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
+	    sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL ||
+	    (dev->link->flags & ATA_LFLAG_DISABLED))
 		goto out_unlock;
 
 	/* request suspend */
@@ -526,9 +527,10 @@ int ata_scsi_device_resume(struct scsi_d
 
 	spin_lock_irqsave(ap->lock, flags);
 
-	/* if @sdev is already detached, nothing to do */
+	/* if @sdev is already detached or link is disabled, nothing to do */
 	if (sdev->sdev_state == SDEV_OFFLINE ||
-	    sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
+	    sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL ||
+	    (dev->link->flags & ATA_LFLAG_DISABLED))
 		goto out_unlock;
 
 	/* request resume */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index fe64a31..a940b67 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -160,6 +160,9 @@ enum {
 	ATA_DEV_PMP_UNSUP	= 6,	/* SATA port multiplier (unsupported) */
 	ATA_DEV_NONE		= 7,	/* no device */
 
+	/* struct ata_link flags */
+	ATA_LFLAG_DISABLED	= (1 << 0), /* this link is disabled (PMP) */
+
 	/* struct ata_port flags */
 	ATA_FLAG_SLAVE_POSS	= (1 << 0), /* host supports slave dev */
 					    /* (doesn't imply presence) */
@@ -283,6 +286,7 @@ enum {
 	ATA_EH_SUSPEND		= (1 << 3),
 	ATA_EH_RESUME		= (1 << 4),
 	ATA_EH_PM_FREEZE	= (1 << 5),
+	ATA_EH_ENABLE_LINK	= (1 << 6),
 
 	ATA_EH_RESET_MASK	= ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
 	ATA_EH_PERDEV_MASK	= ATA_EH_REVALIDATE | ATA_EH_SUSPEND |
@@ -981,7 +985,7 @@ static inline void __ata_ehi_hotplugged(
 	ehi->flags |= ATA_EHI_HOTPLUGGED | ATA_EHI_RESUME_LINK;
 	ehi->hotplug_timestamp = jiffies;
 
-	ehi->action |= ATA_EH_SOFTRESET;
+	ehi->action |= ATA_EH_ENABLE_LINK | ATA_EH_SOFTRESET;
 	ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
 }
 
-- 
1.4.2.3


-
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystems]     [Linux SCSI]     [Linux RAID]     [Git]     [Kernel Newbies]     [Linux Newbie]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Samba]     [Device Mapper]

  Powered by Linux