diff options
author | Krzysztof Helt <krzysztof.h1@wp.pl> | 2008-01-11 15:50:46 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-23 12:29:25 -0500 |
commit | d9aa3af09cdc5d3ae0e67bed4107bcf7e25b9f31 (patch) | |
tree | 82d2699430907da4947022c406feabf855414bdf /drivers | |
parent | 3a0086a80ab7c2f1adb0e9b2a6fc82632979cec5 (diff) |
[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>
Diffstat (limited to 'drivers')
-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) | |||
609 | */ | 609 | */ |
610 | #define WAIT_FOR_PCI_RECOVERY 35 | 610 | #define WAIT_FOR_PCI_RECOVERY 35 |
611 | if (pci_channel_offline(pdev)) { | 611 | if (pci_channel_offline(pdev)) { |
612 | struct completion *io_reset; | ||
613 | int finished_reset = 0; | 612 | int finished_reset = 0; |
614 | init_completion(&eh_done); | 613 | init_completion(&eh_done); |
615 | spin_lock_irq(shost->host_lock); | 614 | spin_lock_irq(shost->host_lock); |
616 | /* Make sure we didn't race */ | 615 | /* Make sure we didn't race */ |
617 | if (pci_channel_offline(pdev)) { | 616 | if (pci_channel_offline(pdev)) { |
618 | if (!sym_data->io_reset) | 617 | BUG_ON(sym_data->io_reset); |
619 | sym_data->io_reset = &eh_done; | 618 | sym_data->io_reset = &eh_done; |
620 | io_reset = sym_data->io_reset; | ||
621 | } else { | 619 | } else { |
622 | finished_reset = 1; | 620 | finished_reset = 1; |
623 | } | 621 | } |
624 | spin_unlock_irq(shost->host_lock); | 622 | spin_unlock_irq(shost->host_lock); |
625 | if (!finished_reset) | 623 | if (!finished_reset) |
626 | finished_reset = wait_for_completion_timeout(io_reset, | 624 | finished_reset = wait_for_completion_timeout |
625 | (sym_data->io_reset, | ||
627 | WAIT_FOR_PCI_RECOVERY*HZ); | 626 | WAIT_FOR_PCI_RECOVERY*HZ); |
627 | spin_lock_irq(shost->host_lock); | ||
628 | sym_data->io_reset = NULL; | ||
629 | spin_unlock_irq(shost->host_lock); | ||
628 | if (!finished_reset) | 630 | if (!finished_reset) |
629 | return SCSI_FAILED; | 631 | return SCSI_FAILED; |
630 | } | 632 | } |
@@ -1879,7 +1881,6 @@ static void sym2_io_resume(struct pci_dev *pdev) | |||
1879 | spin_lock_irq(shost->host_lock); | 1881 | spin_lock_irq(shost->host_lock); |
1880 | if (sym_data->io_reset) | 1882 | if (sym_data->io_reset) |
1881 | complete_all(sym_data->io_reset); | 1883 | complete_all(sym_data->io_reset); |
1882 | sym_data->io_reset = NULL; | ||
1883 | spin_unlock_irq(shost->host_lock); | 1884 | spin_unlock_irq(shost->host_lock); |
1884 | } | 1885 | } |
1885 | 1886 | ||