| From cadef677e4a9b9c1d069675043767df486782986 Mon Sep 17 00:00:00 2001 |
| From: Mikael Pettersson <mikpe@it.uu.se> |
| Date: Fri, 31 Oct 2008 08:03:55 +0100 |
| Subject: sata_promise: add ATA engine reset to reset ops |
| |
| From: Mikael Pettersson <mikpe@it.uu.se> |
| |
| commit cadef677e4a9b9c1d069675043767df486782986 upstream |
| |
| Promise ATA engines need to be reset when errors occur. |
| That's currently done for errors detected by sata_promise itself, |
| but it's not done for errors like timeouts detected outside of |
| the low-level driver. |
| |
| The effect of this omission is that a timeout tends to result |
| in a sequence of failed COMRESETs after which libata EH gives |
| up and disables the port. At that point the port's ATA engine |
| hangs and even reloading the driver will not resume it. |
| |
| To fix this, make sata_promise override ->hardreset on SATA |
| ports with code which calls pdc_reset_port() on the port in |
| question before calling libata's hardreset. PATA ports don't |
| use ->hardreset, so for those we override ->softreset instead. |
| |
| Signed-off-by: Mikael Pettersson <mikpe@it.uu.se> |
| Signed-off-by: Jeff Garzik <jgarzik@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/ata/sata_promise.c | 20 ++++++++++++++++++++ |
| 1 file changed, 20 insertions(+) |
| |
| --- a/drivers/ata/sata_promise.c |
| +++ b/drivers/ata/sata_promise.c |
| @@ -153,6 +153,10 @@ static void pdc_freeze(struct ata_port * |
| static void pdc_sata_freeze(struct ata_port *ap); |
| static void pdc_thaw(struct ata_port *ap); |
| static void pdc_sata_thaw(struct ata_port *ap); |
| +static int pdc_pata_softreset(struct ata_link *link, unsigned int *class, |
| + unsigned long deadline); |
| +static int pdc_sata_hardreset(struct ata_link *link, unsigned int *class, |
| + unsigned long deadline); |
| static void pdc_error_handler(struct ata_port *ap); |
| static void pdc_post_internal_cmd(struct ata_queued_cmd *qc); |
| static int pdc_pata_cable_detect(struct ata_port *ap); |
| @@ -186,6 +190,7 @@ static struct ata_port_operations pdc_sa |
| .scr_read = pdc_sata_scr_read, |
| .scr_write = pdc_sata_scr_write, |
| .port_start = pdc_sata_port_start, |
| + .hardreset = pdc_sata_hardreset, |
| }; |
| |
| /* First-generation chips need a more restrictive ->check_atapi_dma op */ |
| @@ -200,6 +205,7 @@ static struct ata_port_operations pdc_pa |
| .freeze = pdc_freeze, |
| .thaw = pdc_thaw, |
| .port_start = pdc_common_port_start, |
| + .softreset = pdc_pata_softreset, |
| }; |
| |
| static const struct ata_port_info pdc_port_info[] = { |
| @@ -691,6 +697,20 @@ static void pdc_sata_thaw(struct ata_por |
| readl(host_mmio + hotplug_offset); /* flush */ |
| } |
| |
| +static int pdc_pata_softreset(struct ata_link *link, unsigned int *class, |
| + unsigned long deadline) |
| +{ |
| + pdc_reset_port(link->ap); |
| + return ata_sff_softreset(link, class, deadline); |
| +} |
| + |
| +static int pdc_sata_hardreset(struct ata_link *link, unsigned int *class, |
| + unsigned long deadline) |
| +{ |
| + pdc_reset_port(link->ap); |
| + return sata_sff_hardreset(link, class, deadline); |
| +} |
| + |
| static void pdc_error_handler(struct ata_port *ap) |
| { |
| if (!(ap->pflags & ATA_PFLAG_FROZEN)) |