linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Alexander Sabourenkov <screwdriver@lxnt.info>
To: Alexander Sabourenkov <screwdriver@lxnt.info>
Cc: linux-ide@vger.kernel.org, Tejun Heo <htejun@gmail.com>,
	MisterE <MisterE2002@zonnet.nl>,
	benh@kernel.crashing.org, jgarzik@pobox.com, jeff@garzik.org
Subject: [PATCH-RFC] Promise TX4 implement hw-bug workaround
Date: Sat, 27 Oct 2007 19:16:22 +0400	[thread overview]
Message-ID: <47235646.6050202@lxnt.info> (raw)
In-Reply-To: <472340D3.7090507@lxnt.info>

Hello.
Once again,

There appears to be a hardware bug in that it chokes on scatterlist
if the last item is larger than 164 bytes. This was discovered by
reading the code of vendor-supplied driver.

The patch that follows fixes my problem on 2.6.22.

I can't think of a way to avoid second pass over scatterlist without
duplicating code (ata_qc_prep() and ata_fill_sg() from libata-core.c).





--- a/drivers/ata/sata_promise.c	2007-07-09 03:32:17.000000000 +0400
+++ b/drivers/ata/sata_promise.c	2007-10-27 19:12:46.000000000 +0400
@@ -531,6 +531,87 @@
 	memcpy(buf+31, cdb, cdb_len);
 }

+/**
+ *	pdc_fill_sg - Fill PCI IDE PRD table
+ *	@qc: Metadata associated with taskfile to be transferred
+ *
+ *	Fill PCI IDE PRD (scatter-gather) table with segments
+ *	associated with the current disk command.
+ *	Make sure hardware does not choke on it.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ *
+ */
+static void pdc_fill_sg(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct scatterlist *sg;
+	unsigned int idx;
+	const u32 SG_COUNT_ASIC_BUG = 41*4;
+
+	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+		return;
+	
+	WARN_ON(qc->__sg == NULL);
+	WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
+
+	idx = 0;
+	ata_for_each_sg(sg, qc) {
+		u32 addr, offset;
+		u32 sg_len, len;
+
+		/* determine if physical DMA addr spans 64K boundary.
+		 * Note h/w doesn't support 64-bit, so we unconditionally
+		 * truncate dma_addr_t to u32.
+		 */
+		addr = (u32) sg_dma_address(sg);
+		sg_len = sg_dma_len(sg);
+
+		while (sg_len) {
+			offset = addr & 0xffff;
+			len = sg_len;
+			if ((offset + sg_len) > 0x10000)
+				len = 0x10000 - offset;
+
+			ap->prd[idx].addr = cpu_to_le32(addr);
+			ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
+			VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+
+			idx++;
+			sg_len -= len;
+			addr += len;
+		}
+	}
+
+	if (idx) {
+		u32 len = le32_to_cpu(ap->prd[idx - 1].flags_len);
+
+		if (len > SG_COUNT_ASIC_BUG) {
+			u32 addr;
+			/* if len < 2*SG_COUNT_ASIC_BUG then last
+			   segment will be larger than next-to-last.
+			   Somewhat ugly :(
+			*/
+
+			VPRINTK("Splitting last PRD.\n");
+
+			ap->prd[idx - 1].flags_len -= cpu_to_le32(SG_COUNT_ASIC_BUG);
+			VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG);
+			
+			addr = le32_to_cpu(ap->prd[idx - 1].addr) + len - SG_COUNT_ASIC_BUG;
+			len  = SG_COUNT_ASIC_BUG;
+			ap->prd[idx].addr = cpu_to_le32(addr);
+			ap->prd[idx].flags_len = cpu_to_le32(len);
+			VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+
+			idx++;
+		}
+
+		ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+	}
+}
+
 static void pdc_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct pdc_port_priv *pp = qc->ap->private_data;
@@ -540,7 +621,7 @@

 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA:
-		ata_qc_prep(qc);
+		pdc_fill_sg(qc);
 		/* fall through */

 	case ATA_PROT_NODATA:
@@ -556,11 +637,11 @@
 		break;

 	case ATA_PROT_ATAPI:
-		ata_qc_prep(qc);
+		pdc_fill_sg(qc);
 		break;

 	case ATA_PROT_ATAPI_DMA:
-		ata_qc_prep(qc);
+		pdc_fill_sg(qc);
 		/*FALLTHROUGH*/
 	case ATA_PROT_ATAPI_NODATA:
 		pdc_atapi_pkt(qc);


  parent reply	other threads:[~2007-10-27 15:26 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-10-03  7:26 Re[2]: Sata Sil3512 bug? Mikael Pettersson
2007-10-03  8:31 ` Alexander Sabourenkov
2007-10-03 14:45   ` Re[2]: " MisterE
2007-10-03 14:50     ` Alan Cox
2007-10-14 12:07   ` Re[2]: " MisterE
2007-10-15  8:44     ` Alexander Sabourenkov
2007-10-17 12:39   ` Re[2]: Sata Sil3512 bug?; Promise SATA300 TX4 MisterE
2007-10-17 12:54     ` Alexander Sabourenkov
2007-10-17 15:04       ` Re[2]: " MisterE
2007-10-17 19:21         ` Peter Favrholdt
2007-10-19 12:02           ` Re[2]: " MisterE
2007-10-18 21:07         ` Alexander Sabourenkov
2007-10-19  1:26           ` Tejun Heo
2007-10-19 21:06             ` Alexander Sabourenkov
2007-10-19 22:58               ` Re[2]: " MisterE
2007-10-19 23:58               ` Tejun Heo
2007-10-20 21:50                 ` Alexander Sabourenkov
2007-10-27 13:24                   ` [PATCH-RFC] (was: Re: Sata Sil3512 bug?; Promise SATA300 TX4) Alexander Sabourenkov
2007-10-27 13:44                     ` [PATCH-RFC] Alexander Sabourenkov
2007-10-27 14:08                       ` Re[2]: [PATCH-RFC] MisterE
2007-10-27 15:09                         ` [PATCH-RFC] Alexander Sabourenkov
2007-10-27 15:16                       ` Alexander Sabourenkov [this message]
2007-10-27 18:09                         ` [PATCH-RFC] Promise TX4 implement hw-bug workaround Alan Cox
2007-10-27 18:18                           ` Alexander Sabourenkov
2007-10-27 18:37                             ` Alexander Sabourenkov
2007-10-28  8:21                             ` Jeff Garzik
2007-10-28 20:03                               ` Alexander Sabourenkov
2007-10-28 10:29                         ` Jeff Garzik
2007-10-28 11:52                           ` Alexander Sabourenkov
2007-10-28 11:10                             ` Jeff Garzik
  -- strict thread matches above, loose matches on Subject: below --
2007-10-28 11:03 Mikael Pettersson
2007-10-28 16:32 Mikael Pettersson

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=47235646.6050202@lxnt.info \
    --to=screwdriver@lxnt.info \
    --cc=MisterE2002@zonnet.nl \
    --cc=benh@kernel.crashing.org \
    --cc=htejun@gmail.com \
    --cc=jeff@garzik.org \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).