diff options
| author | Tejun Heo <htejun@gmail.com> | 2006-05-15 07:58:24 -0400 |
|---|---|---|
| committer | Tejun Heo <htejun@gmail.com> | 2006-05-15 07:58:24 -0400 |
| commit | 6d97dbd72da31a0e334f251fa9df4be9fab6fde2 (patch) | |
| tree | f31e023080474ba91529d7e1b1468cc999e32c73 | |
| parent | 022bdb075b9e1f224088a0b268de56268d7bc5b6 (diff) | |
[PATCH] libata-eh: implement BMDMA EH
Implement stock BMDMA error handling methods.
Signed-off-by: Tejun Heo <htejun@gmail.com>
| -rw-r--r-- | drivers/scsi/libata-bmdma.c | 144 | ||||
| -rw-r--r-- | drivers/scsi/libata-core.c | 5 | ||||
| -rw-r--r-- | include/linux/libata.h | 8 |
3 files changed, 157 insertions, 0 deletions
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c index 835dff0bafdc..49eff18a67e3 100644 --- a/drivers/scsi/libata-bmdma.c +++ b/drivers/scsi/libata-bmdma.c | |||
| @@ -652,6 +652,150 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc) | |||
| 652 | ata_altstatus(ap); /* dummy read */ | 652 | ata_altstatus(ap); /* dummy read */ |
| 653 | } | 653 | } |
| 654 | 654 | ||
| 655 | /** | ||
| 656 | * ata_bmdma_freeze - Freeze BMDMA controller port | ||
| 657 | * @ap: port to freeze | ||
| 658 | * | ||
| 659 | * Freeze BMDMA controller port. | ||
| 660 | * | ||
| 661 | * LOCKING: | ||
| 662 | * Inherited from caller. | ||
| 663 | */ | ||
| 664 | void ata_bmdma_freeze(struct ata_port *ap) | ||
| 665 | { | ||
| 666 | struct ata_ioports *ioaddr = &ap->ioaddr; | ||
| 667 | |||
| 668 | ap->ctl |= ATA_NIEN; | ||
| 669 | ap->last_ctl = ap->ctl; | ||
| 670 | |||
| 671 | if (ap->flags & ATA_FLAG_MMIO) | ||
| 672 | writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr); | ||
| 673 | else | ||
| 674 | outb(ap->ctl, ioaddr->ctl_addr); | ||
| 675 | } | ||
| 676 | |||
| 677 | /** | ||
| 678 | * ata_bmdma_thaw - Thaw BMDMA controller port | ||
| 679 | * @ap: port to thaw | ||
| 680 | * | ||
| 681 | * Thaw BMDMA controller port. | ||
| 682 | * | ||
| 683 | * LOCKING: | ||
| 684 | * Inherited from caller. | ||
| 685 | */ | ||
| 686 | void ata_bmdma_thaw(struct ata_port *ap) | ||
| 687 | { | ||
| 688 | /* clear & re-enable interrupts */ | ||
| 689 | ata_chk_status(ap); | ||
| 690 | ap->ops->irq_clear(ap); | ||
| 691 | if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */ | ||
| 692 | ata_irq_on(ap); | ||
| 693 | } | ||
| 694 | |||
| 695 | /** | ||
| 696 | * ata_bmdma_drive_eh - Perform EH with given methods for BMDMA controller | ||
| 697 | * @ap: port to handle error for | ||
| 698 | * @softreset: softreset method (can be NULL) | ||
| 699 | * @hardreset: hardreset method (can be NULL) | ||
| 700 | * @postreset: postreset method (can be NULL) | ||
| 701 | * | ||
| 702 | * Handle error for ATA BMDMA controller. It can handle both | ||
| 703 | * PATA and SATA controllers. Many controllers should be able to | ||
| 704 | * use this EH as-is or with some added handling before and | ||
| 705 | * after. | ||
| 706 | * | ||
| 707 | * This function is intended to be used for constructing | ||
| 708 | * ->error_handler callback by low level drivers. | ||
| 709 | * | ||
| 710 | * LOCKING: | ||
| 711 | * Kernel thread context (may sleep) | ||
| 712 | */ | ||
| 713 | void ata_bmdma_drive_eh(struct ata_port *ap, ata_reset_fn_t softreset, | ||
| 714 | ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) | ||
| 715 | { | ||
| 716 | struct ata_host_set *host_set = ap->host_set; | ||
| 717 | struct ata_eh_context *ehc = &ap->eh_context; | ||
| 718 | struct ata_queued_cmd *qc; | ||
| 719 | unsigned long flags; | ||
| 720 | int thaw = 0; | ||
| 721 | |||
| 722 | qc = __ata_qc_from_tag(ap, ap->active_tag); | ||
| 723 | if (qc && !(qc->flags & ATA_QCFLAG_FAILED)) | ||
| 724 | qc = NULL; | ||
| 725 | |||
| 726 | /* reset PIO HSM and stop DMA engine */ | ||
| 727 | spin_lock_irqsave(&host_set->lock, flags); | ||
| 728 | |||
| 729 | ap->flags &= ~ATA_FLAG_NOINTR; | ||
| 730 | ap->hsm_task_state = HSM_ST_IDLE; | ||
| 731 | |||
| 732 | if (qc && (qc->tf.protocol == ATA_PROT_DMA || | ||
| 733 | qc->tf.protocol == ATA_PROT_ATAPI_DMA)) { | ||
| 734 | u8 host_stat; | ||
| 735 | |||
| 736 | host_stat = ata_bmdma_status(ap); | ||
| 737 | |||
| 738 | ata_ehi_push_desc(&ehc->i, "BMDMA stat 0x%x", host_stat); | ||
| 739 | |||
| 740 | /* BMDMA controllers indicate host bus error by | ||
| 741 | * setting DMA_ERR bit and timing out. As it wasn't | ||
| 742 | * really a timeout event, adjust error mask and | ||
| 743 | * cancel frozen state. | ||
| 744 | */ | ||
| 745 | if (qc->err_mask == AC_ERR_TIMEOUT && host_stat & ATA_DMA_ERR) { | ||
| 746 | qc->err_mask = AC_ERR_HOST_BUS; | ||
| 747 | thaw = 1; | ||
| 748 | } | ||
| 749 | |||
| 750 | ap->ops->bmdma_stop(qc); | ||
| 751 | } | ||
| 752 | |||
| 753 | ata_altstatus(ap); | ||
| 754 | ata_chk_status(ap); | ||
| 755 | ap->ops->irq_clear(ap); | ||
| 756 | |||
| 757 | spin_unlock_irqrestore(&host_set->lock, flags); | ||
| 758 | |||
| 759 | if (thaw) | ||
| 760 | ata_eh_thaw_port(ap); | ||
| 761 | |||
| 762 | /* PIO and DMA engines have been stopped, perform recovery */ | ||
| 763 | ata_do_eh(ap, softreset, hardreset, postreset); | ||
| 764 | } | ||
| 765 | |||
| 766 | /** | ||
| 767 | * ata_bmdma_error_handler - Stock error handler for BMDMA controller | ||
| 768 | * @ap: port to handle error for | ||
| 769 | * | ||
| 770 | * Stock error handler for BMDMA controller. | ||
| 771 | * | ||
| 772 | * LOCKING: | ||
| 773 | * Kernel thread context (may sleep) | ||
| 774 | */ | ||
| 775 | void ata_bmdma_error_handler(struct ata_port *ap) | ||
| 776 | { | ||
| 777 | ata_reset_fn_t hardreset; | ||
| 778 | |||
| 779 | hardreset = NULL; | ||
| 780 | if (sata_scr_valid(ap)) | ||
| 781 | hardreset = sata_std_hardreset; | ||
| 782 | |||
| 783 | ata_bmdma_drive_eh(ap, ata_std_softreset, hardreset, ata_std_postreset); | ||
| 784 | } | ||
| 785 | |||
| 786 | /** | ||
| 787 | * ata_bmdma_post_internal_cmd - Stock post_internal_cmd for | ||
| 788 | * BMDMA controller | ||
| 789 | * @qc: internal command to clean up | ||
| 790 | * | ||
| 791 | * LOCKING: | ||
| 792 | * Kernel thread context (may sleep) | ||
| 793 | */ | ||
| 794 | void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc) | ||
| 795 | { | ||
| 796 | ata_bmdma_stop(qc); | ||
| 797 | } | ||
| 798 | |||
| 655 | #ifdef CONFIG_PCI | 799 | #ifdef CONFIG_PCI |
| 656 | static struct ata_probe_ent * | 800 | static struct ata_probe_ent * |
| 657 | ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) | 801 | ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) |
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index ddc47097d37e..2969599ec0b9 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
| @@ -5377,6 +5377,11 @@ EXPORT_SYMBOL_GPL(ata_bmdma_start); | |||
| 5377 | EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); | 5377 | EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); |
| 5378 | EXPORT_SYMBOL_GPL(ata_bmdma_status); | 5378 | EXPORT_SYMBOL_GPL(ata_bmdma_status); |
| 5379 | EXPORT_SYMBOL_GPL(ata_bmdma_stop); | 5379 | EXPORT_SYMBOL_GPL(ata_bmdma_stop); |
| 5380 | EXPORT_SYMBOL_GPL(ata_bmdma_freeze); | ||
| 5381 | EXPORT_SYMBOL_GPL(ata_bmdma_thaw); | ||
| 5382 | EXPORT_SYMBOL_GPL(ata_bmdma_drive_eh); | ||
| 5383 | EXPORT_SYMBOL_GPL(ata_bmdma_error_handler); | ||
| 5384 | EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd); | ||
| 5380 | EXPORT_SYMBOL_GPL(ata_port_probe); | 5385 | EXPORT_SYMBOL_GPL(ata_port_probe); |
| 5381 | EXPORT_SYMBOL_GPL(sata_set_spd); | 5386 | EXPORT_SYMBOL_GPL(sata_set_spd); |
| 5382 | EXPORT_SYMBOL_GPL(sata_phy_reset); | 5387 | EXPORT_SYMBOL_GPL(sata_phy_reset); |
diff --git a/include/linux/libata.h b/include/linux/libata.h index 9fe46073cf8c..6ccacbf889e3 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
| @@ -661,6 +661,14 @@ extern void ata_bmdma_start (struct ata_queued_cmd *qc); | |||
| 661 | extern void ata_bmdma_stop(struct ata_queued_cmd *qc); | 661 | extern void ata_bmdma_stop(struct ata_queued_cmd *qc); |
| 662 | extern u8 ata_bmdma_status(struct ata_port *ap); | 662 | extern u8 ata_bmdma_status(struct ata_port *ap); |
| 663 | extern void ata_bmdma_irq_clear(struct ata_port *ap); | 663 | extern void ata_bmdma_irq_clear(struct ata_port *ap); |
| 664 | extern void ata_bmdma_freeze(struct ata_port *ap); | ||
| 665 | extern void ata_bmdma_thaw(struct ata_port *ap); | ||
| 666 | extern void ata_bmdma_drive_eh(struct ata_port *ap, | ||
| 667 | ata_reset_fn_t softreset, | ||
| 668 | ata_reset_fn_t hardreset, | ||
| 669 | ata_postreset_fn_t postreset); | ||
| 670 | extern void ata_bmdma_error_handler(struct ata_port *ap); | ||
| 671 | extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc); | ||
| 664 | extern void ata_qc_complete(struct ata_queued_cmd *qc); | 672 | extern void ata_qc_complete(struct ata_queued_cmd *qc); |
| 665 | extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, | 673 | extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, |
| 666 | void (*done)(struct scsi_cmnd *)); | 674 | void (*done)(struct scsi_cmnd *)); |
