summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2010-02-17 16:16:58 +0300
committerJeff Garzik <jgarzik@redhat.com>2010-03-01 23:04:58 +0300
commit303f1a76ae792885af8a4a0e784e22e31e850e9a (patch)
treed390d5ca09c5fc0ddb8ac3c1d09361c1bfa3a1f5
parent16ea0fc98d53c72cb4e1a9edcb685a87e3a81430 (diff)
downloadlinux-303f1a76ae792885af8a4a0e784e22e31e850e9a.tar.xz
[libata] pata_efar: add locking for parallel scanning
Add clearing of UDMA enable bit also for PIO modes and then add extra locking for parallel scanning. This is similar change as commit 60c3be3 for ata_piix host driver and while pata_efar doesn't enable parallel scan yet the race could probably also be triggered by requesting re-scanning of both ports at the same time using SCSI sysfs interface. [Ported to current kernel without other patch dependancies by Alan Cox] Original is Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> This one is Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
-rw-r--r--drivers/ata/pata_efar.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index 5556163c80de..1617421f7e76 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -68,6 +68,8 @@ static int efar_cable_detect(struct ata_port *ap)
return ATA_CBL_PATA80;
}
+static DEFINE_SPINLOCK(efar_lock);
+
/**
* efar_set_piomode - Initialize host controller PATA PIO timings
* @ap: Port whose timings we are configuring
@@ -84,7 +86,9 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
unsigned int pio = adev->pio_mode - XFER_PIO_0;
struct pci_dev *dev = to_pci_dev(ap->host->dev);
unsigned int idetm_port= ap->port_no ? 0x42 : 0x40;
+ unsigned long flags;
u16 idetm_data;
+ u8 udma_enable;
int control = 0;
/*
@@ -107,6 +111,8 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
if (adev->class == ATA_DEV_ATA)
control |= 4; /* PPE */
+ spin_lock_irqsave(&efar_lock, flags);
+
pci_read_config_word(dev, idetm_port, &idetm_data);
/* Set PPE, IE, and TIME as appropriate */
@@ -131,6 +137,11 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
idetm_data |= 0x4000; /* Ensure SITRE is set */
pci_write_config_word(dev, idetm_port, idetm_data);
+
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+ udma_enable &= ~(1 << (2 * ap->port_no + adev->devno));
+ pci_write_config_byte(dev, 0x48, udma_enable);
+ spin_unlock_irqrestore(&efar_lock, flags);
}
/**
@@ -151,6 +162,7 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
u16 master_data;
u8 speed = adev->dma_mode;
int devid = adev->devno + 2 * ap->port_no;
+ unsigned long flags;
u8 udma_enable;
static const /* ISP RTC */
@@ -160,6 +172,8 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
{ 2, 1 },
{ 2, 3 }, };
+ spin_lock_irqsave(&efar_lock, flags);
+
pci_read_config_word(dev, master_port, &master_data);
pci_read_config_byte(dev, 0x48, &udma_enable);
@@ -217,6 +231,7 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
pci_write_config_word(dev, master_port, master_data);
}
pci_write_config_byte(dev, 0x48, udma_enable);
+ spin_unlock_irqrestore(&efar_lock, flags);
}
static struct scsi_host_template efar_sht = {