[PATCH-RFC] (was: Re: Sata Sil3512 bug?; Promise SATA300 TX4)

2007-10-27 Thread Alexander Sabourenkov
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.c2007-07-09 03:32:17.0 +0400
+++ b/drivers/ata/sata_promise.c2007-10-27 17:20:03.0 +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 & 0x;
+   len = sg_len;
+   if ((offset + sg_len) > 0x1)
+   len = 0x1 - offset;
+
+   ap->prd[idx].addr = cpu_to_le32(addr);
+   ap->prd[idx].flags_len = cpu_to_le32(len & 0x);
+   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:

-
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH-RFC] (was: Re: Sata Sil3512 bug?; Promise SATA300 TX4)

2007-10-27 Thread Mikael Pettersson
On Sat, 27 Oct 2007 17:24:32 +0400, Alexander Sabourenkov wrote:
> 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.0 +0400
> +++ b/drivers/ata/sata_promise.c  2007-10-27 17:20:03.0 +0400

Interesting, but can you please give more background information?
I.e., how did you determine the existence of this bug?

And please cc: the sata_promise maintainer on sata_promise patches.
(Hint: that's me)

And please choose a Subject: that makes it absolutely clear what
the post is about. "Sata Sil3512 bug" doesn't exactly sound like
something the sata_promise maintainer needs to look at.

Meanwhile I'll check the Promise driver(s) to see if there's
something about SG table formatting restrictions there.

/Mikael
-
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html