aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2007-03-03 22:48:08 -0500
committerJeff Garzik <jeff@garzik.org>2007-03-06 04:04:30 -0500
commit63ed71019c4437caef65fca1f83c990ae729024f (patch)
tree27ff3f4c907c34702ca4eb111175132a6816fdd8 /drivers/ata
parent8b966dddc29899008fb178a533263afa8d1ad849 (diff)
pata_pdc202xx_old: fix data corruption and other problems
Fix wrong "port" calculations in pdc202xx_{configure_piomode,set_dmamode}() They were broken for all configurations except one (master device on primary channel, no other devices) and as a result device settings + PIO/DMA timings were being programmed into the wrong PCI registers. This could result in a large variety of problems including data corruption, hangs etc. (depending on devices used and your luck :-). ap->port_no ap->devno used PCI registers correct PCI registers 0 0 0x60-0x62 0x60-0x62 0 1 0x62-0x64 0x64-0x66 1 0 0x64-0x66 0x68-0x6a 1 1 0x66-0x68 0x6c-0x6e Also forward port recent fixes from drivers/ide pdc202xx_old driver: * fix XFER_MW_DMA0 timings (they were overclocked, use the official ones) * fix bitmasks for clearing bits of register B: - when programming DMA mode bit 0x10 of register B was cleared which resulted in overclocked PIO timing setting (iff PIO0 was used) - when programming PIO mode bits 0x18 weren't cleared so suboptimal timings were used for PIO1-4 if PIO0 was previously set (bit 0x10) and for PIO0/3/4 if PIO1/2 was previously set (bit 0x08) and finally bump driver version. Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/pata_pdc202xx_old.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index 3fb417780166..acdc52cbe38a 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -2,13 +2,14 @@
2 * pata_pdc202xx_old.c - Promise PDC202xx PATA for new ATA layer 2 * pata_pdc202xx_old.c - Promise PDC202xx PATA for new ATA layer
3 * (C) 2005 Red Hat Inc 3 * (C) 2005 Red Hat Inc
4 * Alan Cox <alan@redhat.com> 4 * Alan Cox <alan@redhat.com>
5 * (C) 2007 Bartlomiej Zolnierkiewicz
5 * 6 *
6 * Based in part on linux/drivers/ide/pci/pdc202xx_old.c 7 * Based in part on linux/drivers/ide/pci/pdc202xx_old.c
7 * 8 *
8 * First cut with LBA48/ATAPI 9 * First cut with LBA48/ATAPI
9 * 10 *
10 * TODO: 11 * TODO:
11 * Channel interlock/reset on both required ? 12 * Channel interlock/reset on both required
12 */ 13 */
13 14
14#include <linux/kernel.h> 15#include <linux/kernel.h>
@@ -21,7 +22,7 @@
21#include <linux/libata.h> 22#include <linux/libata.h>
22 23
23#define DRV_NAME "pata_pdc202xx_old" 24#define DRV_NAME "pata_pdc202xx_old"
24#define DRV_VERSION "0.3.0" 25#define DRV_VERSION "0.4.0"
25 26
26/** 27/**
27 * pdc2024x_pre_reset - probe begin 28 * pdc2024x_pre_reset - probe begin
@@ -76,7 +77,7 @@ static void pdc2026x_error_handler(struct ata_port *ap)
76static void pdc202xx_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio) 77static void pdc202xx_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio)
77{ 78{
78 struct pci_dev *pdev = to_pci_dev(ap->host->dev); 79 struct pci_dev *pdev = to_pci_dev(ap->host->dev);
79 int port = 0x60 + 4 * ap->port_no + 2 * adev->devno; 80 int port = 0x60 + 8 * ap->port_no + 4 * adev->devno;
80 static u16 pio_timing[5] = { 81 static u16 pio_timing[5] = {
81 0x0913, 0x050C , 0x0308, 0x0206, 0x0104 82 0x0913, 0x050C , 0x0308, 0x0206, 0x0104
82 }; 83 };
@@ -85,7 +86,7 @@ static void pdc202xx_configure_piomode(struct ata_port *ap, struct ata_device *a
85 pci_read_config_byte(pdev, port, &r_ap); 86 pci_read_config_byte(pdev, port, &r_ap);
86 pci_read_config_byte(pdev, port + 1, &r_bp); 87 pci_read_config_byte(pdev, port + 1, &r_bp);
87 r_ap &= ~0x3F; /* Preserve ERRDY_EN, SYNC_IN */ 88 r_ap &= ~0x3F; /* Preserve ERRDY_EN, SYNC_IN */
88 r_bp &= ~0x07; 89 r_bp &= ~0x1F;
89 r_ap |= (pio_timing[pio] >> 8); 90 r_ap |= (pio_timing[pio] >> 8);
90 r_bp |= (pio_timing[pio] & 0xFF); 91 r_bp |= (pio_timing[pio] & 0xFF);
91 92
@@ -123,7 +124,7 @@ static void pdc202xx_set_piomode(struct ata_port *ap, struct ata_device *adev)
123static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) 124static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev)
124{ 125{
125 struct pci_dev *pdev = to_pci_dev(ap->host->dev); 126 struct pci_dev *pdev = to_pci_dev(ap->host->dev);
126 int port = 0x60 + 4 * ap->port_no + 2 * adev->devno; 127 int port = 0x60 + 8 * ap->port_no + 4 * adev->devno;
127 static u8 udma_timing[6][2] = { 128 static u8 udma_timing[6][2] = {
128 { 0x60, 0x03 }, /* 33 Mhz Clock */ 129 { 0x60, 0x03 }, /* 33 Mhz Clock */
129 { 0x40, 0x02 }, 130 { 0x40, 0x02 },
@@ -132,12 +133,17 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev)
132 { 0x20, 0x01 }, 133 { 0x20, 0x01 },
133 { 0x20, 0x01 } 134 { 0x20, 0x01 }
134 }; 135 };
136 static u8 mdma_timing[3][2] = {
137 { 0x60, 0x03 },
138 { 0x60, 0x04 },
139 { 0xe0, 0x0f },
140 };
135 u8 r_bp, r_cp; 141 u8 r_bp, r_cp;
136 142
137 pci_read_config_byte(pdev, port + 1, &r_bp); 143 pci_read_config_byte(pdev, port + 1, &r_bp);
138 pci_read_config_byte(pdev, port + 2, &r_cp); 144 pci_read_config_byte(pdev, port + 2, &r_cp);
139 145
140 r_bp &= ~0xF0; 146 r_bp &= ~0xE0;
141 r_cp &= ~0x0F; 147 r_cp &= ~0x0F;
142 148
143 if (adev->dma_mode >= XFER_UDMA_0) { 149 if (adev->dma_mode >= XFER_UDMA_0) {
@@ -147,8 +153,8 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev)
147 153
148 } else { 154 } else {
149 int speed = adev->dma_mode - XFER_MW_DMA_0; 155 int speed = adev->dma_mode - XFER_MW_DMA_0;
150 r_bp |= 0x60; 156 r_bp |= mdma_timing[speed][0];
151 r_cp |= (5 - speed); 157 r_cp |= mdma_timing[speed][1];
152 } 158 }
153 pci_write_config_byte(pdev, port + 1, r_bp); 159 pci_write_config_byte(pdev, port + 1, r_bp);
154 pci_write_config_byte(pdev, port + 2, r_cp); 160 pci_write_config_byte(pdev, port + 2, r_cp);