All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tejun Heo <htejun@gmail.com>
To: jgarzik@pobox.com, alan@lxorguk.ukuu.org.uk, axboe@suse.de,
	albertcc@tw.ibm.com, forrest.zhao@intel.com, efalk@google.com,
	linux-ide@vger.kernel.org
Cc: Tejun Heo <htejun@gmail.com>
Subject: [PATCH 10/10] sata_sil24: implement PORT_RST
Date: Fri, 12 May 2006 01:43:43 +0900	[thread overview]
Message-ID: <11473658232595-git-send-email-htejun@gmail.com> (raw)
In-Reply-To: <11473658222012-git-send-email-htejun@gmail.com>

DEV_RST (hardreset) sometimes fail to recover the controller
(especially after PM CS DMA errata).  In such cases, perform PORT_RST
prior to DEV_RST.

---

 drivers/scsi/sata_sil24.c |   98 +++++++++++++++++++++++++++++++++------------
 1 files changed, 72 insertions(+), 26 deletions(-)

246bc1468a20be1c93d294eb0b75a9df71e2a8ef
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 1979cfc..9b7f46f 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -318,6 +318,7 @@ static struct sil24_cerr_info {
 struct sil24_port_priv {
 	union sil24_cmd_block *cmd_block;	/* 32 cmd blocks */
 	dma_addr_t cmd_block_dma;		/* DMA base addr for them */
+	int do_port_rst;
 };
 
 /* ap->host_set->private_data */
@@ -510,6 +511,30 @@ static void sil24_scr_write(struct ata_p
 	}
 }
 
+static void sil24_config_controller(void __iomem *port,
+				    unsigned long host_flags)
+{
+	/* configure IRQ WoC */
+	if (host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
+		writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
+	else
+		writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+
+	/* zero error counters. */
+	writel(0x8000, port + PORT_DECODE_ERR_THRESH);
+	writel(0x8000, port + PORT_CRC_ERR_THRESH);
+	writel(0x8000, port + PORT_HSHK_ERR_THRESH);
+	writel(0x0000, port + PORT_DECODE_ERR_CNT);
+	writel(0x0000, port + PORT_CRC_ERR_CNT);
+	writel(0x0000, port + PORT_HSHK_ERR_CNT);
+
+	/* always use 64bit activation */
+	writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
+
+	/* clear port multiplier enable and resume bits */
+	writel(PORT_CS_PM_EN | PORT_CS_PM_RESUME, port + PORT_CTRL_CLR);
+}
+
 static void sil24_config_pm(struct ata_port *ap, int attached)
 {
 	void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
@@ -538,6 +563,7 @@ static void sil24_clear_pm(struct ata_po
 static int sil24_init_port(struct ata_port *ap)
 {
 	void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+	struct sil24_port_priv *pp = ap->private_data;
 	u32 tmp;
 
 	writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
@@ -549,8 +575,12 @@ static int sil24_init_port(struct ata_po
 	/* clear PM error status */
 	sil24_clear_pm(ap);
 
-	if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY)
+	if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) {
+		pp->do_port_rst = 1;
+		ap->link.eh_context.i.action |= ATA_EH_HARDRESET;
 		return -EIO;
+	}
+
 	return 0;
 }
 
@@ -659,10 +689,34 @@ static int sil24_hardreset(struct ata_li
 {
 	struct ata_port *ap = link->ap;
 	void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+	struct sil24_port_priv *pp = ap->private_data;
+	int did_port_rst = 0;
 	const char *reason;
 	int tout_msec, rc;
 	u32 tmp;
 
+ retry:
+	/* Sometimes, DEV_RST is not enough to recover the controller.
+	 * This happens a lot after PM DMA CS errata.
+	 */
+	if (pp->do_port_rst) {
+		ata_port_printk(ap, KERN_WARNING, "controller in dubious "
+				"state, performing PORT_RST\n");
+
+		writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT);
+		msleep(10);
+		writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
+		ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0,
+				  10, 5000);
+
+		/* restore port configuration */
+		sil24_config_controller(port, ap->flags);
+		sil24_config_pm(ap, ap->nr_pm_links);
+
+		pp->do_port_rst = 0;
+		did_port_rst = 1;
+	}
+
 	/* sil24 does the right thing(tm) without any protection */
 	ata_set_sata_spd(link);
 
@@ -700,6 +754,11 @@ static int sil24_hardreset(struct ata_li
 	return -EAGAIN;
 
  err:
+	if (!did_port_rst) {
+		pp->do_port_rst = 1;
+		goto retry;
+	}
+
 	ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason);
 	return -EIO;
 }
@@ -910,6 +969,7 @@ static void sil24_thaw(struct ata_port *
 static void sil24_error_intr(struct ata_port *ap)
 {
 	void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+	struct sil24_port_priv *pp = ap->private_data;
 	int freeze = 0;
 	struct ata_link *link;
 	struct ata_eh_info *ehi;
@@ -974,6 +1034,7 @@ static void sil24_error_intr(struct ata_
 			ehi->err_mask |= AC_ERR_OTHER;
 			ehi->action |= ATA_EH_HARDRESET;
 			ata_ehi_push_desc(ehi, ", PM DMA CS errata");
+			pp->do_port_rst = 1;
 			freeze = 1;
 		}
 
@@ -1116,17 +1177,17 @@ static irqreturn_t sil24_interrupt(int i
 
 static void sil24_error_handler(struct ata_port *ap)
 {
-	struct ata_eh_context *ehc = &ap->link.eh_context;
+	struct sil24_port_priv *pp = ap->private_data;
 
-	if (sil24_init_port(ap)) {
+	if (sil24_init_port(ap))
 		ata_eh_freeze_port(ap);
-		ehc->i.action |= ATA_EH_HARDRESET;
-	}
 
 	/* perform recovery */
 	ata_pm_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
 		     ata_std_postreset, ata_pm_std_prereset, sil24_pm_softreset,
 		     sil24_pm_hardreset, ata_pm_std_postreset);
+
+	pp->do_port_rst = 0;
 }
 
 static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
@@ -1137,8 +1198,10 @@ static void sil24_post_internal_cmd(stru
 		qc->err_mask |= AC_ERR_OTHER;
 
 	/* make DMA engine forget about the failed command */
-	if (qc->err_mask)
-		sil24_init_port(ap);
+	if (qc->err_mask) {
+		if (sil24_init_port(ap))
+			ata_eh_freeze_port(ap);
+	}
 }
 
 static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev)
@@ -1334,25 +1397,8 @@ static int sil24_init_one(struct pci_dev
 				           "failed to clear port RST\n");
 		}
 
-		/* Configure IRQ WoC */
-		if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
-			writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
-		else
-			writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
-
-		/* Zero error counters. */
-		writel(0x8000, port + PORT_DECODE_ERR_THRESH);
-		writel(0x8000, port + PORT_CRC_ERR_THRESH);
-		writel(0x8000, port + PORT_HSHK_ERR_THRESH);
-		writel(0x0000, port + PORT_DECODE_ERR_CNT);
-		writel(0x0000, port + PORT_CRC_ERR_CNT);
-		writel(0x0000, port + PORT_HSHK_ERR_CNT);
-
-		/* Always use 64bit activation */
-		writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
-
-		/* Clear port multiplier enable and resume bits */
-		writel(PORT_CS_PM_EN | PORT_CS_PM_RESUME, port + PORT_CTRL_CLR);
+		/* configure controller */
+		sil24_config_controller(port, probe_ent->host_flags);
 	}
 
 	/* Turn on interrupts */
-- 
1.2.4



  parent reply	other threads:[~2006-05-11 16:43 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-05-11 16:43 [PATCHSET 11/11] implement PM support Tejun Heo
2006-05-11 16:43 ` [PATCH 02/10] libata-pm: update ata_eh_reset() for PM Tejun Heo
2006-05-11 16:43 ` [PATCH 05/10] sata_sil24: rename PORT_CS_RESUME to PORT_CS_PM_RESUME Tejun Heo
2006-05-11 16:43 ` [PATCH 06/10] sata_sil24: add PM related constants Tejun Heo
2006-05-11 16:43 ` [PATCH 03/10] libata-pm: implement Port Multiplier support Tejun Heo
2006-05-11 16:43 ` [PATCH 07/10] sata_sil24: separate out sil24_exec_polled_cmd() Tejun Heo
2006-05-11 16:43 ` [PATCH 04/10] libata-pm: hook PM support and enable it Tejun Heo
2006-05-11 16:43 ` [PATCH 01/10] libata-pm: add PM related constants, fields, ops and update helpers Tejun Heo
2006-05-11 16:43 ` [PATCH 09/10] sata_sil24: implement PM support Tejun Heo
2006-05-11 16:43 ` Tejun Heo [this message]
2006-05-11 16:43 ` [PATCH 08/10] sata_sil24: separate out sil24_do_softreset() Tejun Heo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=11473658232595-git-send-email-htejun@gmail.com \
    --to=htejun@gmail.com \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=albertcc@tw.ibm.com \
    --cc=axboe@suse.de \
    --cc=efalk@google.com \
    --cc=forrest.zhao@intel.com \
    --cc=jgarzik@pobox.com \
    --cc=linux-ide@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.