aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/sata_nv.c
diff options
context:
space:
mode:
authorRobert Hancock <hancockr@shaw.ca>2008-01-29 20:53:19 -0500
committerJeff Garzik <jeff@garzik.org>2008-02-01 12:26:38 -0500
commita1fe782414b7122d4c0501d3a0988b7302fa586f (patch)
tree8910f893600b45b05d19e0322ebaa5888cb8ff2e /drivers/ata/sata_nv.c
parent7bb3c5290ca0ec9e65947c907495c2b56e895e46 (diff)
sata_nv: fix for completion handling
This patch is based on an original patch from Kuan Luo of NVIDIA, posted under subject "fixed a bug of adma in rhel4u5 with HDS7250SASUN500G". His description follows. I've reworked it a bit to avoid some unnecessary repeated checks but it should be functionally identical. "The patch is to solve the error message "ata1: CPB flags CMD err, flags=0x11" when testing HDS7250SASUN500G in rhel4u5. I tested this hd in 2.6.24-rc7 which needed to remove the mask in blacklist to run the ncq and the same error also showed up. I traced the bug and found that the interrupt finished a command (for example, tag=0) when the driver got that adma status is NV_ADMA_STAT_DONE and cpb->resp_flags is NV_CPB_RESP_DONE. However, For this hd, the drive maybe didn't clear bit 0 at this moment. It meaned the hardware had not completely finished the command. If at the same time the driver freed the command(tag 0) and sended another command (tag 0), the error happened. The notifier register is 32-bit register containing notifier value. Value is bit vector containing one bit per tag number (0-31) in corresponding bit positions (bit 0 is for tag 0, etc). When bit is set then ADMA indicates that command with corresponding tag number completed execution. So i added the check notifier code. Sometimes i saw that the notifier reg set some bits , but the adma status set NV_ADMA_STAT_CMD_COMPLETE ,not NV_ADMA_STAT_DONE. So i added the NV_ADMA_STAT_CMD_COMPLETE check code." Signed-off-by: Robert Hancock <hancockr@shaw.ca> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata/sata_nv.c')
-rw-r--r--drivers/ata/sata_nv.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index a0f98fdab7a0..bfe92a43cf89 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -1011,14 +1011,20 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
1011 } 1011 }
1012 1012
1013 if (status & (NV_ADMA_STAT_DONE | 1013 if (status & (NV_ADMA_STAT_DONE |
1014 NV_ADMA_STAT_CPBERR)) { 1014 NV_ADMA_STAT_CPBERR |
1015 u32 check_commands; 1015 NV_ADMA_STAT_CMD_COMPLETE)) {
1016 u32 check_commands = notifier_clears[i];
1016 int pos, error = 0; 1017 int pos, error = 0;
1017 1018
1018 if (ata_tag_valid(ap->link.active_tag)) 1019 if (status & NV_ADMA_STAT_CPBERR) {
1019 check_commands = 1 << ap->link.active_tag; 1020 /* Check all active commands */
1020 else 1021 if (ata_tag_valid(ap->link.active_tag))
1021 check_commands = ap->link.sactive; 1022 check_commands = 1 <<
1023 ap->link.active_tag;
1024 else
1025 check_commands = ap->
1026 link.sactive;
1027 }
1022 1028
1023 /** Check CPBs for completed commands */ 1029 /** Check CPBs for completed commands */
1024 while ((pos = ffs(check_commands)) && !error) { 1030 while ((pos = ffs(check_commands)) && !error) {