diff options
author | Mikael Pettersson <mikpe@it.uu.se> | 2008-03-23 13:41:01 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2008-03-24 22:31:25 -0400 |
commit | c07a9c4995827a4f4bcdbd07cec40ec87467f308 (patch) | |
tree | 8b23625f1cd345b96c71a678af3b251d765b447a /drivers/ata/sata_promise.c | |
parent | dda7aba119536084d082cd11d4781fe15d7355f2 (diff) |
sata_promise: fix hardreset hotplug events, take 2
A Promise SATA controller will signal hotplug events when a hard
reset (COMRESET) is done on a port. These events aren't masked by
the driver, and the unexpected interrupts will cause a sequence
of failed reset attempts util libata's EH finally gives up.
This has not been a common problem so far, but the pending libata
hardreset-by-default changes makes it a critical issue.
The solution is to disable hotplug events before a reset, and to
reenable them afterwards. (Promise's driver does this too.)
This patch adds SATA-specific versions of ->freeze() and ->thaw()
that also disable and enable hotplug events. PATA ports continue
to use the old versions of ->freeze() and ->thaw().
Accesses to the hotplug register must be serialised via host->lock.
We rely on ap->lock == &ap->host->lock and that libata takes this
lock before ->freeze() and ->thaw(). Document this requirement.
The interrupt handler is adjusted so its hotplug register accesses
are inside the region protected by host->lock.
Tested on various chips (SATA300TX4, SATA300TX2plus, SATAII150TX4,
FastTrack TX4000) with various combinations of SATA and PATA disks,
with and without the pending hardreset-by-default changes.
Signed-off-by: Mikael Pettersson <mikpe@it.uu.se>
Acked-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata/sata_promise.c')
-rw-r--r-- | drivers/ata/sata_promise.c | 109 |
1 files changed, 88 insertions, 21 deletions
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index f251a5f569d5..11c1afea2db2 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c | |||
@@ -46,7 +46,7 @@ | |||
46 | #include "sata_promise.h" | 46 | #include "sata_promise.h" |
47 | 47 | ||
48 | #define DRV_NAME "sata_promise" | 48 | #define DRV_NAME "sata_promise" |
49 | #define DRV_VERSION "2.11" | 49 | #define DRV_VERSION "2.12" |
50 | 50 | ||
51 | enum { | 51 | enum { |
52 | PDC_MAX_PORTS = 4, | 52 | PDC_MAX_PORTS = 4, |
@@ -145,7 +145,9 @@ static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc); | |||
145 | static void pdc_irq_clear(struct ata_port *ap); | 145 | static void pdc_irq_clear(struct ata_port *ap); |
146 | static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc); | 146 | static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc); |
147 | static void pdc_freeze(struct ata_port *ap); | 147 | static void pdc_freeze(struct ata_port *ap); |
148 | static void pdc_sata_freeze(struct ata_port *ap); | ||
148 | static void pdc_thaw(struct ata_port *ap); | 149 | static void pdc_thaw(struct ata_port *ap); |
150 | static void pdc_sata_thaw(struct ata_port *ap); | ||
149 | static void pdc_pata_error_handler(struct ata_port *ap); | 151 | static void pdc_pata_error_handler(struct ata_port *ap); |
150 | static void pdc_sata_error_handler(struct ata_port *ap); | 152 | static void pdc_sata_error_handler(struct ata_port *ap); |
151 | static void pdc_post_internal_cmd(struct ata_queued_cmd *qc); | 153 | static void pdc_post_internal_cmd(struct ata_queued_cmd *qc); |
@@ -180,8 +182,8 @@ static const struct ata_port_operations pdc_sata_ops = { | |||
180 | 182 | ||
181 | .qc_prep = pdc_qc_prep, | 183 | .qc_prep = pdc_qc_prep, |
182 | .qc_issue = pdc_qc_issue_prot, | 184 | .qc_issue = pdc_qc_issue_prot, |
183 | .freeze = pdc_freeze, | 185 | .freeze = pdc_sata_freeze, |
184 | .thaw = pdc_thaw, | 186 | .thaw = pdc_sata_thaw, |
185 | .error_handler = pdc_sata_error_handler, | 187 | .error_handler = pdc_sata_error_handler, |
186 | .post_internal_cmd = pdc_post_internal_cmd, | 188 | .post_internal_cmd = pdc_post_internal_cmd, |
187 | .cable_detect = pdc_sata_cable_detect, | 189 | .cable_detect = pdc_sata_cable_detect, |
@@ -205,8 +207,8 @@ static const struct ata_port_operations pdc_old_sata_ops = { | |||
205 | 207 | ||
206 | .qc_prep = pdc_qc_prep, | 208 | .qc_prep = pdc_qc_prep, |
207 | .qc_issue = pdc_qc_issue_prot, | 209 | .qc_issue = pdc_qc_issue_prot, |
208 | .freeze = pdc_freeze, | 210 | .freeze = pdc_sata_freeze, |
209 | .thaw = pdc_thaw, | 211 | .thaw = pdc_sata_thaw, |
210 | .error_handler = pdc_sata_error_handler, | 212 | .error_handler = pdc_sata_error_handler, |
211 | .post_internal_cmd = pdc_post_internal_cmd, | 213 | .post_internal_cmd = pdc_post_internal_cmd, |
212 | .cable_detect = pdc_sata_cable_detect, | 214 | .cable_detect = pdc_sata_cable_detect, |
@@ -631,6 +633,41 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc) | |||
631 | } | 633 | } |
632 | } | 634 | } |
633 | 635 | ||
636 | static int pdc_is_sataii_tx4(unsigned long flags) | ||
637 | { | ||
638 | const unsigned long mask = PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS; | ||
639 | return (flags & mask) == mask; | ||
640 | } | ||
641 | |||
642 | static unsigned int pdc_port_no_to_ata_no(unsigned int port_no, | ||
643 | int is_sataii_tx4) | ||
644 | { | ||
645 | static const unsigned char sataii_tx4_port_remap[4] = { 3, 1, 0, 2}; | ||
646 | return is_sataii_tx4 ? sataii_tx4_port_remap[port_no] : port_no; | ||
647 | } | ||
648 | |||
649 | static unsigned int pdc_sata_nr_ports(const struct ata_port *ap) | ||
650 | { | ||
651 | return (ap->flags & PDC_FLAG_4_PORTS) ? 4 : 2; | ||
652 | } | ||
653 | |||
654 | static unsigned int pdc_sata_ata_port_to_ata_no(const struct ata_port *ap) | ||
655 | { | ||
656 | const struct ata_host *host = ap->host; | ||
657 | unsigned int nr_ports = pdc_sata_nr_ports(ap); | ||
658 | unsigned int i; | ||
659 | |||
660 | for(i = 0; i < nr_ports && host->ports[i] != ap; ++i) | ||
661 | ; | ||
662 | BUG_ON(i >= nr_ports); | ||
663 | return pdc_port_no_to_ata_no(i, pdc_is_sataii_tx4(ap->flags)); | ||
664 | } | ||
665 | |||
666 | static unsigned int pdc_sata_hotplug_offset(const struct ata_port *ap) | ||
667 | { | ||
668 | return (ap->flags & PDC_FLAG_GEN_II) ? PDC2_SATA_PLUG_CSR : PDC_SATA_PLUG_CSR; | ||
669 | } | ||
670 | |||
634 | static void pdc_freeze(struct ata_port *ap) | 671 | static void pdc_freeze(struct ata_port *ap) |
635 | { | 672 | { |
636 | void __iomem *mmio = ap->ioaddr.cmd_addr; | 673 | void __iomem *mmio = ap->ioaddr.cmd_addr; |
@@ -643,6 +680,29 @@ static void pdc_freeze(struct ata_port *ap) | |||
643 | readl(mmio + PDC_CTLSTAT); /* flush */ | 680 | readl(mmio + PDC_CTLSTAT); /* flush */ |
644 | } | 681 | } |
645 | 682 | ||
683 | static void pdc_sata_freeze(struct ata_port *ap) | ||
684 | { | ||
685 | struct ata_host *host = ap->host; | ||
686 | void __iomem *host_mmio = host->iomap[PDC_MMIO_BAR]; | ||
687 | unsigned int hotplug_offset = pdc_sata_hotplug_offset(ap); | ||
688 | unsigned int ata_no = pdc_sata_ata_port_to_ata_no(ap); | ||
689 | u32 hotplug_status; | ||
690 | |||
691 | /* Disable hotplug events on this port. | ||
692 | * | ||
693 | * Locking: | ||
694 | * 1) hotplug register accesses must be serialised via host->lock | ||
695 | * 2) ap->lock == &ap->host->lock | ||
696 | * 3) ->freeze() and ->thaw() are called with ap->lock held | ||
697 | */ | ||
698 | hotplug_status = readl(host_mmio + hotplug_offset); | ||
699 | hotplug_status |= 0x11 << (ata_no + 16); | ||
700 | writel(hotplug_status, host_mmio + hotplug_offset); | ||
701 | readl(host_mmio + hotplug_offset); /* flush */ | ||
702 | |||
703 | pdc_freeze(ap); | ||
704 | } | ||
705 | |||
646 | static void pdc_thaw(struct ata_port *ap) | 706 | static void pdc_thaw(struct ata_port *ap) |
647 | { | 707 | { |
648 | void __iomem *mmio = ap->ioaddr.cmd_addr; | 708 | void __iomem *mmio = ap->ioaddr.cmd_addr; |
@@ -658,6 +718,26 @@ static void pdc_thaw(struct ata_port *ap) | |||
658 | readl(mmio + PDC_CTLSTAT); /* flush */ | 718 | readl(mmio + PDC_CTLSTAT); /* flush */ |
659 | } | 719 | } |
660 | 720 | ||
721 | static void pdc_sata_thaw(struct ata_port *ap) | ||
722 | { | ||
723 | struct ata_host *host = ap->host; | ||
724 | void __iomem *host_mmio = host->iomap[PDC_MMIO_BAR]; | ||
725 | unsigned int hotplug_offset = pdc_sata_hotplug_offset(ap); | ||
726 | unsigned int ata_no = pdc_sata_ata_port_to_ata_no(ap); | ||
727 | u32 hotplug_status; | ||
728 | |||
729 | pdc_thaw(ap); | ||
730 | |||
731 | /* Enable hotplug events on this port. | ||
732 | * Locking: see pdc_sata_freeze(). | ||
733 | */ | ||
734 | hotplug_status = readl(host_mmio + hotplug_offset); | ||
735 | hotplug_status |= 0x11 << ata_no; | ||
736 | hotplug_status &= ~(0x11 << (ata_no + 16)); | ||
737 | writel(hotplug_status, host_mmio + hotplug_offset); | ||
738 | readl(host_mmio + hotplug_offset); /* flush */ | ||
739 | } | ||
740 | |||
661 | static void pdc_common_error_handler(struct ata_port *ap, ata_reset_fn_t hardreset) | 741 | static void pdc_common_error_handler(struct ata_port *ap, ata_reset_fn_t hardreset) |
662 | { | 742 | { |
663 | if (!(ap->pflags & ATA_PFLAG_FROZEN)) | 743 | if (!(ap->pflags & ATA_PFLAG_FROZEN)) |
@@ -765,19 +845,6 @@ static void pdc_irq_clear(struct ata_port *ap) | |||
765 | readl(mmio + PDC_INT_SEQMASK); | 845 | readl(mmio + PDC_INT_SEQMASK); |
766 | } | 846 | } |
767 | 847 | ||
768 | static int pdc_is_sataii_tx4(unsigned long flags) | ||
769 | { | ||
770 | const unsigned long mask = PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS; | ||
771 | return (flags & mask) == mask; | ||
772 | } | ||
773 | |||
774 | static unsigned int pdc_port_no_to_ata_no(unsigned int port_no, | ||
775 | int is_sataii_tx4) | ||
776 | { | ||
777 | static const unsigned char sataii_tx4_port_remap[4] = { 3, 1, 0, 2}; | ||
778 | return is_sataii_tx4 ? sataii_tx4_port_remap[port_no] : port_no; | ||
779 | } | ||
780 | |||
781 | static irqreturn_t pdc_interrupt(int irq, void *dev_instance) | 848 | static irqreturn_t pdc_interrupt(int irq, void *dev_instance) |
782 | { | 849 | { |
783 | struct ata_host *host = dev_instance; | 850 | struct ata_host *host = dev_instance; |
@@ -799,6 +866,8 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance) | |||
799 | 866 | ||
800 | mmio_base = host->iomap[PDC_MMIO_BAR]; | 867 | mmio_base = host->iomap[PDC_MMIO_BAR]; |
801 | 868 | ||
869 | spin_lock(&host->lock); | ||
870 | |||
802 | /* read and clear hotplug flags for all ports */ | 871 | /* read and clear hotplug flags for all ports */ |
803 | if (host->ports[0]->flags & PDC_FLAG_GEN_II) | 872 | if (host->ports[0]->flags & PDC_FLAG_GEN_II) |
804 | hotplug_offset = PDC2_SATA_PLUG_CSR; | 873 | hotplug_offset = PDC2_SATA_PLUG_CSR; |
@@ -814,11 +883,9 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance) | |||
814 | 883 | ||
815 | if (mask == 0xffffffff && hotplug_status == 0) { | 884 | if (mask == 0xffffffff && hotplug_status == 0) { |
816 | VPRINTK("QUICK EXIT 2\n"); | 885 | VPRINTK("QUICK EXIT 2\n"); |
817 | return IRQ_NONE; | 886 | goto done_irq; |
818 | } | 887 | } |
819 | 888 | ||
820 | spin_lock(&host->lock); | ||
821 | |||
822 | mask &= 0xffff; /* only 16 tags possible */ | 889 | mask &= 0xffff; /* only 16 tags possible */ |
823 | if (mask == 0 && hotplug_status == 0) { | 890 | if (mask == 0 && hotplug_status == 0) { |
824 | VPRINTK("QUICK EXIT 3\n"); | 891 | VPRINTK("QUICK EXIT 3\n"); |