diff options
Diffstat (limited to 'drivers/scsi/libata-bmdma.c')
-rw-r--r-- | drivers/scsi/libata-bmdma.c | 160 |
1 files changed, 158 insertions, 2 deletions
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c index 835dff0bafdc..004e1a0d8b71 100644 --- a/drivers/scsi/libata-bmdma.c +++ b/drivers/scsi/libata-bmdma.c | |||
@@ -652,6 +652,151 @@ 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 | * @prereset: prereset method (can be NULL) | ||
699 | * @softreset: softreset method (can be NULL) | ||
700 | * @hardreset: hardreset method (can be NULL) | ||
701 | * @postreset: postreset method (can be NULL) | ||
702 | * | ||
703 | * Handle error for ATA BMDMA controller. It can handle both | ||
704 | * PATA and SATA controllers. Many controllers should be able to | ||
705 | * use this EH as-is or with some added handling before and | ||
706 | * after. | ||
707 | * | ||
708 | * This function is intended to be used for constructing | ||
709 | * ->error_handler callback by low level drivers. | ||
710 | * | ||
711 | * LOCKING: | ||
712 | * Kernel thread context (may sleep) | ||
713 | */ | ||
714 | void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, | ||
715 | ata_reset_fn_t softreset, ata_reset_fn_t hardreset, | ||
716 | ata_postreset_fn_t postreset) | ||
717 | { | ||
718 | struct ata_eh_context *ehc = &ap->eh_context; | ||
719 | struct ata_queued_cmd *qc; | ||
720 | unsigned long flags; | ||
721 | int thaw = 0; | ||
722 | |||
723 | qc = __ata_qc_from_tag(ap, ap->active_tag); | ||
724 | if (qc && !(qc->flags & ATA_QCFLAG_FAILED)) | ||
725 | qc = NULL; | ||
726 | |||
727 | /* reset PIO HSM and stop DMA engine */ | ||
728 | spin_lock_irqsave(ap->lock, flags); | ||
729 | |||
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(ap->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, prereset, 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_prereset, ata_std_softreset, hardreset, | ||
784 | ata_std_postreset); | ||
785 | } | ||
786 | |||
787 | /** | ||
788 | * ata_bmdma_post_internal_cmd - Stock post_internal_cmd for | ||
789 | * BMDMA controller | ||
790 | * @qc: internal command to clean up | ||
791 | * | ||
792 | * LOCKING: | ||
793 | * Kernel thread context (may sleep) | ||
794 | */ | ||
795 | void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc) | ||
796 | { | ||
797 | ata_bmdma_stop(qc); | ||
798 | } | ||
799 | |||
655 | #ifdef CONFIG_PCI | 800 | #ifdef CONFIG_PCI |
656 | static struct ata_probe_ent * | 801 | static struct ata_probe_ent * |
657 | ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) | 802 | ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) |
@@ -930,10 +1075,21 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, | |||
930 | 1075 | ||
931 | /* FIXME: check ata_device_add return */ | 1076 | /* FIXME: check ata_device_add return */ |
932 | if (legacy_mode) { | 1077 | if (legacy_mode) { |
933 | if (legacy_mode & (1 << 0)) | 1078 | struct device *dev = &pdev->dev; |
1079 | struct ata_host_set *host_set = NULL; | ||
1080 | |||
1081 | if (legacy_mode & (1 << 0)) { | ||
934 | ata_device_add(probe_ent); | 1082 | ata_device_add(probe_ent); |
935 | if (legacy_mode & (1 << 1)) | 1083 | host_set = dev_get_drvdata(dev); |
1084 | } | ||
1085 | |||
1086 | if (legacy_mode & (1 << 1)) { | ||
936 | ata_device_add(probe_ent2); | 1087 | ata_device_add(probe_ent2); |
1088 | if (host_set) { | ||
1089 | host_set->next = dev_get_drvdata(dev); | ||
1090 | dev_set_drvdata(dev, host_set); | ||
1091 | } | ||
1092 | } | ||
937 | } else | 1093 | } else |
938 | ata_device_add(probe_ent); | 1094 | ata_device_add(probe_ent); |
939 | 1095 | ||