pata_scc.c: Workaround for errata A308

Workaround for errata A308: turn down the UDMA mode and retry
the DMA command when the data lost condition is detected.

Signed-off-by: Kou Ishizaki <kou.ishizaki@toshiba.co.jp>
Signed-off-by: Akira Iguchi <akira2.iguchi@toshiba.co.jp>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
Akira Iguchi 2007-07-10 18:29:34 +09:00 committed by Jeff Garzik
parent a520f26146
commit fae57d3483

View file

@ -238,6 +238,12 @@ static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
else
offset = 0; /* 100MHz */
/* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
if (adev->class == ATA_DEV_ATAPI && speed > XFER_UDMA_4) {
printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
speed = XFER_UDMA_4;
}
if (speed >= XFER_UDMA_0)
idx = speed - XFER_UDMA_0;
else
@ -724,22 +730,36 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc)
static u8 scc_bmdma_status (struct ata_port *ap)
{
u8 host_stat;
void __iomem *mmio = ap->ioaddr.bmdma_addr;
u8 host_stat = in_be32(mmio + SCC_DMA_STATUS);
u32 int_status = in_be32(mmio + SCC_DMA_INTST);
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
static int retry = 0;
host_stat = in_be32(mmio + SCC_DMA_STATUS);
/* return if IOS_SS is cleared */
if (!(in_be32(mmio + SCC_DMA_CMD) & ATA_DMA_START))
return host_stat;
/* Workaround for PTERADD: emulate DMA_INTR when
* - IDE_STATUS[ERR] = 1
* - INT_STATUS[INTRQ] = 1
* - DMA_STATUS[IORACTA] = 1
*/
if (!(host_stat & ATA_DMA_INTR)) {
u32 int_status = in_be32(mmio + SCC_DMA_INTST);
if (ata_altstatus(ap) & ATA_ERR &&
int_status & INTSTS_INTRQ &&
host_stat & ATA_DMA_ACTIVE)
host_stat |= ATA_DMA_INTR;
/* errata A252,A308 workaround: Step4 */
if (ata_altstatus(ap) & ATA_ERR && int_status & INTSTS_INTRQ)
return (host_stat | ATA_DMA_INTR);
/* errata A308 workaround Step5 */
if (int_status & INTSTS_IOIRQS) {
host_stat |= ATA_DMA_INTR;
/* We don't check ATAPI DMA because it is limited to UDMA4 */
if ((qc->tf.protocol == ATA_PROT_DMA &&
qc->dev->xfer_mode > XFER_UDMA_4)) {
if (!(int_status & INTSTS_ACTEINT)) {
printk(KERN_WARNING "ata%u: data lost occurred. (ACTEINT==0, retry:%d)\n",
ap->print_id, retry);
host_stat |= ATA_DMA_ERR;
if (retry++)
ap->udma_mask >>= 1;
} else
retry = 0;
}
}
return host_stat;