|
@@ -401,6 +401,33 @@ static int scc_ide_dma_end(ide_drive_t * drive)
|
|
|
ide_hwif_t *hwif = HWIF(drive);
|
|
|
unsigned long intsts_port = hwif->dma_base + 0x014;
|
|
|
u32 reg;
|
|
|
+ int dma_stat, data_loss = 0;
|
|
|
+ static int retry = 0;
|
|
|
+
|
|
|
+ /* errata A308 workaround: Step5 (check data loss) */
|
|
|
+ /* We don't check non ide_disk because it is limited to UDMA4 */
|
|
|
+ if (!(in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT) &&
|
|
|
+ drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) {
|
|
|
+ reg = in_be32((void __iomem *)intsts_port);
|
|
|
+ if (!(reg & INTSTS_ACTEINT)) {
|
|
|
+ printk(KERN_WARNING "%s: operation failed (transfer data loss)\n",
|
|
|
+ drive->name);
|
|
|
+ data_loss = 1;
|
|
|
+ if (retry++) {
|
|
|
+ struct request *rq = HWGROUP(drive)->rq;
|
|
|
+ int unit;
|
|
|
+ /* ERROR_RESET and drive->crc_count are needed
|
|
|
+ * to reduce DMA transfer mode in retry process.
|
|
|
+ */
|
|
|
+ if (rq)
|
|
|
+ rq->errors |= ERROR_RESET;
|
|
|
+ for (unit = 0; unit < MAX_DRIVES; unit++) {
|
|
|
+ ide_drive_t *drive = &hwif->drives[unit];
|
|
|
+ drive->crc_count++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
while (1) {
|
|
|
reg = in_be32((void __iomem *)intsts_port);
|
|
@@ -469,27 +496,25 @@ static int scc_ide_dma_end(ide_drive_t * drive)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- return __ide_dma_end(drive);
|
|
|
+ dma_stat = __ide_dma_end(drive);
|
|
|
+ if (data_loss)
|
|
|
+ dma_stat |= 2; /* emulate DMA error (to retry command) */
|
|
|
+ return dma_stat;
|
|
|
}
|
|
|
|
|
|
/* returns 1 if dma irq issued, 0 otherwise */
|
|
|
static int scc_dma_test_irq(ide_drive_t *drive)
|
|
|
{
|
|
|
- ide_hwif_t *hwif = HWIF(drive);
|
|
|
- u8 dma_stat = hwif->INB(hwif->dma_status);
|
|
|
+ ide_hwif_t *hwif = HWIF(drive);
|
|
|
+ u32 int_stat = in_be32((void __iomem *)hwif->dma_base + 0x014);
|
|
|
|
|
|
- /* return 1 if INTR asserted */
|
|
|
- if ((dma_stat & 4) == 4)
|
|
|
+ /* SCC errata A252,A308 workaround: Step4 */
|
|
|
+ if ((in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT) &&
|
|
|
+ (int_stat & INTSTS_INTRQ))
|
|
|
return 1;
|
|
|
|
|
|
- /* Workaround for PTERADD: emulate DMA_INTR when
|
|
|
- * - IDE_STATUS[ERR] = 1
|
|
|
- * - INT_STATUS[INTRQ] = 1
|
|
|
- * - DMA_STATUS[IORACTA] = 1
|
|
|
- */
|
|
|
- if (in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT &&
|
|
|
- in_be32((void __iomem *)(hwif->dma_base + 0x014)) & INTSTS_INTRQ &&
|
|
|
- dma_stat & 1)
|
|
|
+ /* SCC errata A308 workaround: Step5 (polling IOIRQS) */
|
|
|
+ if (int_stat & INTSTS_IOIRQS)
|
|
|
return 1;
|
|
|
|
|
|
if (!drive->waiting_for_dma)
|
|
@@ -498,6 +523,21 @@ static int scc_dma_test_irq(ide_drive_t *drive)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static u8 scc_udma_filter(ide_drive_t *drive)
|
|
|
+{
|
|
|
+ ide_hwif_t *hwif = drive->hwif;
|
|
|
+ u8 mask = hwif->ultra_mask;
|
|
|
+
|
|
|
+ /* errata A308 workaround: limit non ide_disk drive to UDMA4 */
|
|
|
+ if ((drive->media != ide_disk) && (mask & 0xE0)) {
|
|
|
+ printk(KERN_INFO "%s: limit %s to UDMA4\n",
|
|
|
+ SCC_PATA_NAME, drive->name);
|
|
|
+ mask = 0x1F;
|
|
|
+ }
|
|
|
+
|
|
|
+ return mask;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* setup_mmio_scc - map CTRL/BMID region
|
|
|
* @dev: PCI device we are configuring
|
|
@@ -702,6 +742,7 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif)
|
|
|
hwif->tuneproc = scc_tuneproc;
|
|
|
hwif->ide_dma_check = scc_config_drive_for_dma;
|
|
|
hwif->ide_dma_test_irq = scc_dma_test_irq;
|
|
|
+ hwif->udma_filter = scc_udma_filter;
|
|
|
|
|
|
hwif->drives[0].autotune = IDE_TUNE_AUTO;
|
|
|
hwif->drives[1].autotune = IDE_TUNE_AUTO;
|