diff options
author | Krzysztof Helt <krzysztof.h1@wp.pl> | 2008-01-11 23:50:46 +0300 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-23 20:29:25 +0300 |
commit | d9aa3af09cdc5d3ae0e67bed4107bcf7e25b9f31 (patch) | |
tree | 82d2699430907da4947022c406feabf855414bdf | |
parent | 3a0086a80ab7c2f1adb0e9b2a6fc82632979cec5 (diff) | |
download | linux-d9aa3af09cdc5d3ae0e67bed4107bcf7e25b9f31.tar.xz |
[SCSI] sym53c8xx: fixes two bugs related to chip reset
This patch fixes two bugs pointed by James Bottomley:
1. the if (!sym_data->io_reset). That variable is only ever filled
by a stack based completion. If we find it non empty it means
this code has been entered twice and we have a severe problem,
so that should just become a BUG_ON(sym_data->io_reset).
2. sym_data->io_reset should be set to NULL before the routine is
exited otherwise the PCI recovery code could end up completing
what will be a bogus pointer into the stack.
Big thanks to James Bottomley for help with the patch.
Signed-off-by: Krzysztof Helt <krzysztof.h1@w.pl>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | drivers/scsi/sym53c8xx_2/sym_glue.c | 13 |
1 files changed, 7 insertions, 6 deletions
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 09bbb39efe88..dc9af8f8f260 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -609,22 +609,24 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) */ #define WAIT_FOR_PCI_RECOVERY 35 if (pci_channel_offline(pdev)) { - struct completion *io_reset; int finished_reset = 0; init_completion(&eh_done); spin_lock_irq(shost->host_lock); /* Make sure we didn't race */ if (pci_channel_offline(pdev)) { - if (!sym_data->io_reset) - sym_data->io_reset = &eh_done; - io_reset = sym_data->io_reset; + BUG_ON(sym_data->io_reset); + sym_data->io_reset = &eh_done; } else { finished_reset = 1; } spin_unlock_irq(shost->host_lock); if (!finished_reset) - finished_reset = wait_for_completion_timeout(io_reset, + finished_reset = wait_for_completion_timeout + (sym_data->io_reset, WAIT_FOR_PCI_RECOVERY*HZ); + spin_lock_irq(shost->host_lock); + sym_data->io_reset = NULL; + spin_unlock_irq(shost->host_lock); if (!finished_reset) return SCSI_FAILED; } @@ -1879,7 +1881,6 @@ static void sym2_io_resume(struct pci_dev *pdev) spin_lock_irq(shost->host_lock); if (sym_data->io_reset) complete_all(sym_data->io_reset); - sym_data->io_reset = NULL; spin_unlock_irq(shost->host_lock); } |