aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-02-24 23:52:30 -0500
committerJeff Garzik <jeff@garzik.org>2006-02-25 16:52:31 -0500
commite4e10e3e7995f5bd481d2720bf30d3a661d110ca (patch)
tree14dbbab4fcc8c2fd10376751516c2f0088459247 /drivers/scsi
parent0ee304d5802dc62746f13f12d4cb4ec4ed285f66 (diff)
[PATCH] sata_sil: implement R_ERR on DMA activate FIS errata fix
Silicon Image has disclosed a new sil3114/3152 errata and workaround which causes the controller to return R_ERR on DMA activate FIS if the FIS is received while the next PRD is being fetched. This patch implements the workaround. This errata results in lock up and doesn't trigger if m15w workaround is in effect. We stopped applying m15w to 3512 and 3114 in 2.6.14-rc1 which makes 3512/3114 lock up with some drives on all kernel versions since 2.6.14-rc1 upto now (2.6.16-rc4). This patch should fix the regression. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/sata_sil.c33
1 files changed, 27 insertions, 6 deletions
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 510c2e0bd90e..9face3c6aa21 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -49,6 +49,7 @@
49#define DRV_VERSION "0.9" 49#define DRV_VERSION "0.9"
50 50
51enum { 51enum {
52 SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
52 SIL_FLAG_MOD15WRITE = (1 << 30), 53 SIL_FLAG_MOD15WRITE = (1 << 30),
53 54
54 sil_3112 = 0, 55 sil_3112 = 0,
@@ -202,7 +203,8 @@ static const struct ata_port_info sil_port_info[] = {
202 { 203 {
203 .sht = &sil_sht, 204 .sht = &sil_sht,
204 .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 205 .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
205 ATA_FLAG_SRST | ATA_FLAG_MMIO, 206 ATA_FLAG_SRST | ATA_FLAG_MMIO |
207 SIL_FLAG_RERR_ON_DMA_ACT,
206 .pio_mask = 0x1f, /* pio0-4 */ 208 .pio_mask = 0x1f, /* pio0-4 */
207 .mwdma_mask = 0x07, /* mwdma0-2 */ 209 .mwdma_mask = 0x07, /* mwdma0-2 */
208 .udma_mask = 0x3f, /* udma0-5 */ 210 .udma_mask = 0x3f, /* udma0-5 */
@@ -212,7 +214,8 @@ static const struct ata_port_info sil_port_info[] = {
212 { 214 {
213 .sht = &sil_sht, 215 .sht = &sil_sht,
214 .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 216 .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
215 ATA_FLAG_SRST | ATA_FLAG_MMIO, 217 ATA_FLAG_SRST | ATA_FLAG_MMIO |
218 SIL_FLAG_RERR_ON_DMA_ACT,
216 .pio_mask = 0x1f, /* pio0-4 */ 219 .pio_mask = 0x1f, /* pio0-4 */
217 .mwdma_mask = 0x07, /* mwdma0-2 */ 220 .mwdma_mask = 0x07, /* mwdma0-2 */
218 .udma_mask = 0x3f, /* udma0-5 */ 221 .udma_mask = 0x3f, /* udma0-5 */
@@ -229,12 +232,13 @@ static const struct {
229 unsigned long scr; /* SATA control register block */ 232 unsigned long scr; /* SATA control register block */
230 unsigned long sien; /* SATA Interrupt Enable register */ 233 unsigned long sien; /* SATA Interrupt Enable register */
231 unsigned long xfer_mode;/* data transfer mode register */ 234 unsigned long xfer_mode;/* data transfer mode register */
235 unsigned long sfis_cfg; /* SATA FIS reception config register */
232} sil_port[] = { 236} sil_port[] = {
233 /* port 0 ... */ 237 /* port 0 ... */
234 { 0x80, 0x8A, 0x00, 0x100, 0x148, 0xb4 }, 238 { 0x80, 0x8A, 0x00, 0x100, 0x148, 0xb4, 0x14c },
235 { 0xC0, 0xCA, 0x08, 0x180, 0x1c8, 0xf4 }, 239 { 0xC0, 0xCA, 0x08, 0x180, 0x1c8, 0xf4, 0x1cc },
236 { 0x280, 0x28A, 0x200, 0x300, 0x348, 0x2b4 }, 240 { 0x280, 0x28A, 0x200, 0x300, 0x348, 0x2b4, 0x34c },
237 { 0x2C0, 0x2CA, 0x208, 0x380, 0x3c8, 0x2f4 }, 241 { 0x2C0, 0x2CA, 0x208, 0x380, 0x3c8, 0x2f4, 0x3cc },
238 /* ... port 3 */ 242 /* ... port 3 */
239}; 243};
240 244
@@ -484,6 +488,23 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
484 dev_printk(KERN_WARNING, &pdev->dev, 488 dev_printk(KERN_WARNING, &pdev->dev,
485 "cache line size not set. Driver may not function\n"); 489 "cache line size not set. Driver may not function\n");
486 490
491 /* Apply R_ERR on DMA activate FIS errata workaround */
492 if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
493 int cnt;
494
495 for (i = 0, cnt = 0; i < probe_ent->n_ports; i++) {
496 tmp = readl(mmio_base + sil_port[i].sfis_cfg);
497 if ((tmp & 0x3) != 0x01)
498 continue;
499 if (!cnt)
500 dev_printk(KERN_INFO, &pdev->dev,
501 "Applying R_ERR on DMA activate "
502 "FIS errata fix\n");
503 writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
504 cnt++;
505 }
506 }
507
487 if (ent->driver_data == sil_3114) { 508 if (ent->driver_data == sil_3114) {
488 irq_mask = SIL_MASK_4PORT; 509 irq_mask = SIL_MASK_4PORT;
489 510