From: Alexander Sabourenkov <screwdriver@lxnt.info>
To: linux-ide@vger.kernel.org
Cc: Tejun Heo <htejun@gmail.com>, MisterE <MisterE2002@zonnet.nl>,
benh@kernel.crashing.org, jgarzik@pobox.com, jeff@garzik.org
Subject: [PATCH-RFC] (was: Re: Sata Sil3512 bug?; Promise SATA300 TX4)
Date: Sat, 27 Oct 2007 17:24:32 +0400 [thread overview]
Message-ID: <47233C10.4020100@lxnt.info> (raw)
In-Reply-To: <471A783E.9060607@lxnt.info>
Hello.
There appears to be a hardware bug in that it chokes on scatterlist
if the last item is larger than 164 bytes.
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 17:20:03.000000000 +0400
@@ -531,6 +531,80 @@
memcpy(buf+31, cdb, cdb_len);
}
+/**
+ * pdc_qc_prep - 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_qc_prep(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 = ap->prd[idx - 1].flags_len;
+ if (len > SG_COUNT_ASIC_BUG) {
+ u32 addr, len;
+
+ VPRINTK("Last PRD split\n");
+
+ len = le32_to_cpu(ap->prd[idx - 1].flags_len) - SG_COUNT_ASIC_BUG;
+ addr = le32_to_cpu(ap->prd[idx - 1].addr);
+ ap->prd[idx - 1].flags_len = cpu_to_le32(len);
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+
+ ap->prd[idx].flags_len = cpu_to_le32(SG_COUNT_ASIC_BUG);
+ ap->prd[idx].addr = cpu_to_le32(addr + len);
+ idx++;
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr + len, SG_COUNT_ASIC_BUG);
+ }
+ 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 +614,7 @@
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
- ata_qc_prep(qc);
+ pdc_qc_prep(qc);
/* fall through */
case ATA_PROT_NODATA:
next prev parent reply other threads:[~2007-10-27 13:34 UTC|newest]
Thread overview: 31+ 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 ` Alexander Sabourenkov [this message]
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 ` [PATCH-RFC] Promise TX4 implement hw-bug workaround Alexander Sabourenkov
2007-10-27 18:09 ` 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-27 14:53 [PATCH-RFC] (was: Re: Sata Sil3512 bug?; Promise SATA300 TX4) 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=47233C10.4020100@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).