CentOS-5 patch: sata_via fix FIFO issue on vt6420/vt6421 CentOS bug #4864 Applied by Akemi Yagi <toracat@centos.org> Adopted from ELRepo's kmod-sata_via patch. 2010-11-19 Tejun Heo sata_via: apply magic FIFO fix to vt6420 too 2010-06-02 Tejun Heo sata_via: magic vt6421 fix for transmission problems... 2010-06-07 Tejun Heo sata_via: explain the magic fix --- a/drivers/ata/sata_via.c.dist 2011-05-31 12:54:42.000000000 -0700 +++ a/drivers/ata/sata_via.c 2011-05-31 14:08:29.000000000 -0700 @@ -367,7 +367,7 @@ return 0; } -static void svia_configure(struct pci_dev *pdev) +static void svia_configure(struct pci_dev *pdev, int board_id) { u8 tmp8; @@ -404,6 +404,34 @@ tmp8 |= NATIVE_MODE_ALL; pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); } + + /* + * vt6420/1 has problems talking to some drives. The following + * is the fix from Joseph Chan <JosephChan@via.com.tw>. + * + * When host issues HOLD, device may send up to 20DW of data + * before acknowledging it with HOLDA and the host should be + * able to buffer them in FIFO. Unfortunately, some WD drives + * send upto 40DW before acknowledging HOLD and, in the + * default configuration, this ends up overflowing vt6421's + * FIFO, making the controller abort the transaction with + * R_ERR. + * + * Rx52[2] is the internal 128DW FIFO Flow control watermark + * adjusting mechanism enable bit and the default value 0 + * means host will issue HOLD to device when the left FIFO + * size goes below 32DW. Setting it to 1 makes the watermark + * 64DW. + * + * https://bugzilla.kernel.org/show_bug.cgi?id=15173 + * http://article.gmane.org/gmane.linux.ide/46352 + * http://thread.gmane.org/gmane.linux.kernel/1062139 + */ + if (board_id == vt6420 || board_id == vt6421) { + pci_read_config_byte(pdev, 0x52, &tmp8); + tmp8 |= 1 << 2; + pci_write_config_byte(pdev, 0x52, tmp8); + } } static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -445,7 +473,7 @@ if (rc) return rc; - svia_configure(pdev); + svia_configure(pdev, board_id); pci_set_master(pdev); return ata_host_activate(host, pdev->irq, ata_sff_interrupt,