aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2009-01-29 06:31:36 -0500
committerJeff Garzik <jgarzik@redhat.com>2009-02-02 23:04:31 -0500
commit9062712fa9ed13b531dfc2228086650b8bd6a255 (patch)
treed1bde6caeb53936859943bb1866ac65794cae5cb /drivers/ata
parentcf9a590a9eae3b99ca77d8db17afd2d7dbdd0986 (diff)
libata: implement HORKAGE_1_5_GBPS and apply it to WD My Book
3Gbps is often much more prone to transmission failures. It's usually okay to let EH handle speed down after transmission failures but some WD My Book drives completely shutdown after certain transmission failures and after it only power cycling can revive them. Combined with the fact that external drives often end up with cable assembly which is longer than usual and more likely to have intervening gender, this makes these drives very likely to shutdown under certain configurations virtually rendering them unusable. This patch implements HOARKGE_1_5_GBPS and applies it to WD My Book such that 1.5Gbps is forced once the device is identified. Please take a look at the following bz for related reports. http://bugzilla.kernel.org/show_bug.cgi?id=9913 Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/libata-core.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 3c5965d56c47..9fbf0595f3d4 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2232,6 +2232,40 @@ retry:
2232 return rc; 2232 return rc;
2233} 2233}
2234 2234
2235static int ata_do_link_spd_horkage(struct ata_device *dev)
2236{
2237 struct ata_link *plink = ata_dev_phys_link(dev);
2238 u32 target, target_limit;
2239
2240 if (!sata_scr_valid(plink))
2241 return 0;
2242
2243 if (dev->horkage & ATA_HORKAGE_1_5_GBPS)
2244 target = 1;
2245 else
2246 return 0;
2247
2248 target_limit = (1 << target) - 1;
2249
2250 /* if already on stricter limit, no need to push further */
2251 if (plink->sata_spd_limit <= target_limit)
2252 return 0;
2253
2254 plink->sata_spd_limit = target_limit;
2255
2256 /* Request another EH round by returning -EAGAIN if link is
2257 * going faster than the target speed. Forward progress is
2258 * guaranteed by setting sata_spd_limit to target_limit above.
2259 */
2260 if (plink->sata_spd > target) {
2261 ata_dev_printk(dev, KERN_INFO,
2262 "applying link speed limit horkage to %s\n",
2263 sata_spd_string(target));
2264 return -EAGAIN;
2265 }
2266 return 0;
2267}
2268
2235static inline u8 ata_dev_knobble(struct ata_device *dev) 2269static inline u8 ata_dev_knobble(struct ata_device *dev)
2236{ 2270{
2237 struct ata_port *ap = dev->link->ap; 2271 struct ata_port *ap = dev->link->ap;
@@ -2322,6 +2356,10 @@ int ata_dev_configure(struct ata_device *dev)
2322 return 0; 2356 return 0;
2323 } 2357 }
2324 2358
2359 rc = ata_do_link_spd_horkage(dev);
2360 if (rc)
2361 return rc;
2362
2325 /* let ACPI work its magic */ 2363 /* let ACPI work its magic */
2326 rc = ata_acpi_on_devcfg(dev); 2364 rc = ata_acpi_on_devcfg(dev);
2327 if (rc) 2365 if (rc)
@@ -4223,6 +4261,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
4223 /* Devices that do not need bridging limits applied */ 4261 /* Devices that do not need bridging limits applied */
4224 { "MTRON MSP-SATA*", NULL, ATA_HORKAGE_BRIDGE_OK, }, 4262 { "MTRON MSP-SATA*", NULL, ATA_HORKAGE_BRIDGE_OK, },
4225 4263
4264 /* Devices which aren't very happy with higher link speeds */
4265 { "WD My Book", NULL, ATA_HORKAGE_1_5_GBPS, },
4266
4226 /* End Marker */ 4267 /* End Marker */
4227 { } 4268 { }
4228}; 4269};