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

Commit 4da2b1eb authored by Finn Thain's avatar Finn Thain Committed by Martin K. Petersen
Browse files

scsi: mac_esp: Replace bogus memory barrier with spinlock



Commit da244654 ("[SCSI] mac_esp: fix for quadras with two esp
chips") added mac_scsi_esp_intr() to handle the IRQ lines from a pair of
on-board ESP chips (a normal shared IRQ did not work).

Proper mutual exclusion was missing from that patch. This patch fixes
race conditions between comparison and assignment of esp_chips[]
pointers.

Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Reviewed-by: default avatarMichael Schmitz <schmitzmic@gmail.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 62d57f20
Loading
Loading
Loading
Loading
+23 −10
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ struct mac_esp_priv {
	int error;
};
static struct esp *esp_chips[2];
static DEFINE_SPINLOCK(esp_chips_lock);

#define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \
			       platform_get_drvdata((struct platform_device *) \
@@ -562,15 +563,18 @@ static int esp_mac_probe(struct platform_device *dev)
	}

	host->irq = IRQ_MAC_SCSI;
	esp_chips[dev->id] = esp;
	mb();
	if (esp_chips[!dev->id] == NULL) {

	/* The request_irq() call is intended to succeed for the first device
	 * and fail for the second device.
	 */
	err = request_irq(host->irq, mac_scsi_esp_intr, 0, "ESP", NULL);
		if (err < 0) {
			esp_chips[dev->id] = NULL;
	spin_lock(&esp_chips_lock);
	if (err < 0 && esp_chips[!dev->id] == NULL) {
		spin_unlock(&esp_chips_lock);
		goto fail_free_priv;
	}
	}
	esp_chips[dev->id] = esp;
	spin_unlock(&esp_chips_lock);

	err = scsi_esp_register(esp, &dev->dev);
	if (err)
@@ -579,8 +583,13 @@ static int esp_mac_probe(struct platform_device *dev)
	return 0;

fail_free_irq:
	if (esp_chips[!dev->id] == NULL)
	spin_lock(&esp_chips_lock);
	esp_chips[dev->id] = NULL;
	if (esp_chips[!dev->id] == NULL) {
		spin_unlock(&esp_chips_lock);
		free_irq(host->irq, esp);
	} else
		spin_unlock(&esp_chips_lock);
fail_free_priv:
	kfree(mep);
fail_free_command_block:
@@ -599,9 +608,13 @@ static int esp_mac_remove(struct platform_device *dev)

	scsi_esp_unregister(esp);

	spin_lock(&esp_chips_lock);
	esp_chips[dev->id] = NULL;
	if (!(esp_chips[0] || esp_chips[1]))
	if (esp_chips[!dev->id] == NULL) {
		spin_unlock(&esp_chips_lock);
		free_irq(irq, NULL);
	} else
		spin_unlock(&esp_chips_lock);

	kfree(mep);