Thread (5 messages) flat view 5 messages, 4 authors, 2012-09-10

Re: [PATCH][v3] sata_fsl: add workaround for data length mismatch on freescale V2 controller

From: Kumar Gala <hidden>
Date: 2012-09-07 12:38:07
Also in: linux-ide, lkml

On Sep 7, 2012, at 5:01 AM, Shaohui Xie wrote:
The freescale V2 SATA controller checks if the received data length =
matches
the programmed length 'ttl', if not, it assumes that this is an error.
In ATAPI, the 'ttl' is based on max allocation length and not the =
actual
data transfer length, controller will raise 'DLM' (Data length =
Mismatch)
error bit in Hstatus register. Along with 'DLM', DE (Device error) and
FE (fatal Error) bits are also set in Hstatus register, 'E' (Internal =
Error)
bit is set in Serror register and CE (Command Error) and DE (Device =
error)
registers have the corresponding bit set. In this condition, we need =
to
clear errors in following way: in the service routine, based on 'DLM' =
flag,
HCONTROL[27] operation clears Hstatus, CE and DE registers, clear =
Serror
quoted hunk ↗ jump to hunk
register.
=20
Signed-off-by: Shaohui Xie <redacted>
Signed-off-by: Anju Bhartiya <redacted>
---
changes for v3:
1. not using uppercase for variable names;
2. remove unnecessary parens;
=20
changes for v2:
1. remove the using of quirk;
2. wrap errata codes in condition;
=20
drivers/ata/sata_fsl.c |   39 +++++++++++++++++++++++++++++++++++----
1 files changed, 35 insertions(+), 4 deletions(-)
=20
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index d6577b9..9fbab68 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -143,6 +143,7 @@ enum {
	    FATAL_ERR_CRC_ERR_RX |
	    FATAL_ERR_FIFO_OVRFL_TX | FATAL_ERR_FIFO_OVRFL_RX,
=20
+	INT_ON_DATA_LENGTH_MISMATCH =3D (1 << 12),
	INT_ON_FATAL_ERR =3D (1 << 5),
	INT_ON_PHYRDY_CHG =3D (1 << 4),
=20
@@ -1181,25 +1182,55 @@ static void sata_fsl_host_intr(struct ata_port =
*ap)
	u32 hstatus, done_mask =3D 0;
	struct ata_queued_cmd *qc;
	u32 SError;
+	u32 tag;
+	u32 status_mask =3D INT_ON_ERROR;
=20
	hstatus =3D ioread32(hcr_base + HSTATUS);
=20
	sata_fsl_scr_read(&ap->link, SCR_ERROR, &SError);
=20
+	/* Read command completed register */
+	done_mask =3D ioread32(hcr_base + CC);
+
+	/* Workaround for data length mismatch errata */
+	if (unlikely(hstatus & INT_ON_DATA_LENGTH_MISMATCH)) {
+		for (tag =3D 0; tag < ATA_MAX_QUEUE; tag++) {
+			qc =3D ata_qc_from_tag(ap, tag);
+			if (qc && ata_is_atapi(qc->tf.protocol)) {
+				u32 hcontrol;
+#define HCONTROL_CLEAR_ERROR	(1 << 27)
shouldn't we have this #define be part of the enum that the other =
HCONTROL_ bits/flags are part of?
+				/* Set HControl[27] to clear error =
registers */
+				hcontrol =3D ioread32(hcr_base + =
HCONTROL);
+				iowrite32(hcontrol | =
HCONTROL_CLEAR_ERROR,
+						hcr_base + HCONTROL);
+
+				/* Clear HControl[27] */
+				iowrite32(hcontrol & =
~HCONTROL_CLEAR_ERROR,
+						hcr_base + HCONTROL);
+
+				/* Clear SError[E] bit */
+				sata_fsl_scr_write(&ap->link, SCR_ERROR,
+						SError);
+
+				/* Ignore fatal error and device error =
*/
+				status_mask &=3D =
~(INT_ON_SINGL_DEVICE_ERR
+						| INT_ON_FATAL_ERR);
+				break;
+			}
+		}
+	}
+
	if (unlikely(SError & 0xFFFF0000)) {
		DPRINTK("serror @host_intr : 0x%x\n", SError);
		sata_fsl_error_intr(ap);
	}
=20
-	if (unlikely(hstatus & INT_ON_ERROR)) {
+	if (unlikely(hstatus & status_mask)) {
		DPRINTK("error interrupt!!\n");
		sata_fsl_error_intr(ap);
		return;
	}
=20
-	/* Read command completed register */
-	done_mask =3D ioread32(hcr_base + CC);
-
	VPRINTK("Status of all queues :\n");
	VPRINTK("done_mask/CC =3D 0x%x, CA =3D 0x%x, =
CE=3D0x%x,CQ=3D0x%x,apqa=3D0x%x\n",
		done_mask,
--=20
1.6.4
=20
=20
--
To unsubscribe from this list: send the line "unsubscribe =
linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help