From c6d8d628a47babd221a0c8f46cd398842ffa4704 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: <7498034fbbadc770e50ec1d4c674d3a79a684524.1167304867.git.robbat2@gentoo.org> References: <7498034fbbadc770e50ec1d4c674d3a79a684524.1167304867.git.robbat2@gentoo.org> From: Tejun Heo Date: Mon, 16 Oct 2006 07:24:42 +0900 Subject: [PATCH 3/13] [PATCH] libata-pmp: implement ATA_LFLAG_DISABLED 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 Signed-off-by: Robin H. Johnson --- 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 ata_link *link) 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 ata_link *link) 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 ata_link *link) 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_prereset_fn_t prereset, 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_device *sdev, pm_message_t mesg) 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_device *sdev) 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(struct ata_eh_info *ehi) 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.4.3