Commit cbda3cb1 authored by ananth@broadcom.com's avatar ananth@broadcom.com Committed by Jeff Garzik

[libata sata_svw] race condition fix, new device support

* address race condition WRT order of DMA-start and ATA command issue
  (see code comment for more details)

* Add support for Frodo 4/8
parent b006f041
...@@ -148,6 +148,72 @@ static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) ...@@ -148,6 +148,72 @@ static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
} }
} }
/**
* k2_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction (MMIO)
* @qc: Info associated with this ATA transaction.
*
* LOCKING:
* spin_lock_irqsave(host_set lock)
*/
void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
u8 dmactl;
void *mmio = (void *) ap->ioaddr.bmdma_addr;
/* load PRD table addr. */
mb(); /* make sure PRD table writes are visible to controller */
writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
/* specify data direction, triple-check start bit is clear */
dmactl = readb(mmio + ATA_DMA_CMD);
dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
if (!rw)
dmactl |= ATA_DMA_WR;
writeb(dmactl, mmio + ATA_DMA_CMD);
/* issue r/w command if this is not a ATA DMA command*/
if (qc->tf.protocol != ATA_PROT_DMA)
ap->ops->exec_command(ap, &qc->tf);
}
/**
* k2_bmdma_start_mmio - Start a PCI IDE BMDMA transaction (MMIO)
* @qc: Info associated with this ATA transaction.
*
* LOCKING:
* spin_lock_irqsave(host_set lock)
*/
void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
void *mmio = (void *) ap->ioaddr.bmdma_addr;
u8 dmactl;
/* start host DMA transaction */
dmactl = readb(mmio + ATA_DMA_CMD);
writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
/* There is a race condition in certain SATA controllers that can
be seen when the r/w command is given to the controller before the
host DMA is started. On a Read command, the controller would initiate
the command to the drive even before it sees the DMA start. When there
are very fast drives connected to the controller, or when the data request
hits in the drive cache, there is the possibility that the drive returns a part
or all of the requested data to the controller before the DMA start is issued.
In this case, the controller would become confused as to what to do with the data.
In the worst case when all the data is returned back to the controller, the
controller could hang. In other cases it could return partial data returning
in data corruption. This problem has been seen in PPC systems and can also appear
on an system with very fast disks, where the SATA controller is sitting behind a
number of bridges, and hence there is significant latency between the r/w command
and the start command. */
/* issue r/w command if the access is to ATA*/
if (qc->tf.protocol == ATA_PROT_DMA)
ap->ops->exec_command(ap, &qc->tf);
}
static u8 k2_stat_check_status(struct ata_port *ap) static u8 k2_stat_check_status(struct ata_port *ap)
{ {
...@@ -232,8 +298,8 @@ static struct ata_port_operations k2_sata_ops = { ...@@ -232,8 +298,8 @@ static struct ata_port_operations k2_sata_ops = {
.check_status = k2_stat_check_status, .check_status = k2_stat_check_status,
.exec_command = ata_exec_command, .exec_command = ata_exec_command,
.phy_reset = sata_phy_reset, .phy_reset = sata_phy_reset,
.bmdma_setup = ata_bmdma_setup, .bmdma_setup = k2_bmdma_setup_mmio,
.bmdma_start = ata_bmdma_start, .bmdma_start = k2_bmdma_start_mmio,
.qc_prep = ata_qc_prep, .qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot, .qc_issue = ata_qc_issue_prot,
.eng_timeout = ata_eng_timeout, .eng_timeout = ata_eng_timeout,
...@@ -373,6 +439,8 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e ...@@ -373,6 +439,8 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
static struct pci_device_id k2_sata_pci_tbl[] = { static struct pci_device_id k2_sata_pci_tbl[] = {
{ 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ } { }
}; };
......
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