ncr5380: Split NCR5380_init() into two functions

This patch splits the NCR5380_init() function into two parts, similar
to the scheme used with atari_NCR5380.c. This avoids two problems.

Firstly, NCR5380_init() may perform a bus reset, which would cause the
chip to assert IRQ. The chip is unable to mask its bus reset interrupt.
Drivers can't call request_irq() before calling NCR5380_init(), because
initialization must happen before the interrupt handler executes. If
driver initialization causes an interrupt it may be problematic on some
platforms. To avoid that, first move the bus reset code into
NCR5380_maybe_reset_bus().

Secondly, NCR5380_init() contains some board-specific interrupt setup code
for the NCR53C400 that does not belong in the core driver. In moving this
code, better not re-order interrupt initialization and bus reset. Again,
the solution is to move the bus reset code into NCR5380_maybe_reset_bus().

Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Tested-by: Ondrej Zary <linux@rainbow-software.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 78d7858..1f9028a 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -777,8 +777,7 @@
 
 static int NCR5380_init(struct Scsi_Host *instance, int flags)
 {
-	int i, pass;
-	unsigned long timeout;
+	int i;
 	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
 
 	if(in_interrupt())
@@ -831,18 +830,26 @@
 		NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
 	}
 #endif
+	return 0;
+}
 
-	/* 
-	 * Detect and correct bus wedge problems.
-	 *
-	 * If the system crashed, it may have crashed in a state 
-	 * where a SCSI command was still executing, and the 
-	 * SCSI bus is not in a BUS FREE STATE.
-	 *
-	 * If this is the case, we'll try to abort the currently
-	 * established nexus which we know nothing about, and that
-	 * failing, do a hard reset of the SCSI bus 
-	 */
+/**
+ * NCR5380_maybe_reset_bus - Detect and correct bus wedge problems.
+ * @instance: adapter to check
+ *
+ * If the system crashed, it may have crashed with a connected target and
+ * the SCSI bus busy. Check for BUS FREE phase. If not, try to abort the
+ * currently established nexus, which we know nothing about. Failing that
+ * do a bus reset.
+ *
+ * Note that a bus reset will cause the chip to assert IRQ.
+ *
+ * Returns 0 if successful, otherwise -ENXIO.
+ */
+
+static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance)
+{
+	int pass;
 
 	for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) {
 		switch (pass) {
@@ -850,7 +857,6 @@
 		case 3:
 		case 5:
 			printk(KERN_INFO "scsi%d: SCSI bus busy, waiting up to five seconds\n", instance->host_no);
-			timeout = jiffies + 5 * HZ;
 			NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, 0, 5*HZ);
 			break;
 		case 2:
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index 24c7841..2057eaa 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -318,6 +318,7 @@
 static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible);
 #endif
 static int NCR5380_init(struct Scsi_Host *instance, int flags);
+static int NCR5380_maybe_reset_bus(struct Scsi_Host *);
 static void NCR5380_exit(struct Scsi_Host *instance);
 static void NCR5380_information_transfer(struct Scsi_Host *instance);
 #ifndef DONT_USE_INTR
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index 8996a6c..c7dc65e 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -240,6 +240,8 @@
 
 	NCR5380_init(host, 0);
 
+	NCR5380_maybe_reset_bus(host);
+
         priv(host)->ctrl = 0;
         writeb(0, priv(host)->base + CTRL);
 
diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
index aa5310b..ca0f31d 100644
--- a/drivers/scsi/arm/oak.c
+++ b/drivers/scsi/arm/oak.c
@@ -145,6 +145,8 @@
 
 	NCR5380_init(host, 0);
 
+	NCR5380_maybe_reset_bus(host);
+
 	ret = scsi_add_host(host, &ec->dev);
 	if (ret)
 		goto out_unmap;
diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c
index 8d2984d..2c0fd76 100644
--- a/drivers/scsi/dmx3191d.c
+++ b/drivers/scsi/dmx3191d.c
@@ -97,6 +97,8 @@
 
 	NCR5380_init(shost, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E);
 
+	NCR5380_maybe_reset_bus(shost);
+
 	pci_set_drvdata(pdev, shost);
 
 	error = scsi_add_host(shost, &pdev->dev);
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index 43c1739..02a5532 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -237,6 +237,8 @@
 
 		NCR5380_init(instance, 0);
 
+		NCR5380_maybe_reset_bus(instance);
+
 		NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);	/* Enable int's */
 		if (overrides[current_override].irq != IRQ_AUTO)
 			instance->irq = overrides[current_override].irq;
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 4559fbc7..6f5fdf6 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -422,6 +422,8 @@
 
 		NCR5380_init(instance, flags);
 
+		NCR5380_maybe_reset_bus(instance);
+
 		if (overrides[current_override].irq != IRQ_AUTO)
 			instance->irq = overrides[current_override].irq;
 		else
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index e147f56..c316ff7 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -384,6 +384,8 @@
 
 	NCR5380_init(instance, 0);
 
+	NCR5380_maybe_reset_bus(instance);
+
 	if (overrides[current_override].irq != IRQ_AUTO)
 	    instance->irq = overrides[current_override].irq;
 	else 
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index d06ae1d..d5e6b67 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -215,6 +215,8 @@
 
 	NCR5380_init(instance, 0);
 
+	NCR5380_maybe_reset_bus(instance);
+
 	if (overrides[current_override].irq != IRQ_AUTO)
 	    instance->irq = overrides[current_override].irq;
 	else