Commit 303f1a76 authored by Bartlomiej Zolnierkiewicz's avatar Bartlomiej Zolnierkiewicz Committed by Jeff Garzik

[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 60c3be38 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: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>

This one is
Signed-off-by: default avatarAlan Cox <alan@linux.intel.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent 16ea0fc9
...@@ -68,6 +68,8 @@ static int efar_cable_detect(struct ata_port *ap) ...@@ -68,6 +68,8 @@ static int efar_cable_detect(struct ata_port *ap)
return ATA_CBL_PATA80; return ATA_CBL_PATA80;
} }
static DEFINE_SPINLOCK(efar_lock);
/** /**
* efar_set_piomode - Initialize host controller PATA PIO timings * efar_set_piomode - Initialize host controller PATA PIO timings
* @ap: Port whose timings we are configuring * @ap: Port whose timings we are configuring
...@@ -84,7 +86,9 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev) ...@@ -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; unsigned int pio = adev->pio_mode - XFER_PIO_0;
struct pci_dev *dev = to_pci_dev(ap->host->dev); struct pci_dev *dev = to_pci_dev(ap->host->dev);
unsigned int idetm_port= ap->port_no ? 0x42 : 0x40; unsigned int idetm_port= ap->port_no ? 0x42 : 0x40;
unsigned long flags;
u16 idetm_data; u16 idetm_data;
u8 udma_enable;
int control = 0; int control = 0;
/* /*
...@@ -107,6 +111,8 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev) ...@@ -107,6 +111,8 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
if (adev->class == ATA_DEV_ATA) if (adev->class == ATA_DEV_ATA)
control |= 4; /* PPE */ control |= 4; /* PPE */
spin_lock_irqsave(&efar_lock, flags);
pci_read_config_word(dev, idetm_port, &idetm_data); pci_read_config_word(dev, idetm_port, &idetm_data);
/* Set PPE, IE, and TIME as appropriate */ /* Set PPE, IE, and TIME as appropriate */
...@@ -131,6 +137,11 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev) ...@@ -131,6 +137,11 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
idetm_data |= 0x4000; /* Ensure SITRE is set */ idetm_data |= 0x4000; /* Ensure SITRE is set */
pci_write_config_word(dev, idetm_port, idetm_data); 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) ...@@ -151,6 +162,7 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
u16 master_data; u16 master_data;
u8 speed = adev->dma_mode; u8 speed = adev->dma_mode;
int devid = adev->devno + 2 * ap->port_no; int devid = adev->devno + 2 * ap->port_no;
unsigned long flags;
u8 udma_enable; u8 udma_enable;
static const /* ISP RTC */ static const /* ISP RTC */
...@@ -160,6 +172,8 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev) ...@@ -160,6 +172,8 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
{ 2, 1 }, { 2, 1 },
{ 2, 3 }, }; { 2, 3 }, };
spin_lock_irqsave(&efar_lock, flags);
pci_read_config_word(dev, master_port, &master_data); pci_read_config_word(dev, master_port, &master_data);
pci_read_config_byte(dev, 0x48, &udma_enable); 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) ...@@ -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_word(dev, master_port, master_data);
} }
pci_write_config_byte(dev, 0x48, udma_enable); pci_write_config_byte(dev, 0x48, udma_enable);
spin_unlock_irqrestore(&efar_lock, flags);
} }
static struct scsi_host_template efar_sht = { static struct scsi_host_template efar_sht = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment