diff options
author | Grant Grundler <grundler@google.com> | 2010-04-14 21:43:32 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2010-05-14 17:08:02 -0400 |
commit | 4f2c774856708bccecb74c0e6296e9e2c9136ee1 (patch) | |
tree | 33ebceafd0f2f21b155dde40344addf45e2cb4ed /drivers/ata | |
parent | fbaf666b854c04b2d8ebca17114ee409ddea08b5 (diff) |
[libata] Disable R_OK (Early ACK) on SII 3726 PMP
In 2009, While running "cache read" performance test of drives behind
SII PMP we encountered a "all 5 drives" timeout on more than 30% of the
machines under test. This patch reduces the rate by a factor of about 70.
Low enough that we didn't care to further investigate the issue.
Performance impact with any sort of "normal" use was ~2%+ CPU and less
than 1% throughput degradation. Worst case impact (cached read) was
6% IOPS reduction. This is with NCQ off (q=1) but I believe FIS based
switching enabled in the SATA driver.
The patch disables "Early ACK" in the 3726 port multiplier.
"Early ACK" is issued when device sends a FIS to the host (via PMP)
and the PMP sends an ACK immediately back to the device - well before
the host gets the response. Under worst case IOPs load (cached read
test) and more than 2 PMPs connected to a 4-port SATA controller,
I suspect the time to service all of the PMPs is exceeding the PMPs
ability to keep track of outstanding FIS it owes the Host. Reducing
the number of PMPs to 2 (or 1) reduces the frequency by several orders
of magnitude. Kudos to Gwendal for initial debugging of this issue.
[Any errors in the description are mine, not his.]
Patch is currently in production on Google servers.
Signed-off-by: Grant Grundler <grundler@google.com>
Signed-off-by: Gwendal Grignou <gwendal@google.com>
Acked-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-pmp.c | 32 |
1 files changed, 29 insertions, 3 deletions
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 00305f41ed86..224faabd7b7e 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c | |||
@@ -231,10 +231,14 @@ static const char *sata_pmp_spec_rev_str(const u32 *gscr) | |||
231 | return "<unknown>"; | 231 | return "<unknown>"; |
232 | } | 232 | } |
233 | 233 | ||
234 | #define PMP_GSCR_SII_POL 129 | ||
235 | |||
234 | static int sata_pmp_configure(struct ata_device *dev, int print_info) | 236 | static int sata_pmp_configure(struct ata_device *dev, int print_info) |
235 | { | 237 | { |
236 | struct ata_port *ap = dev->link->ap; | 238 | struct ata_port *ap = dev->link->ap; |
237 | u32 *gscr = dev->gscr; | 239 | u32 *gscr = dev->gscr; |
240 | u16 vendor = sata_pmp_gscr_vendor(gscr); | ||
241 | u16 devid = sata_pmp_gscr_devid(gscr); | ||
238 | unsigned int err_mask = 0; | 242 | unsigned int err_mask = 0; |
239 | const char *reason; | 243 | const char *reason; |
240 | int nr_ports, rc; | 244 | int nr_ports, rc; |
@@ -260,12 +264,34 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) | |||
260 | goto fail; | 264 | goto fail; |
261 | } | 265 | } |
262 | 266 | ||
267 | /* Disable sending Early R_OK. | ||
268 | * With "cached read" HDD testing and multiple ports busy on a SATA | ||
269 | * host controller, 3726 PMP will very rarely drop a deferred | ||
270 | * R_OK that was intended for the host. Symptom will be all | ||
271 | * 5 drives under test will timeout, get reset, and recover. | ||
272 | */ | ||
273 | if (vendor == 0x1095 && devid == 0x3726) { | ||
274 | u32 reg; | ||
275 | |||
276 | err_mask = sata_pmp_read(&ap->link, PMP_GSCR_SII_POL, ®); | ||
277 | if (err_mask) { | ||
278 | rc = -EIO; | ||
279 | reason = "failed to read Sil3726 Private Register"; | ||
280 | goto fail; | ||
281 | } | ||
282 | reg &= ~0x1; | ||
283 | err_mask = sata_pmp_write(&ap->link, PMP_GSCR_SII_POL, reg); | ||
284 | if (err_mask) { | ||
285 | rc = -EIO; | ||
286 | reason = "failed to write Sil3726 Private Register"; | ||
287 | goto fail; | ||
288 | } | ||
289 | } | ||
290 | |||
263 | if (print_info) { | 291 | if (print_info) { |
264 | ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, " | 292 | ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, " |
265 | "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n", | 293 | "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n", |
266 | sata_pmp_spec_rev_str(gscr), | 294 | sata_pmp_spec_rev_str(gscr), vendor, devid, |
267 | sata_pmp_gscr_vendor(gscr), | ||
268 | sata_pmp_gscr_devid(gscr), | ||
269 | sata_pmp_gscr_rev(gscr), | 295 | sata_pmp_gscr_rev(gscr), |
270 | nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN], | 296 | nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN], |
271 | gscr[SATA_PMP_GSCR_FEAT]); | 297 | gscr[SATA_PMP_GSCR_FEAT]); |