aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxiangliang yu <yxlraid@gmail.com>2013-10-27 08:03:04 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-04 13:56:13 -0500
commit420df0f5c514a3d6f44829c2dacfcb44964f6517 (patch)
tree6c31e816c47ea5a194e9be7ec85cfa6a72d93c74
parent296cfdecbe6cf01b12f6073a521694db2073af5e (diff)
ahci: disabled FBS prior to issuing software reset
commit 89dafa20f3daab5b3e0c13d0068a28e8e64e2102 upstream. Tested with Marvell 88se9125, attached with one port mulitplier(5 ports) and one disk, we will get following boot log messages if using current code: ata8: SATA link up 6.0 Gbps (SStatus 133 SControl 330) ata8.15: Port Multiplier 1.2, 0x1b4b:0x9715 r160, 5 ports, feat 0x1/0x1f ahci 0000:03:00.0: FBS is enabled ata8.00: hard resetting link ata8.00: SATA link down (SStatus 0 SControl 330) ata8.01: hard resetting link ata8.01: SATA link down (SStatus 0 SControl 330) ata8.02: hard resetting link ata8.02: SATA link down (SStatus 0 SControl 330) ata8.03: hard resetting link ata8.03: SATA link up 6.0 Gbps (SStatus 133 SControl 133) ata8.04: hard resetting link ata8.04: failed to resume link (SControl 133) ata8.04: failed to read SCR 0 (Emask=0x40) ata8.04: failed to read SCR 0 (Emask=0x40) ata8.04: failed to read SCR 1 (Emask=0x40) ata8.04: failed to read SCR 0 (Emask=0x40) ata8.03: native sectors (2) is smaller than sectors (976773168) ata8.03: ATA-8: ST3500413AS, JC4B, max UDMA/133 ata8.03: 976773168 sectors, multi 0: LBA48 NCQ (depth 31/32) ata8.03: configured for UDMA/133 ata8.04: failed to IDENTIFY (I/O error, err_mask=0x100) ata8.15: hard resetting link ata8.15: SATA link up 6.0 Gbps (SStatus 133 SControl 330) ata8.15: Port Multiplier vendor mismatch '0x1b4b' != '0x133' ata8.15: PMP revalidation failed (errno=-19) ata8.15: hard resetting link ata8.15: SATA link up 6.0 Gbps (SStatus 133 SControl 330) ata8.15: Port Multiplier vendor mismatch '0x1b4b' != '0x133' ata8.15: PMP revalidation failed (errno=-19) ata8.15: limiting SATA link speed to 3.0 Gbps ata8.15: hard resetting link ata8.15: SATA link up 3.0 Gbps (SStatus 123 SControl 320) ata8.15: Port Multiplier vendor mismatch '0x1b4b' != '0x133' ata8.15: PMP revalidation failed (errno=-19) ata8.15: failed to recover PMP after 5 tries, giving up ata8.15: Port Multiplier detaching ata8.03: disabled ata8.00: disabled ata8: EH complete The reason is that current detection code doesn't follow AHCI spec: First,the port multiplier detection process look like this: ahci_hardreset(link, class, deadline) if (class == ATA_DEV_PMP) { sata_pmp_attach(dev) /* will enable FBS */ sata_pmp_init_links(ap, nr_ports); ata_for_each_link(link, ap, EDGE) { sata_std_hardreset(link, class, deadline); if (link_is_online) /* do soft reset */ ahci_softreset(link, class, deadline); } } But, according to chapter 9.3.9 in AHCI spec: Prior to issuing software reset, software shall clear PxCMD.ST to '0' and then clear PxFBS.EN to '0'. The patch test ok with kernel 3.11.1. tj: Patch white space contaminated, applied manually with trivial updates. Signed-off-by: Xiangliang Yu <yuxiangl@marvell.com> Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/ata/libahci.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 7b9bdd822c62..8905e03a53a2 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -1266,9 +1266,11 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
1266{ 1266{
1267 struct ata_port *ap = link->ap; 1267 struct ata_port *ap = link->ap;
1268 struct ahci_host_priv *hpriv = ap->host->private_data; 1268 struct ahci_host_priv *hpriv = ap->host->private_data;
1269 struct ahci_port_priv *pp = ap->private_data;
1269 const char *reason = NULL; 1270 const char *reason = NULL;
1270 unsigned long now, msecs; 1271 unsigned long now, msecs;
1271 struct ata_taskfile tf; 1272 struct ata_taskfile tf;
1273 bool fbs_disabled = false;
1272 int rc; 1274 int rc;
1273 1275
1274 DPRINTK("ENTER\n"); 1276 DPRINTK("ENTER\n");
@@ -1278,6 +1280,16 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
1278 if (rc && rc != -EOPNOTSUPP) 1280 if (rc && rc != -EOPNOTSUPP)
1279 ata_link_warn(link, "failed to reset engine (errno=%d)\n", rc); 1281 ata_link_warn(link, "failed to reset engine (errno=%d)\n", rc);
1280 1282
1283 /*
1284 * According to AHCI-1.2 9.3.9: if FBS is enable, software shall
1285 * clear PxFBS.EN to '0' prior to issuing software reset to devices
1286 * that is attached to port multiplier.
1287 */
1288 if (!ata_is_host_link(link) && pp->fbs_enabled) {
1289 ahci_disable_fbs(ap);
1290 fbs_disabled = true;
1291 }
1292
1281 ata_tf_init(link->device, &tf); 1293 ata_tf_init(link->device, &tf);
1282 1294
1283 /* issue the first D2H Register FIS */ 1295 /* issue the first D2H Register FIS */
@@ -1318,6 +1330,10 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
1318 } else 1330 } else
1319 *class = ahci_dev_classify(ap); 1331 *class = ahci_dev_classify(ap);
1320 1332
1333 /* re-enable FBS if disabled before */
1334 if (fbs_disabled)
1335 ahci_enable_fbs(ap);
1336
1321 DPRINTK("EXIT, class=%u\n", *class); 1337 DPRINTK("EXIT, class=%u\n", *class);
1322 return 0; 1338 return 0;
1323 1339