diff options
author | Kou Ishizaki <kou.ishizaki@toshiba.co.jp> | 2007-07-19 19:11:53 -0400 |
---|---|---|
committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-07-19 19:11:53 -0400 |
commit | 4ae41ff887224b39c3c3c673a918193e90be558f (patch) | |
tree | 50ea15b294c108ca0c905b0e411e8ee577e0967f /drivers/ide | |
parent | f644d47af3834b603d909c212287d0c21ec3ebbb (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')
-rw-r--r-- | drivers/ide/pci/scc_pata.c | 67 |
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 */ |
476 | static int scc_dma_test_irq(ide_drive_t *drive) | 506 | static 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 | ||
526 | static 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; |