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);
next prev 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).