aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/pata_scc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata/pata_scc.c')
-rw-r--r--drivers/ata/pata_scc.c54
1 files changed, 35 insertions, 19 deletions
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index 61502bc7bf1d..c55667e0eb65 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -238,6 +238,12 @@ static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
238 else 238 else
239 offset = 0; /* 100MHz */ 239 offset = 0; /* 100MHz */
240 240
241 /* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
242 if (adev->class == ATA_DEV_ATAPI && speed > XFER_UDMA_4) {
243 printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
244 speed = XFER_UDMA_4;
245 }
246
241 if (speed >= XFER_UDMA_0) 247 if (speed >= XFER_UDMA_0)
242 idx = speed - XFER_UDMA_0; 248 idx = speed - XFER_UDMA_0;
243 else 249 else
@@ -724,22 +730,36 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc)
724 730
725static u8 scc_bmdma_status (struct ata_port *ap) 731static u8 scc_bmdma_status (struct ata_port *ap)
726{ 732{
727 u8 host_stat;
728 void __iomem *mmio = ap->ioaddr.bmdma_addr; 733 void __iomem *mmio = ap->ioaddr.bmdma_addr;
729 734 u8 host_stat = in_be32(mmio + SCC_DMA_STATUS);
730 host_stat = in_be32(mmio + SCC_DMA_STATUS); 735 u32 int_status = in_be32(mmio + SCC_DMA_INTST);
731 736 struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
732 /* Workaround for PTERADD: emulate DMA_INTR when 737 static int retry = 0;
733 * - IDE_STATUS[ERR] = 1 738
734 * - INT_STATUS[INTRQ] = 1 739 /* return if IOS_SS is cleared */
735 * - DMA_STATUS[IORACTA] = 1 740 if (!(in_be32(mmio + SCC_DMA_CMD) & ATA_DMA_START))
736 */ 741 return host_stat;
737 if (!(host_stat & ATA_DMA_INTR)) { 742
738 u32 int_status = in_be32(mmio + SCC_DMA_INTST); 743 /* errata A252,A308 workaround: Step4 */
739 if (ata_altstatus(ap) & ATA_ERR && 744 if (ata_altstatus(ap) & ATA_ERR && int_status & INTSTS_INTRQ)
740 int_status & INTSTS_INTRQ && 745 return (host_stat | ATA_DMA_INTR);
741 host_stat & ATA_DMA_ACTIVE) 746
742 host_stat |= ATA_DMA_INTR; 747 /* errata A308 workaround Step5 */
748 if (int_status & INTSTS_IOIRQS) {
749 host_stat |= ATA_DMA_INTR;
750
751 /* We don't check ATAPI DMA because it is limited to UDMA4 */
752 if ((qc->tf.protocol == ATA_PROT_DMA &&
753 qc->dev->xfer_mode > XFER_UDMA_4)) {
754 if (!(int_status & INTSTS_ACTEINT)) {
755 printk(KERN_WARNING "ata%u: data lost occurred. (ACTEINT==0, retry:%d)\n",
756 ap->print_id, retry);
757 host_stat |= ATA_DMA_ERR;
758 if (retry++)
759 ap->udma_mask >>= 1;
760 } else
761 retry = 0;
762 }
743 } 763 }
744 764
745 return host_stat; 765 return host_stat;
@@ -892,10 +912,6 @@ static void scc_std_postreset (struct ata_port *ap, unsigned int *classes)
892{ 912{
893 DPRINTK("ENTER\n"); 913 DPRINTK("ENTER\n");
894 914
895 /* re-enable interrupts */
896 if (!ap->ops->error_handler)
897 ap->ops->irq_on(ap);
898
899 /* is double-select really necessary? */ 915 /* is double-select really necessary? */
900 if (classes[0] != ATA_DEV_NONE) 916 if (classes[0] != ATA_DEV_NONE)
901 ap->ops->dev_select(ap, 1); 917 ap->ops->dev_select(ap, 1);