diff options
author | Tejun Heo <htejun@gmail.com> | 2007-09-23 00:14:12 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-10-12 14:55:41 -0400 |
commit | ae791c05694d7391ee9261a0450a50f7e95aedfd (patch) | |
tree | 73e3fbcd6cdfe667b5dcc512daaec7fb5941a132 | |
parent | da917d69d0ea63f5390716cba6e77f490ce96df9 (diff) |
libata-pmp-prep: implement ATA_LFLAG_NO_SRST, ASSUME_ATA and ASSUME_SEMB
Some links on some PMPs locks up on SRST and/or report incorrect
device signature. Implement ATA_LFLAG_NO_SRST, ASSUME_ATA and
ASSUME_SEMB to handle these quirky links. NO_SRST makes EH avoid
SRST. ASSUME_ATA and SEMB forces class code to ATA and SEMB_UNSUP
respectively. Note that SEMB isn't currently supported yet so the
_UNSUP variant is used.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/ata/libata-eh.c | 42 | ||||
-rw-r--r-- | include/linux/libata.h | 4 |
2 files changed, 36 insertions, 10 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 5244723952c2..7be04bd30bfe 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -1906,14 +1906,18 @@ static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, | |||
1906 | return 0; | 1906 | return 0; |
1907 | } | 1907 | } |
1908 | 1908 | ||
1909 | static int ata_eh_followup_srst_needed(int rc, int classify, | 1909 | static int ata_eh_followup_srst_needed(struct ata_link *link, |
1910 | int rc, int classify, | ||
1910 | const unsigned int *classes) | 1911 | const unsigned int *classes) |
1911 | { | 1912 | { |
1913 | if (link->flags & ATA_LFLAG_NO_SRST) | ||
1914 | return 0; | ||
1912 | if (rc == -EAGAIN) | 1915 | if (rc == -EAGAIN) |
1913 | return 1; | 1916 | return 1; |
1914 | if (rc != 0) | 1917 | if (rc != 0) |
1915 | return 0; | 1918 | return 0; |
1916 | if (classify && classes[0] == ATA_DEV_UNKNOWN) | 1919 | if (classify && !(link->flags & ATA_LFLAG_ASSUME_CLASS) && |
1920 | classes[0] == ATA_DEV_UNKNOWN) | ||
1917 | return 1; | 1921 | return 1; |
1918 | return 0; | 1922 | return 0; |
1919 | } | 1923 | } |
@@ -1940,7 +1944,8 @@ int ata_eh_reset(struct ata_link *link, int classify, | |||
1940 | */ | 1944 | */ |
1941 | action = ehc->i.action; | 1945 | action = ehc->i.action; |
1942 | ehc->i.action &= ~ATA_EH_RESET_MASK; | 1946 | ehc->i.action &= ~ATA_EH_RESET_MASK; |
1943 | if (softreset && (!hardreset || (!sata_set_spd_needed(link) && | 1947 | if (softreset && (!hardreset || (!(link->flags & ATA_LFLAG_NO_SRST) && |
1948 | !sata_set_spd_needed(link) && | ||
1944 | !(action & ATA_EH_HARDRESET)))) | 1949 | !(action & ATA_EH_HARDRESET)))) |
1945 | ehc->i.action |= ATA_EH_SOFTRESET; | 1950 | ehc->i.action |= ATA_EH_SOFTRESET; |
1946 | else | 1951 | else |
@@ -2003,7 +2008,7 @@ int ata_eh_reset(struct ata_link *link, int classify, | |||
2003 | rc = ata_do_reset(link, reset, classes, deadline); | 2008 | rc = ata_do_reset(link, reset, classes, deadline); |
2004 | 2009 | ||
2005 | if (reset == hardreset && | 2010 | if (reset == hardreset && |
2006 | ata_eh_followup_srst_needed(rc, classify, classes)) { | 2011 | ata_eh_followup_srst_needed(link, rc, classify, classes)) { |
2007 | /* okay, let's do follow-up softreset */ | 2012 | /* okay, let's do follow-up softreset */ |
2008 | reset = softreset; | 2013 | reset = softreset; |
2009 | 2014 | ||
@@ -2018,8 +2023,8 @@ int ata_eh_reset(struct ata_link *link, int classify, | |||
2018 | ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK); | 2023 | ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK); |
2019 | rc = ata_do_reset(link, reset, classes, deadline); | 2024 | rc = ata_do_reset(link, reset, classes, deadline); |
2020 | 2025 | ||
2021 | if (rc == 0 && classify && | 2026 | if (rc == 0 && classify && classes[0] == ATA_DEV_UNKNOWN && |
2022 | classes[0] == ATA_DEV_UNKNOWN) { | 2027 | !(link->flags & ATA_LFLAG_ASSUME_CLASS)) { |
2023 | ata_link_printk(link, KERN_ERR, | 2028 | ata_link_printk(link, KERN_ERR, |
2024 | "classification failed\n"); | 2029 | "classification failed\n"); |
2025 | rc = -EINVAL; | 2030 | rc = -EINVAL; |
@@ -2027,6 +2032,10 @@ int ata_eh_reset(struct ata_link *link, int classify, | |||
2027 | } | 2032 | } |
2028 | } | 2033 | } |
2029 | 2034 | ||
2035 | /* if we skipped follow-up srst, clear rc */ | ||
2036 | if (rc == -EAGAIN) | ||
2037 | rc = 0; | ||
2038 | |||
2030 | if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) { | 2039 | if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) { |
2031 | unsigned long now = jiffies; | 2040 | unsigned long now = jiffies; |
2032 | 2041 | ||
@@ -2051,12 +2060,25 @@ int ata_eh_reset(struct ata_link *link, int classify, | |||
2051 | if (rc == 0) { | 2060 | if (rc == 0) { |
2052 | u32 sstatus; | 2061 | u32 sstatus; |
2053 | 2062 | ||
2054 | /* After the reset, the device state is PIO 0 and the | 2063 | ata_link_for_each_dev(dev, link) { |
2055 | * controller state is undefined. Record the mode. | 2064 | /* After the reset, the device state is PIO 0 |
2056 | */ | 2065 | * and the controller state is undefined. |
2057 | ata_link_for_each_dev(dev, link) | 2066 | * Record the mode. |
2067 | */ | ||
2058 | dev->pio_mode = XFER_PIO_0; | 2068 | dev->pio_mode = XFER_PIO_0; |
2059 | 2069 | ||
2070 | if (ata_link_offline(link)) | ||
2071 | continue; | ||
2072 | |||
2073 | /* apply class override and convert UNKNOWN to NONE */ | ||
2074 | if (link->flags & ATA_LFLAG_ASSUME_ATA) | ||
2075 | classes[dev->devno] = ATA_DEV_ATA; | ||
2076 | else if (link->flags & ATA_LFLAG_ASSUME_SEMB) | ||
2077 | classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */ | ||
2078 | else if (classes[dev->devno] == ATA_DEV_UNKNOWN) | ||
2079 | classes[dev->devno] = ATA_DEV_NONE; | ||
2080 | } | ||
2081 | |||
2060 | /* record current link speed */ | 2082 | /* record current link speed */ |
2061 | if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0) | 2083 | if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0) |
2062 | link->sata_spd = (sstatus >> 4) & 0xf; | 2084 | link->sata_spd = (sstatus >> 4) & 0xf; |
diff --git a/include/linux/libata.h b/include/linux/libata.h index f9f81fd93293..6266fffb0eb3 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
@@ -165,6 +165,10 @@ enum { | |||
165 | ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */ | 165 | ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */ |
166 | ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), /* can't wait for the first D2H | 166 | ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), /* can't wait for the first D2H |
167 | * Register FIS clearing BSY */ | 167 | * Register FIS clearing BSY */ |
168 | ATA_LFLAG_NO_SRST = (1 << 2), /* avoid softreset */ | ||
169 | ATA_LFLAG_ASSUME_ATA = (1 << 3), /* assume ATA class */ | ||
170 | ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */ | ||
171 | ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, | ||
168 | 172 | ||
169 | /* struct ata_port flags */ | 173 | /* struct ata_port flags */ |
170 | ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ | 174 | ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ |