Patchwork ahci: enable pmp but connected to HDD issue fixed

login
register
mail settings
Submitter Yuan-Hsin Chen
Date June 14, 2011, 5:48 a.m.
Message ID <1308030504-3026-1-git-send-email-yuanlmm@gmail.com>
Download mbox | patch
Permalink /patch/100280/
State Not Applicable
Delegated to: David Miller
Headers show

Comments

Yuan-Hsin Chen - June 14, 2011, 5:48 a.m.
From: Yuan-Hsin Chen <yhchen@faraday-tech.com>

When enabling both port multiplier and platform ahci sata, ahci
times out while connecting to HDD directly. This is because soft
reset fails with IPMS set. Do soft reset again to port 0.

The soft reset sequence is copied from ahci.c.

Signed-off-by: Yuan-Hsin Chen <yhchen@faraday-tech.com>
---
 drivers/ata/ahci_platform.c |   62 ++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 61 insertions(+), 1 deletions(-)
Tejun Heo - June 14, 2011, 6:52 a.m.
On Tue, Jun 14, 2011 at 01:48:24PM +0800, Yuan-Hsin Chen wrote:
> From: Yuan-Hsin Chen <yhchen@faraday-tech.com>
> 
> When enabling both port multiplier and platform ahci sata, ahci
> times out while connecting to HDD directly. This is because soft
> reset fails with IPMS set. Do soft reset again to port 0.
> 
> The soft reset sequence is copied from ahci.c.

This is the same one as ahci_sb600_softreset(), right?  Please don't
copy & paste like that.  Rename and ahci_sb600_softreset() to
libahci.c, create a separate ata_port_operations for it and use the
ops for the affected controllers.

Thanks.
BingJiun Luo - June 15, 2011, 2:50 a.m.
Since more than one controllers has software reset failed problem when PMP
enabled, I think it would be better to move ahci_sb600_softreset() from ahci.c
to libahci.c and rename it, let's say: ahci_pmpenable_softreset() .
(Just arbitrary
name, please someone may give a better function name)
Controller that has software reset problem when PMP enable may point its
softreset and pmp_softreset call back function of struct ata_port_operations to
ahci_pmpenable_softreset(). Regardless of PCI or Platform based AHCI controller.
(ahci.c or ahci_platform.c)
Regards,
BingJiun
On Tue, Jun 14, 2011 at 1:48 PM, Yuan-Hsin Chen <yuanlmm@gmail.com> wrote:
>
> From: Yuan-Hsin Chen <yhchen@faraday-tech.com>
>
> When enabling both port multiplier and platform ahci sata, ahci
> times out while connecting to HDD directly. This is because soft
> reset fails with IPMS set. Do soft reset again to port 0.
>
> The soft reset sequence is copied from ahci.c.
>
> Signed-off-by: Yuan-Hsin Chen <yhchen@faraday-tech.com>
> ---
>  drivers/ata/ahci_platform.c |   62 ++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 61 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
> index 6fef1fa..6eab716 100644
> --- a/drivers/ata/ahci_platform.c
> +++ b/drivers/ata/ahci_platform.c
> @@ -27,6 +27,66 @@ static struct scsi_host_template ahci_platform_sht = {
>        AHCI_SHT("ahci_platform"),
>  };
>
> +static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
> +                         unsigned long deadline);
> +
> +static struct ata_port_operations ahci_pmp_ops = {
> +       .inherits               = &ahci_ops,
> +       .softreset              = ahci_pmp_softreset,
> +       .pmp_softreset          = ahci_pmp_softreset,
> +};
> +
> +static int ahci_pmp_check_ready(struct ata_link *link)
> +{
> +       void __iomem *port_mmio = ahci_port_base(link->ap);
> +       u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
> +       u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);
> +
> +       /*
> +        * There is no need to check TFDATA if BAD PMP is found due to HW bug,
> +        * which can save timeout delay.
> +        */
> +       if (irq_status & PORT_IRQ_BAD_PMP)
> +               return -EIO;
> +
> +       printk("%s:TFT 0x%x\n", __func__, status);
> +       return ata_check_ready(status);
> +}
> +
> +static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
> +                               unsigned long deadline)
> +{
> +       struct ata_port *ap = link->ap;
> +       void __iomem *port_mmio = ahci_port_base(ap);
> +       int pmp = sata_srst_pmp(link);
> +       int rc;
> +       u32 irq_sts;
> +
> +       DPRINTK("ENTER\n");
> +
> +       rc = ahci_do_softreset(link, class, pmp, deadline,
> +                              ahci_pmp_check_ready);
> +
> +       /*
> +        * Soft reset fails with IPMS set when PMP is enabled but
> +        * SATA HDD/ODD is connected to SATA port, do soft reset
> +        * again to port 0.
> +        */
> +       if (rc == -EIO) {
> +               irq_sts = readl(port_mmio + PORT_IRQ_STAT);
> +               if (irq_sts & PORT_IRQ_BAD_PMP) {
> +                       ata_link_printk(link, KERN_WARNING,
> +                                       "applying PMP SRST workaround "
> +                                       "and retrying\n");
> +                       rc = ahci_do_softreset(link, class, 0, deadline,
> +                                              ahci_check_ready);
> +               }
> +       }
> +
> +       return rc;
> +}
> +
> +
>  static int __init ahci_probe(struct platform_device *pdev)
>  {
>        struct device *dev = &pdev->dev;
> @@ -35,7 +95,7 @@ static int __init ahci_probe(struct platform_device *pdev)
>                .flags          = AHCI_FLAG_COMMON,
>                .pio_mask       = ATA_PIO4,
>                .udma_mask      = ATA_UDMA6,
> -               .port_ops       = &ahci_ops,
> +               .port_ops       = &ahci_pmp_ops,
>        };
>        const struct ata_port_info *ppi[] = { &pi, NULL };
>        struct ahci_host_priv *hpriv;
> --
> 1.7.3.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ide" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 6fef1fa..6eab716 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -27,6 +27,66 @@  static struct scsi_host_template ahci_platform_sht = {
 	AHCI_SHT("ahci_platform"),
 };
 
+static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
+			  unsigned long deadline);
+
+static struct ata_port_operations ahci_pmp_ops = {
+	.inherits		= &ahci_ops,
+	.softreset		= ahci_pmp_softreset,
+	.pmp_softreset		= ahci_pmp_softreset,
+};
+
+static int ahci_pmp_check_ready(struct ata_link *link)
+{
+	void __iomem *port_mmio = ahci_port_base(link->ap);
+	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
+	u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);
+
+	/*
+	 * There is no need to check TFDATA if BAD PMP is found due to HW bug,
+	 * which can save timeout delay.
+	 */
+	if (irq_status & PORT_IRQ_BAD_PMP)
+		return -EIO;
+
+	printk("%s:TFT 0x%x\n", __func__, status);
+	return ata_check_ready(status);
+}
+
+static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
+				unsigned long deadline)
+{
+	struct ata_port *ap = link->ap;
+	void __iomem *port_mmio = ahci_port_base(ap);
+	int pmp = sata_srst_pmp(link);
+	int rc;
+	u32 irq_sts;
+
+	DPRINTK("ENTER\n");
+
+	rc = ahci_do_softreset(link, class, pmp, deadline,
+			       ahci_pmp_check_ready);
+
+	/*
+	 * Soft reset fails with IPMS set when PMP is enabled but
+	 * SATA HDD/ODD is connected to SATA port, do soft reset
+	 * again to port 0.
+	 */
+	if (rc == -EIO) {
+		irq_sts = readl(port_mmio + PORT_IRQ_STAT);
+		if (irq_sts & PORT_IRQ_BAD_PMP) {
+			ata_link_printk(link, KERN_WARNING,
+					"applying PMP SRST workaround "
+					"and retrying\n");
+			rc = ahci_do_softreset(link, class, 0, deadline,
+					       ahci_check_ready);
+		}
+	}
+
+	return rc;
+}
+
+
 static int __init ahci_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -35,7 +95,7 @@  static int __init ahci_probe(struct platform_device *pdev)
 		.flags		= AHCI_FLAG_COMMON,
 		.pio_mask	= ATA_PIO4,
 		.udma_mask	= ATA_UDMA6,
-		.port_ops	= &ahci_ops,
+		.port_ops	= &ahci_pmp_ops,
 	};
 	const struct ata_port_info *ppi[] = { &pi, NULL };
 	struct ahci_host_priv *hpriv;