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 *)); |