Skip to content

Commit

Permalink
[libata] pata_efar: add locking for parallel scanning
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Bartlomiej Zolnierkiewicz authored and Jeff Garzik committed Mar 1, 2010
1 parent 16ea0fc commit 303f1a7
Showing 1 changed file with 15 additions and 0 deletions.
15 changes: 15 additions & 0 deletions drivers/ata/pata_efar.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;

/*
Expand All @@ -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 */
Expand All @@ -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);
}

/**
Expand All @@ -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 */
Expand All @@ -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);

Expand Down Expand Up @@ -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 = {
Expand Down

0 comments on commit 303f1a7

Please sign in to comment.