Re: sata_sil, writing bug with multiple cards?

From: Tejun Heo
Date: Tue Jul 10 2007 - 06:56:16 EST


Tejun Heo wrote:
> Andi Kleen wrote:
>> On Wednesday 04 July 2007 10:17:34 7091@xxxxxxxxxx wrote:
>>
>>>> Most likely it is some sort of hardware bug that we might
>>>> not be able to do much about. Have you tried contacting SIL or VIA?
>>> No, I haven't. Like I mentioned above, the OpenBSD drivers seemed to work,
>>> or at least did with similar tests. I would need to run the more extensive
>>> checks to be positive, but those take a lot of time, obviously. And
>>> downtime for the box, a lot of which isn't really manageable, at the moment.
>> Perhaps the OpenBSD drivers program the SIL chip in a different way
>> that avoids this problem.
>>
>>>> e.g. if you have some other system with a different chipset it might
>>>> be useful to test the SIL controllers in those.
>>> The previous motherboard was an AMD 760 chipset, and it had the same
>>> problem.
>> Ok this means it's likely a SIL issue, not a chipset issue.
>
> Hmmmm... okay. I'll take look at the openBSD driver. I still have no
> idea what it can be tho. Maybe, FIFO setup?

Please give a shot at the attached patch on top of 2.6.22. Thanks.

--
tejun
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 2a86dc4..6c0fe7e 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -280,14 +280,6 @@ static int slow_down = 0;
module_param(slow_down, int, 0444);
MODULE_PARM_DESC(slow_down, "Sledgehammer used to work around random problems, by limiting commands to 15 sectors (0=off, 1=on)");

-
-static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
-{
- u8 cache_line = 0;
- pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line);
- return cache_line;
-}
-
/**
* sil_set_mode - wrap set_mode functions
* @ap: port to set up
@@ -597,17 +589,29 @@ static void sil_init_controller(struct ata_host *host)
u32 tmp;
int i;

- /* Initialize FIFO PCI bus arbitration */
- cls = sil_get_device_cache_line(pdev);
- if (cls) {
- cls >>= 3;
- cls++; /* cls = (line_size/8)+1 */
- for (i = 0; i < host->n_ports; i++)
- writew(cls << 8 | cls,
- mmio_base + sil_port[i].fifo_cfg);
- } else
- dev_printk(KERN_WARNING, &pdev->dev,
- "cache line size not set. Driver may not function\n");
+ /* When the Silicon Image 3112/4 retries a PCI memory read
+ * command, it may retry it as a memory read multiple command
+ * under some circumstances. This can totally confuse some
+ * PCI controllers, so ensure that it will never do this by
+ * making sure that the Read Threshold (FIFO Read Request
+ * Control) field of the FIFO Valid Byte Count and Control
+ * registers for all the channels are set to be at least as
+ * large as the cacheline size register.
+ *
+ * tj - code and comment shamelessly taken from NetBSD.
+ */
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls);
+ cls *= 4;
+
+ if (cls > 224) {
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 224 / 4);
+ cls = 224;
+ } else if (cls < 32)
+ cls = 32;
+
+ cls = DIV_ROUND_UP(cls, 32);
+ for (i = 0; i < host->n_ports; i++)
+ writeb(cls, mmio_base + sil_port[i].fifo_cfg);

/* Apply R_ERR on DMA activate FIS errata workaround */
if (host->ports[0]->flags & SIL_FLAG_RERR_ON_DMA_ACT) {