Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d9aa3af0 authored by Krzysztof Helt's avatar Krzysztof Helt Committed by James Bottomley
Browse files

[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: default avatarKrzysztof Helt <krzysztof.h1@w.pl>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 3a0086a8
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
@@ -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)
			BUG_ON(sym_data->io_reset);
			sym_data->io_reset = &eh_done;
			io_reset = sym_data->io_reset;
		} 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);
}