aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ide/pci/scc_pata.c
diff options
context:
space:
mode:
authorKou Ishizaki <kou.ishizaki@toshiba.co.jp>2007-07-19 19:11:53 -0400
committerBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2007-07-19 19:11:53 -0400
commit4ae41ff887224b39c3c3c673a918193e90be558f (patch)
tree50ea15b294c108ca0c905b0e411e8ee577e0967f /drivers/ide/pci/scc_pata.c
parentf644d47af3834b603d909c212287d0c21ec3ebbb (diff)
scc_pata.c: Workaround for errata A308 (take 2)
Workaround for errata A308: turn down the UDMA mode and retry the DMA command when the data lost condition is detected. take2: udma_filter() hook is used to limit ATAPI UDMA mode. Signed-off-by: Kou Ishizaki <kou.ishizaki@toshiba.co.jp> Signed-off-by: Akira Iguchi <akira2.iguchi@toshiba.co.jp> Cc: Sergei Shtylyov <sshtylyov@ru.mvista.com> Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers/ide/pci/scc_pata.c')
-rw-r--r--drivers/ide/pci/scc_pata.c67
1 files changed, 54 insertions, 13 deletions
diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c
index a96333c74bf1..fd4b1a24ecab 100644
--- a/drivers/ide/pci/scc_pata.c
+++ b/drivers/ide/pci/scc_pata.c
@@ -401,6 +401,33 @@ static int scc_ide_dma_end(ide_drive_t * drive)
401 ide_hwif_t *hwif = HWIF(drive); 401 ide_hwif_t *hwif = HWIF(drive);
402 unsigned long intsts_port = hwif->dma_base + 0x014; 402 unsigned long intsts_port = hwif->dma_base + 0x014;
403 u32 reg; 403 u32 reg;
404 int dma_stat, data_loss = 0;
405 static int retry = 0;
406
407 /* errata A308 workaround: Step5 (check data loss) */
408 /* We don't check non ide_disk because it is limited to UDMA4 */
409 if (!(in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT) &&
410 drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) {
411 reg = in_be32((void __iomem *)intsts_port);
412 if (!(reg & INTSTS_ACTEINT)) {
413 printk(KERN_WARNING "%s: operation failed (transfer data loss)\n",
414 drive->name);
415 data_loss = 1;
416 if (retry++) {
417 struct request *rq = HWGROUP(drive)->rq;
418 int unit;
419 /* ERROR_RESET and drive->crc_count are needed
420 * to reduce DMA transfer mode in retry process.
421 */
422 if (rq)
423 rq->errors |= ERROR_RESET;
424 for (unit = 0; unit < MAX_DRIVES; unit++) {
425 ide_drive_t *drive = &hwif->drives[unit];
426 drive->crc_count++;
427 }
428 }
429 }
430 }
404 431
405 while (1) { 432 while (1) {
406 reg = in_be32((void __iomem *)intsts_port); 433 reg = in_be32((void __iomem *)intsts_port);
@@ -469,27 +496,25 @@ static int scc_ide_dma_end(ide_drive_t * drive)
469 break; 496 break;
470 } 497 }
471 498
472 return __ide_dma_end(drive); 499 dma_stat = __ide_dma_end(drive);
500 if (data_loss)
501 dma_stat |= 2; /* emulate DMA error (to retry command) */
502 return dma_stat;
473} 503}
474 504
475/* returns 1 if dma irq issued, 0 otherwise */ 505/* returns 1 if dma irq issued, 0 otherwise */
476static int scc_dma_test_irq(ide_drive_t *drive) 506static int scc_dma_test_irq(ide_drive_t *drive)
477{ 507{
478 ide_hwif_t *hwif = HWIF(drive); 508 ide_hwif_t *hwif = HWIF(drive);
479 u8 dma_stat = hwif->INB(hwif->dma_status); 509 u32 int_stat = in_be32((void __iomem *)hwif->dma_base + 0x014);
480 510
481 /* return 1 if INTR asserted */ 511 /* SCC errata A252,A308 workaround: Step4 */
482 if ((dma_stat & 4) == 4) 512 if ((in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT) &&
513 (int_stat & INTSTS_INTRQ))
483 return 1; 514 return 1;
484 515
485 /* Workaround for PTERADD: emulate DMA_INTR when 516 /* SCC errata A308 workaround: Step5 (polling IOIRQS) */
486 * - IDE_STATUS[ERR] = 1 517 if (int_stat & INTSTS_IOIRQS)
487 * - INT_STATUS[INTRQ] = 1
488 * - DMA_STATUS[IORACTA] = 1
489 */
490 if (in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT &&
491 in_be32((void __iomem *)(hwif->dma_base + 0x014)) & INTSTS_INTRQ &&
492 dma_stat & 1)
493 return 1; 518 return 1;
494 519
495 if (!drive->waiting_for_dma) 520 if (!drive->waiting_for_dma)
@@ -498,6 +523,21 @@ static int scc_dma_test_irq(ide_drive_t *drive)
498 return 0; 523 return 0;
499} 524}
500 525
526static u8 scc_udma_filter(ide_drive_t *drive)
527{
528 ide_hwif_t *hwif = drive->hwif;
529 u8 mask = hwif->ultra_mask;
530
531 /* errata A308 workaround: limit non ide_disk drive to UDMA4 */
532 if ((drive->media != ide_disk) && (mask & 0xE0)) {
533 printk(KERN_INFO "%s: limit %s to UDMA4\n",
534 SCC_PATA_NAME, drive->name);
535 mask = 0x1F;
536 }
537
538 return mask;
539}
540
501/** 541/**
502 * setup_mmio_scc - map CTRL/BMID region 542 * setup_mmio_scc - map CTRL/BMID region
503 * @dev: PCI device we are configuring 543 * @dev: PCI device we are configuring
@@ -702,6 +742,7 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif)
702 hwif->tuneproc = scc_tuneproc; 742 hwif->tuneproc = scc_tuneproc;
703 hwif->ide_dma_check = scc_config_drive_for_dma; 743 hwif->ide_dma_check = scc_config_drive_for_dma;
704 hwif->ide_dma_test_irq = scc_dma_test_irq; 744 hwif->ide_dma_test_irq = scc_dma_test_irq;
745 hwif->udma_filter = scc_udma_filter;
705 746
706 hwif->drives[0].autotune = IDE_TUNE_AUTO; 747 hwif->drives[0].autotune = IDE_TUNE_AUTO;
707 hwif->drives[1].autotune = IDE_TUNE_AUTO; 748 hwif->drives[1].autotune = IDE_TUNE_AUTO;