patch-2.4.19 linux-2.4.19/drivers/scsi/sim710.c

Next file: linux-2.4.19/drivers/scsi/sim710.h
Previous file: linux-2.4.19/drivers/scsi/sgiwd93.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.18/drivers/scsi/sim710.c linux-2.4.19/drivers/scsi/sim710.c
@@ -18,6 +18,9 @@
  *----------------------------------------------------------------------------
  *
  * MCA card detection code by Trent McNair.
+ * Fixes to not explicitly nul bss data from Xavier Bestel.
+ * Some multiboard fixes from Rolf Eike Beer.
+ * Auto probing of EISA config space from Trevor Hemsley.
  *
  * Various bits of code in this driver have been copied from 53c7,8xx,c,
  * which is coyright Drew Eckhardt.  The scripts for the SCSI chip are
@@ -41,6 +44,16 @@
  * and insmod parameters similar to
  *	sim710="addr:0x9000 irq:15"
  *
+ * Multiple controllers can also be set up by command line, provided the
+ * addr: parameter is specified first for each controller.  e.g.
+ *      sim710="addr:0x9000 irq:15 addr:0x8000 irq:14"
+ *
+ * To seperate the different options, ' ', '+', and ',' can be used, except
+ * that ',' can not be used in module parameters.  ' ' can be a pain, because
+ * it needs to be quoted, which causes problems with some installers.
+ * The command line above is completely equivalent to
+ *      sim710="addr:0x9000+irq:15+addr:0x8000+irq:14"
+ *
  * The complete list of options are:
  *
  * addr:0x9000		Specifies the base I/O port (or address) of the 53C710.
@@ -49,12 +62,18 @@
  * ignore:0x0a		Makes the driver ignore SCSI IDs 0 and 2.
  * nodisc:0x70		Prevents disconnects from IDs 6, 5 and 4.
  * noneg:0x10		Prevents SDTR negotiation on ID 4.
+ * disabled:1		Completely disables the driver. When present, overrides
+ *			all other options.
+ *
+ * The driver will auto-probe chip addresses and IRQs now, so typically no
+ * parameters are needed.  Auto-probing of addresses is disabled if any addr:
+ * parameters are specified.
  *
  * Current limitations:
  *
  * o  Async only
  * o  Severely lacking in error recovery
- * o  Auto detection of IRQs and chip addresses only on MCA architectures
+ * o  'debug:' should be per host really.
  *
  */
 
@@ -71,27 +90,20 @@
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/mca.h>
+#include <linux/interrupt.h>
 #include <asm/dma.h>
 #include <asm/system.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,17)
 #include <linux/spinlock.h>
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93)
-#include <asm/spinlock.h>
-#endif
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/byteorder.h>
 #include <linux/blk.h>
 
-#ifdef CONFIG_TP34V_SCSI
-
-#include <asm/tp34vhw.h>
-#define MEM_MAPPED
-
-#elif defined(CONFIG_MCA)
-
+/* All targets are I/O mapped at the moment */
 #define IO_MAPPED
 
+#if defined(CONFIG_MCA)
+
 /*
  * For each known microchannel card using the 53c710 we need a list
  * of possible IRQ and IO settings, as well as their corresponding
@@ -116,12 +128,6 @@
 
 #define MCA_004F_IRQS { 5, 9, 14 }
 
-#else
-
-/* Assume an Intel platform */
-
-#define IO_MAPPED
-
 #endif
 
 #include "scsi.h"
@@ -151,7 +157,7 @@
 
 #ifdef DEBUG
 #define DEB(m,x) if (sim710_debug & m) x
-int sim710_debug = 0;
+int sim710_debug;
 #else
 #define DEB(m,x)
 #endif
@@ -178,7 +184,7 @@
 #define STATE_BUSY		3
 #define STATE_DISABLED		4
 
-#define MAXBOARDS 2	/* Increase this and the sizes of the
+#define MAXBOARDS 4	/* Increase this and the sizes of the
 			   arrays below, if you need more.. */
 
 #ifdef MODULE
@@ -193,44 +199,15 @@
 
 #endif
 
-static int sim710_errors = 0;	/* Count of error interrupts */
-static int sim710_intrs = 0;	/* Count of all interrupts */
-static int ignore_ids = 0;	/* Accept all SCSI IDs */
-static int opt_nodisc = 0;	/* Allow disconnect on all IDs */
-static int opt_noneg = 0;	/* Allow SDTR negotiation on all IDs */
-
-#ifdef CONFIG_TP34V_SCSI
-
-/* Special hardwired case for Tadpole TP34V at the moment, otherwise
- * boot parameters 'sim710=addr:0x8000,irq:15' (for example) must be given.
- */
-
-static int no_of_boards = 2;
-
-static unsigned int bases[MAXBOARDS] = {
-	TP34V_SCSI0_BASE, TP34V_SCSI1_BASE
-};
-static unsigned int irq_vectors[MAXBOARDS] = {
-	TP34V_SCSI0_VECTOR, TP34V_SCSI1_VECTOR
-};
-static unsigned int irq_index[MAXBOARDS] = {
-	TP34V_SCSI0_IRQ_INDEX, TP34V_SCSI1_IRQ_INDEX
-};
-
-#else
-
-/* All other cases use boot/module params, or auto-detect */
-
-static int no_of_boards = 0;
-
-static unsigned int bases[MAXBOARDS] = {
-	0
-};
-static unsigned int irq_vectors[MAXBOARDS] = {
-	0
-};
-
-#endif
+static int sim710_errors;		/* Count of error interrupts */
+static int sim710_intrs;		/* Count of all interrupts */
+static int ignore_ids[MAXBOARDS];	/* Accept all SCSI IDs */
+static int opt_nodisc[MAXBOARDS];	/* Allow disconnect on all IDs */
+static int opt_noneg[MAXBOARDS];	/* Allow SDTR negotiation on all IDs */
+static int hostdata_order;		/* Encoded size of hostdata for free_pages() */
+static int no_of_boards;		/* Actual number of boards/chips */
+static unsigned int bases[MAXBOARDS];	/* Base addresses of chips */
+static unsigned int irq_vectors[MAXBOARDS]; /* IRQ vectors used by chips */
 
 /* The SCSI Script!!! */
 
@@ -249,7 +226,6 @@
 
 #define MAX_SG		128	/* Scatter/Gather elements */
 
-
 #define MAX_MSGOUT	8
 #define MAX_MSGIN	8
 #define MAX_CMND	12
@@ -263,6 +239,9 @@
     u8 negotiate;
     u8 reselected_identify;
     u8 msgin_buf[MAX_MSGIN];
+    u8 msg_reject;
+    u32 test1_src __attribute__ ((aligned (4)));
+    u32 test1_dst;
 
     struct sim710_target {
 	Scsi_Cmnd *cur_cmd;
@@ -294,82 +273,127 @@
 
 
 /*
- * Function: int param_setup(char *str)
+ * Function : static void ncr_dump (struct Scsi_Host *host)
+ *
+ * Purpose :  Dump (possibly) useful info
+ *
+ * Inputs : host - pointer to this host adapter's structure
  */
 
-#ifdef MODULE
-#define ARG_SEP ' '
-#else
-#define ARG_SEP ','
-#endif
+static void
+ncr_dump (struct Scsi_Host *host)
+{
+    unsigned long flags;
+    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
+       host->hostdata[0];
 
-static int
+    save_flags(flags);
+    cli();
+    printk("scsi%d: Chip register contents:\n", host->host_no);
+    printk(" (script at virt %p, bus %lx)\n",
+           hostdata->script, virt_to_bus(hostdata->script));
+    printk(" 00  sien:  %02x  sdid:  %02x  scntl1:%02x  scntl0:%02x\n"
+	   " 04  socl:  %02x  sodl:  %02x  sxfer: %02x  scid:  %02x\n"
+	   " 08  sbcl:  %02x  sbdl:  %02x  sidl:  %02x  sfbr:  %02x\n"
+	   " 0C  sstat2:%02x  sstat1:%02x  sstat0:%02x  dstat: %02x\n"
+	   " 10  dsa:   %08x\n"
+	   " 14  ctest3:%02x  ctest2:%02x  ctest1:%02x  ctest0:%02x\n"
+	   " 18  ctest7:%02x  ctest6:%02x  ctest5:%02x  ctest4:%02x\n"
+	   " 1C  temp:  %08x\n"
+	   " 20  lcrc:  %02x  ctest8:%02x  istat: %02x  dfifo: %02x\n"
+	   " 24  dbc:   %08x  dnad:  %08x  dsp:   %08x\n"
+	   " 30  dsps:  %08x  scratch:%08x\n"
+	   " 38  dcntl: %02x  dwt:   %02x  dien:  %02x  dmode: %02x\n"
+	   " 3C  adder: %08x\n",
+	  NCR_read8(SIEN_REG), NCR_read8(SDID_REG), NCR_read8(SCNTL1_REG),
+	  NCR_read8(SCNTL0_REG), NCR_read8(SOCL_REG), NCR_read8(SODL_REG),
+	  NCR_read8(SXFER_REG), NCR_read8(SCID_REG), NCR_read8(SBCL_REG),
+	  NCR_read8(SBDL_REG), NCR_read8(SIDL_REG), NCR_read8(SFBR_REG),
+	  NCR_read8(SSTAT2_REG), NCR_read8(SSTAT1_REG), NCR_read8(SSTAT0_REG),
+	  NCR_read8(DSTAT_REG), NCR_read32(DSA_REG), NCR_read8(CTEST3_REG),
+	  NCR_read8(CTEST2_REG), NCR_read8(CTEST1_REG), NCR_read8(CTEST0_REG),
+	  NCR_read8(CTEST7_REG), NCR_read8(CTEST6_REG), NCR_read8(CTEST5_REG),
+	  NCR_read8(CTEST4_REG), NCR_read8(TEMP_REG), NCR_read8(LCRC_REG),
+	  NCR_read8(CTEST8_REG), NCR_read8(ISTAT_REG), NCR_read8(DFIFO_REG),
+	  NCR_read32(DBC_REG), NCR_read32(DNAD_REG), NCR_read32(DSP_REG),
+	  NCR_read32(DSPS_REG), NCR_read32(SCRATCH_REG), NCR_read8(DCNTL_REG),
+	  NCR_read8(DWT_REG), NCR_read8(DIEN_REG), NCR_read8(DMODE_REG),
+	  NCR_read32(ADDER_REG));
+
+    restore_flags(flags);
+}
+
+
+/*
+ * Function: int param_setup(char *str)
+ */
+
+__init int
 param_setup(char *str)
 {
     char *cur = str;
-    char *pc, *pv;
+    char *p, *pc, *pv;
     int val;
-    int base;
     int c;
 
     no_of_boards = 0;
-    while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+    while (no_of_boards < MAXBOARDS && cur != NULL &&
+		(pc = strchr(cur, ':')) != NULL) {
 	char *pe;
 
 	val = 0;
 	pv = pc;
 	c = *++pv;
 
-	if (c == 'n')
-	    val = 0;
-	else if	(c == 'y')
-	    val = 1;
-	else {
-	    base = 0;
-	    val = (int) simple_strtoul(pv, &pe, base);
-	}
+	val = (int) simple_strtoul(pv, &pe, 0);
+
 	if (!strncmp(cur, "addr:", 5)) {
-	    bases[0] = val;
-	    no_of_boards = 1;
+	    bases[no_of_boards++] = val;
+	}
+#ifdef DEBUG
+	else if (!strncmp(cur, "debug:", 6)) {
+	    sim710_debug = val;
+	}
+#endif
+	else if (no_of_boards == 0) {
+	    printk("sim710: Invalid parameters, addr: must come first\n");
+	    no_of_boards = -1;
+	    return 1;
 	}
 	else if	(!strncmp(cur, "irq:", 4))
-	    irq_vectors[0] = val;
+	    irq_vectors[no_of_boards-1] = val;
 	else if	(!strncmp(cur, "ignore:", 7))
-	    ignore_ids = val;
+	    ignore_ids[no_of_boards-1] = val;
 	else if	(!strncmp(cur, "nodisc:", 7))
-	    opt_nodisc = val;
+	    opt_nodisc[no_of_boards-1] = val;
 	else if	(!strncmp(cur, "noneg:", 6))
-	    opt_noneg = val;
-	else if	(!strncmp(cur, "disabled:", 5)) {
+	    opt_noneg[no_of_boards-1] = val;
+	else if	(!strncmp(cur, "disabled:", 9)) {
 	    no_of_boards = -1;
 	    return 1;
 	}
-#ifdef DEBUG
-	else if (!strncmp(cur, "debug:", 6)) {
-	    sim710_debug = val;
+	else {
+	    printk("sim710: unexpected boot option '%.*s'\n", (int)(pc-cur+1), cur);
+	    no_of_boards = -1;
+	    return 1;
 	}
-#endif
-	else
-	    printk("sim710: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
 
-	if ((cur = strchr(cur, ARG_SEP)) != NULL)
-	    ++cur;
+	/* Allow ',', ' ', or '+' seperators.  Used to be ',' at boot and
+	 * ' ' for module load, some installers crap out on the space and
+	 * insmod doesn't like the comma.
+	 */
+       if ((p = strchr(cur, ',')) || (p = strchr(cur, ' ')) ||
+               (p = strchr(cur, '+')))
+           cur = p + 1;
+        else
+           break;
     }
     return 1;
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13)
 #ifndef MODULE
 __setup("sim710=", param_setup);
 #endif
-#else
-/* Old boot param syntax support */
-void
-sim710_setup(char *str, int *ints)
-{
-    param_setup(str);
-}
-#endif
 
 
 /*
@@ -398,22 +422,6 @@
 
 
 /*
- * Function: static void disable (struct Scsi_Host *host)
- */
-
-static void
-disable (struct Scsi_Host *host)
-{
-    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
-	host->hostdata[0];
-
-    hostdata->state = STATE_DISABLED;
-    printk (KERN_ALERT "scsi%d : disabled.  Unload and reload\n",
-		            host->host_no);
-}
-
-
-/*
  * Function : static int ncr_halt (struct Scsi_Host *host)
  *
  * Purpose : halts the SCSI SCRIPTS(tm) processor on the NCR chip
@@ -431,6 +439,8 @@
     struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
 	host->hostdata[0];
     int stage;
+    int timeout;
+    int res = 0;
 
     save_flags(flags);
     cli();
@@ -438,8 +448,10 @@
        Stage 1 : set ABORT
        Stage 2 : eat all but abort interrupts
        Stage 3 : eat all interrupts
+       We loop for 50000 times with a delay of 10us which should give us
+       about half a second.
      */
-    for (stage = 0;;) {
+    for (stage = 0, timeout = 50000; timeout; timeout--) {
 	if (stage == 1) {
 	    DEB(DEB_HALT, printk("ncr_halt: writing ISTAT_ABRT\n"));
 	    NCR_write8(ISTAT_REG, ISTAT_ABRT);
@@ -460,9 +472,8 @@
 		    NCR_write8(ISTAT_REG, 0);
 		    ++stage;
 		} else {
-		    printk(KERN_ALERT "scsi%d : could not halt NCR chip\n",
-			host->host_no);
-		    disable (host);
+		    res = 1;
+		    break;
 	    	}
     	    }
 	}
@@ -472,10 +483,18 @@
 	    else if (stage == 3)
 		break;
 	}
+	udelay(10);
     }
-    hostdata->state = STATE_HALTED;
     restore_flags(flags);
-    return 0;
+
+    if (timeout == 0 || res) {
+	printk(KERN_ALERT "scsi%d: could not halt NCR chip\n", host->host_no);
+	return 1;
+    }
+    else {
+	hostdata->state = STATE_HALTED;
+	return 0;
+    }
 }
 
 /*
@@ -494,16 +513,9 @@
 sim710_soft_reset (struct Scsi_Host *host)
 {
     unsigned long flags;
-#ifdef CONFIG_TP34V_SCSI
-    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
-	host->hostdata[0];
-#endif
 
     save_flags(flags);
     cli();
-#ifdef CONFIG_TP34V_SCSI
-    tpvic.loc_icr[irq_index[hostdata->chip]].icr = 0x80;
-#endif
     /*
      * Do a soft reset of the chip so that everything is
      * reinitialized to the power-on state.
@@ -528,6 +540,7 @@
 
     mdelay(1000);				/* Let devices recover */
 
+    NCR_write32(SCRATCH_REG, 0);
     NCR_write8(DCNTL_REG, DCNTL_10_COM | DCNTL_700_CF_3);
     NCR_write8(CTEST7_REG, CTEST7_10_CDIS|CTEST7_STD);
     NCR_write8(DMODE_REG, DMODE_10_BL_8 | DMODE_10_FC2);
@@ -544,11 +557,6 @@
     NCR_write8(SIEN_REG_700,
 	    SIEN_PAR | SIEN_700_STO | SIEN_RST | SIEN_UDC | SIEN_SGE | SIEN_MA);
 
-
-#ifdef CONFIG_TP34V_SCSI
-    tpvic.loc_icr[irq_index[hostdata->chip]].icr = 0x30 | TP34V_SCSI0n1_IPL;
-#endif
-
     restore_flags(flags);
 }
 
@@ -577,6 +585,12 @@
     	virt_to_bus((void *)&(hostdata->reselected_identify)));
     patch_abs_32 (hostdata->script, 0, msgin_buf, 
     	virt_to_bus((void *)&(hostdata->msgin_buf[0])));
+    patch_abs_32 (hostdata->script, 0, msg_reject, 
+	virt_to_bus((void *)&(hostdata->msg_reject)));
+    patch_abs_32 (hostdata->script, 0, test1_src, 
+	virt_to_bus((void *)&(hostdata->test1_src)));
+    patch_abs_32 (hostdata->script, 0, test1_dst, 
+	virt_to_bus((void *)&(hostdata->test1_dst)));
     hostdata->state = STATE_INITIALISED;
     hostdata->negotiate = 0xff;
 }
@@ -587,7 +601,7 @@
  * spurious request from the target.  Don't really expect target initiated
  * SDTRs, because we always negotiate on the first command.  Could still
  * get them though..
- * The chip is currently paused with ACK asserted o the last byte of the
+ * The chip is currently paused with ACK asserted on the last byte of the
  * SDTR.
  * resa is the resume address if the message is in response to our outgoing
  * SDTR.  Only possible on initial identify.
@@ -739,6 +753,12 @@
 		host->host_no);
 	    resume_offset = Ent_resume_cmd;
 	}
+	else if (sbcl == SBCL_PHASE_STATIN) {
+	    /* Some devices do this on parity error, at least */
+	    printk("scsi%d: Unexpected switch to STATUSIN on initial message out\n",
+		host->host_no);
+	    resume_offset = Ent_end_data_trans;
+	}
 	else {
 	    printk("scsi%d: Unexpected phase change to %s on initial msgout\n",
 		host->host_no, sbcl_to_phase(sbcl));
@@ -801,6 +821,14 @@
 	    resume_offset = Ent_resume_pmm;
 	}
     }
+    else if (sbcl == SBCL_PHASE_STATIN) {
+	/* Change to Status In at some random point; probably wants to report a
+	 * parity error or similar.
+	 */
+	printk("scsi%d: Unexpected phase change to STATUSIN at index 0x%x\n",
+		host->host_no, index);
+	resume_offset = Ent_end_data_trans;
+    }
     else {
 	printk("scsi%d: Unexpected phase change to %s at index 0x%x\n",
 		host->host_no, sbcl_to_phase(sbcl), index);
@@ -868,12 +896,6 @@
 	printk("scsi%d: int_data_bad_phase, phase %s (%x)\n",
 		host->host_no, sbcl_to_phase(sbcl), sbcl);
 	break;
-    case A_int_bad_extmsg1a:
-    case A_int_bad_extmsg1b:
-    case A_int_bad_extmsg2a:
-    case A_int_bad_extmsg2b:
-    case A_int_bad_extmsg3a:
-    case A_int_bad_extmsg3b:
     case A_int_bad_msg1:
     case A_int_bad_msg2:
     case A_int_bad_msg3:
@@ -917,21 +939,22 @@
 static void
 sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
-    unsigned int flags;
     struct Scsi_Host * host = (struct Scsi_Host *)dev_id;
     struct sim710_hostdata *hostdata = (struct sim710_hostdata *)host->hostdata[0];
     Scsi_Cmnd * cmd;
     unsigned char istat, dstat;
     unsigned char sstat0;
-    u32 dsps, resume_offset = 0;
+    u32 scratch, dsps, resume_offset = 0;
 
-    save_flags(flags);
-    cli();
-    sim710_intrs++;
-    while ((istat = NCR_read8(ISTAT_REG)) & (ISTAT_SIP|ISTAT_DIP)) {
+    istat = NCR_read8(ISTAT_REG);
+    if (!(istat & (ISTAT_SIP|ISTAT_DIP)))
+	return;
+    else {
+	sim710_intrs++;
 	dsps = NCR_read32(DSPS_REG);
 	hostdata->state = STATE_HALTED;
 	sstat0 = dstat = 0;
+	scratch = NCR_read32(SCRATCH_REG);
 	if (istat & ISTAT_SIP) {
 	    sstat0 = NCR_read8(SSTAT0_REG);
 	}
@@ -944,7 +967,13 @@
 		"dstat %02x, dsp [%04x], scratch %02x\n",
 	    host->host_no, sim710_intrs, istat, sstat0, dstat,
 	    (u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script,
-	    NCR_read32(SCRATCH_REG)));
+	    scratch));
+	if (scratch & 0x100) {
+	    u8 *p = hostdata->msgin_buf;
+
+	    DEB(DEB_INTS, printk("  msgin_buf: %02x %02x %02x %02x\n",
+			p[0], p[1], p[2], p[3]));
+	}
 	if ((dstat & DSTAT_SIR) && dsps == A_int_reselected) {
 	    /* Reselected.  Identify the target from LCRC_REG, and
 	     * update current command.  If we were trying to select
@@ -1001,12 +1030,7 @@
 	    hostdata->target[cmd->target].cur_cmd = NULL;
 	    resume_offset = Ent_reselect;
 	}
-	else if (dstat & DSTAT_SIR)
-	    resume_offset = handle_script_int(host, cmd);
-	else if (sstat0 & SSTAT0_MA) {
-	    resume_offset = handle_phase_mismatch(host, cmd);
-	}
-	else if (sstat0 & (SSTAT0_MA|SSTAT0_SGE|SSTAT0_UDC|SSTAT0_RST|SSTAT0_PAR)) {
+	else if (sstat0 & (SSTAT0_SGE|SSTAT0_UDC|SSTAT0_RST|SSTAT0_PAR)) {
 	    printk("scsi%d: Serious error, sstat0 = %02x\n", host->host_no,
 			    sstat0);
 	    sim710_errors++;
@@ -1018,6 +1042,10 @@
 	    sim710_errors++;
 	    /* resume_offset is zero, which will cause a host reset */
 	}
+	else if (dstat & DSTAT_SIR)
+	    resume_offset = handle_script_int(host, cmd);
+	else if (sstat0 & SSTAT0_MA)
+	    resume_offset = handle_phase_mismatch(host, cmd);
 	else if (dstat & DSTAT_IID) {
 	    /* This can be due to a quick reselect while doing a WAIT
 	     * DISCONNECT.
@@ -1043,18 +1071,19 @@
 #ifdef DEBUG_LIMIT_INTS
 	if (sim710_intrs < DEBUG_LIMIT_INTS)
 #endif
-	NCR_write32(DSP_REG, virt_to_bus(hostdata->script+resume_offset/4));
+	{
+	    NCR_write32(SCRATCH_REG, 0);
+	    NCR_write32(DSP_REG, virt_to_bus(hostdata->script+resume_offset/4));
+	}
 	if (resume_offset == Ent_reselect)
 	    run_process_issue_queue(hostdata);
     }
     else {
 	printk("scsi%d: Failed to handle interrupt.  Failing commands "
 		"and resetting SCSI bus and chip\n", host->host_no);
-	mdelay(4000);		/* Give chance to read screen!! */
+	mdelay(1000);		/* Give chance to read screen!! */
 	full_reset(host);
     }
-
-    restore_flags(flags);
 }
 
 
@@ -1100,9 +1129,9 @@
     memcpy(targdata->dsa_cdb, cmd->cmnd, MAX_CMND);
 
     targdata->dsa_msgout[0] =
-		IDENTIFY((opt_nodisc & (1<<cmd->target)) ? 0 : 1 ,0);
+		IDENTIFY((opt_nodisc[hostdata->chip] & (1<<cmd->target)) ? 0 : 1 ,0);
     if (hostdata->negotiate & (1 << cmd->target)) {
-	if (opt_noneg & (1 << cmd->target)) {
+	if (opt_noneg[hostdata->chip] & (1 << cmd->target)) {
 	    hostdata->negotiate ^= (1 << cmd->target);
 	    targdata->dsa[DSA_MSGOUT] = 1;
 	}
@@ -1143,16 +1172,10 @@
 		cmd->request_bufflen;
 
 	if (datain) {
-#ifdef CONFIG_TP34V_SCSI
-	    cache_clear(virt_to_phys((void *)vbuf), cnt);
-#endif
 	    *dip++	= cnt;
 	    *dip++	= bbuf;
 	}
 	if (dataout) {
-#ifdef CONFIG_TP34V_SCSI
-	    cache_push(virt_to_phys((void *)vbuf), cnt);
-#endif
 	    *dop++	= cnt;
 	    *dop++	= bbuf;
 	}
@@ -1288,7 +1311,7 @@
     save_flags(flags);
     cli();
 
-    if (ignore_ids & (1 << cmd->target)) {
+    if (ignore_ids[hostdata->chip] & (1 << cmd->target)) {
 	printk("scsi%d: ignoring target %d\n", host->host_no, cmd->target);
 	cmd->result = (DID_BAD_TARGET << 16);
 	done(cmd);
@@ -1320,18 +1343,25 @@
 }
 
 
-int
+__init int
 sim710_detect(Scsi_Host_Template * tpnt)
 {
-    unsigned char irq_vector;
     unsigned char scsi_id;
     unsigned int base_addr;
     struct Scsi_Host * host = NULL;
     struct sim710_hostdata *hostdata;
+    unsigned long timeout;
+    unsigned long irq_mask;
+    int requested_irq;
+    int probed_irq;
+    u32 dsps;
     int chips = 0;
+    int limit;
     int indx;
     int revision;
-    int order, size;
+    int size;
+    volatile u8 tmp;
+    struct Scsi_Host *our_hosts[MAXBOARDS+1];
 
 #ifdef MODULE
     if (sim710)
@@ -1433,83 +1463,190 @@
     }
 #endif
 
+#ifdef CONFIG_EISA
+    /* Auto probe, if no boards specified in boot parameters */
+    if (no_of_boards == 0) {
+	int io_addr;
+	/* reverse probe, so my on-board controller at 0x9000 is always scsi0 */
+	for (io_addr = 0x9000; no_of_boards < MAXBOARDS && io_addr >= 0x1000; io_addr -= 0x1000) {
+	    if (request_region(io_addr, 0x40, "sim710") != NULL) {
+		int id0 = inw(io_addr + 0xc80);
+		int id1 = inw(io_addr + 0xc82);
+		/* The on-board controller on my Proliant 2000 is 0x1044,
+		 * my EISA card is 0x1144.
+		 */
+		if (id0 == 0x110e && (id1 == 0x1044 || id1 == 0x1144)) {
+		    bases[no_of_boards] = io_addr;
+#if 0
+		    /* This should detect the IRQ, but I havn't proved it for
+		     * myself.  Leave the old probe code active for now, as
+		     * no-one has reported problems with it.
+		     */
+		    switch (inb(io_addr + 0xc88)) {
+			case (0x00):
+			    irq_vectors[no_of_boards] = 11;
+			    break;
+			case (0x01):
+			    irq_vectors[no_of_boards] = 14;
+			    break;
+			case (0x02):
+			    irq_vectors[no_of_boards] = 15;
+			    break;
+			case (0x03):
+			    irq_vectors[no_of_boards] = 10;
+			    break;
+			case (0x04):
+			    irq_vectors[no_of_boards] = 9;
+			    break;
+			default:
+			    printk("sim710.c: irq nasty\n");
+		    }
+#endif
+		    no_of_boards++;
+		}
+		release_region(io_addr, 64);
+	    }
+	}
+    }
+#endif
     if (!no_of_boards) {
-       printk("sim710: No NCR53C710 adapter found.\n");
-       return 0;
+	printk("sim710: No NCR53C710 adapter found.\n");
+	return 0;
     }
 
     size = sizeof(struct sim710_hostdata);
-    order = 0;
-    while (size > (PAGE_SIZE << order))
-	order++;
-    size = PAGE_SIZE << order;
+    hostdata_order = 0;
+    while (size > (PAGE_SIZE << hostdata_order))
+	hostdata_order++;
+    size = PAGE_SIZE << hostdata_order;
 
     DEB(DEB_ANY, printk("sim710: hostdata %d bytes, size %d, order %d\n",
-	sizeof(struct sim710_hostdata), size, order));
+	sizeof(struct sim710_hostdata), size, hostdata_order));
 
     tpnt->proc_name = "sim710";
 
-    for(indx = 0; indx < no_of_boards; indx++) {
-        unsigned long page = __get_free_pages(GFP_ATOMIC, order);
+    memset(our_hosts, 0, sizeof(our_hosts));
+    for (indx = 0; indx < no_of_boards; indx++) {
+        unsigned long page = __get_free_pages(GFP_ATOMIC, hostdata_order);
         if(page == 0UL)
         {
-        	printk(KERN_WARNING "sim710: out of memory registering board %d.\n", indx);
-        	break;
+	    printk(KERN_WARNING "sim710: out of memory registering board %d.\n", indx);
+	    break;
         }
 	host = scsi_register(tpnt, 4);
-	if(host == NULL)
-		break;
+	if(host == NULL) {
+	    free_pages(host->hostdata[0], hostdata_order);
+	    break;
+	}
+	our_hosts[chips] = host;
 	host->hostdata[0] = page;
 	hostdata = (struct sim710_hostdata *)host->hostdata[0];
 	memset(hostdata, 0, size);
-#ifdef CONFIG_TP34V_SCSI
-	cache_push(virt_to_phys(hostdata), size);
-	cache_clear(virt_to_phys(hostdata), size);
-	kernel_set_cachemode((void *)hostdata,size,IOMAP_NOCACHE_SER);
-#endif
 	scsi_id = 7;
 	base_addr = bases[indx];
-	irq_vector = irq_vectors[indx];
-	printk("sim710: Configuring Sim710 (SCSI-ID %d) at %x, IRQ %d\n",
-	    		scsi_id, base_addr, irq_vector);
+	requested_irq = irq_vectors[indx];
+	printk("scsi%d: Configuring Sim710 (SCSI-ID %d) at %x, IRQ %d\n",
+			host->host_no, scsi_id, base_addr, requested_irq);
 	DEB(DEB_ANY, printk("sim710: hostdata = %p (%d bytes), dsa0 = %p\n",
 			hostdata, sizeof(struct sim710_hostdata),
 			 hostdata->target[0].dsa));
 	hostdata->chip = indx;
-	host->irq = irq_vector;
+	host->irq = requested_irq;
 	host->this_id = scsi_id;
 	host->unique_id = base_addr;
 	host->base = base_addr;
+	hostdata->msg_reject = MESSAGE_REJECT;
 
-	ncr_halt(host);
-
+	if (ncr_halt(host)) {
+	    free_pages(host->hostdata[0], hostdata_order);
+	    scsi_unregister (host);
+	    printk("scsi%d: Failed to initialise 53c710 at address %x\n",
+			host->host_no, base_addr);
+	    continue;
+	}
+	DEB(DEB_ANY,ncr_dump(host));
 	revision = (NCR_read8(CTEST8_REG) & 0xF0) >> 4;
 	printk("scsi%d: Revision 0x%x\n",host->host_no,revision);
-
 	sim710_soft_reset(host);
 
 	sim710_driver_init(host);
 
-#ifdef CONFIG_TP34V_SCSI
-	if (request_irq(irq_vector,do_sim710_intr_handle, 0, "sim710", host))
-#else
-	if (request_irq(irq_vector,do_sim710_intr_handle, SA_INTERRUPT, "sim710", host))
-#endif
-	{
-	    printk("scsi%d : IRQ%d not free, detaching\n",
-	    		host->host_no, host->irq);
-
-	    scsi_unregister (host);
+	request_region((u32)host->base, 64, "sim710");
+	/* Now run test1 */
+	hostdata->test1_src = 0x53c710aa;
+	hostdata->test1_dst = 0x76543210;
+	NCR_write32(DSPS_REG, 0x89abcdef);
+	irq_mask = probe_irq_on();
+	NCR_write32(DSP_REG, virt_to_bus(hostdata->script+Ent_test1/4));
+	timeout = 5;
+	while (hostdata->test1_dst != hostdata->test1_src && timeout--)
+	    mdelay(100);
+	tmp = NCR_read8(ISTAT_REG);
+	tmp = NCR_read8(SSTAT0_REG);
+	udelay(10);
+	tmp = NCR_read8(DSTAT_REG);
+	probed_irq = probe_irq_off(irq_mask);
+	if (requested_irq == 0) {
+	    if (probed_irq > 0) {
+		printk("scsi%d: Chip is using IRQ %d\n", host->host_no,
+			probed_irq);
+		requested_irq = host->irq = probed_irq;
+	    }
+	    else {
+		printk("scsi%d: Failed to probe for IRQ (returned %d)\n",
+			host->host_no, probed_irq);
+		ncr_halt(host);
+		free_pages(host->hostdata[0], hostdata_order);
+		scsi_unregister (host);
+		release_region((u32)host->base, 64);
+		continue;
+	    }
 	}
-	else {
-#ifdef IO_MAPPED
-	    request_region((u32)host->base, 64, "sim710");
-#endif
-	    chips++;
+	else if (probed_irq > 0 && probed_irq != requested_irq)
+	    printk("scsi%d: WARNING requested IRQ %d, but probed as %d\n",
+			host->host_no, requested_irq, probed_irq);
+	else if (probed_irq <= 0)
+	    printk("scsi%d: WARNING IRQ probe failed, (returned %d)\n",
+			host->host_no, probed_irq);
+  
+	dsps = NCR_read32(DSPS_REG);
+	if (hostdata->test1_dst != 0x53c710aa || dsps != A_int_test1) {
+	    if (hostdata->test1_dst != 0x53c710aa)
+		printk("scsi%d: test 1 FAILED: data: exp 0x53c710aa, got 0x%08x\n",
+			host->host_no, hostdata->test1_dst);
+	    if (dsps != A_int_test1)
+		printk("scsi%d: test 1 FAILED: dsps: exp 0x%08x, got 0x%08x\n",
+			host->host_no, A_int_test1, dsps);
+	    ncr_dump(host);
+	    ncr_halt(host);
+	    free_pages(host->hostdata[0], hostdata_order);
+	    scsi_unregister (host);
+	    release_region((u32)host->base, 64);
+	    continue;
 	}
+	printk("scsi%d: test 1 completed ok.\n", host->host_no);
+
 	NCR_write32(DSP_REG, virt_to_bus(hostdata->script+Ent_reselect/4));
 	hostdata->state = STATE_IDLE;
+	chips++;
     }
+    /* OK, now run down our_hosts[] calling request_irq(... SA_SHIRQ ...).
+     * Couldn't call request_irq earlier, as probing would have failed.
+     */
+    for (indx = 0, limit = chips; indx < limit; indx++) {
+	host = our_hosts[indx];
+	if (request_irq(host->irq, do_sim710_intr_handle,
+                       SA_INTERRUPT | SA_SHIRQ, "sim710", host))
+	{
+	    printk("scsi%d : IRQ%d not free, detaching\n",
+			host->host_no, host->irq);
+	    ncr_halt(host);
+	    free_pages(host->hostdata[0], hostdata_order);
+	    scsi_unregister (host);
+	    chips--;
+	}
+    }
+
     return chips;
 }
 
@@ -1557,12 +1694,34 @@
 	    host->hostdata[0];
     int target;
     Scsi_Cmnd *cmd;
+    u32 istat, dstat = 0, sstat0 = 0, sstat1 = 0, dsp, dsps, scratch;
+    unsigned long flags;
 
-    ncr_halt(host);
-    printk("scsi%d: dsp = %08x (script[0x%04x]), scratch = %08x\n",
-	host->host_no, NCR_read32(DSP_REG),
-	((u32)bus_to_virt(NCR_read32(DSP_REG)) - (u32)hostdata->script)/4,
-	NCR_read32(SCRATCH_REG));
+    save_flags(flags);
+    cli();
+
+    istat = NCR_read8(ISTAT_REG);
+    if (istat & ISTAT_SIP) {
+	sstat0 = NCR_read8(SSTAT0_REG);
+	sstat1 = NCR_read8(SSTAT1_REG);
+	udelay(10);
+    }
+    if (istat & ISTAT_DIP)
+	dstat = NCR_read8(DSTAT_REG);
+
+    if (ncr_halt(host)) {
+	restore_flags(flags);
+	return FAILED;
+    }
+    restore_flags(flags);
+    dsp = NCR_read32(DSP_REG);
+    dsps = NCR_read32(DSPS_REG);
+    scratch = NCR_read32(SCRATCH_REG);
+    printk("scsi%d: istat = %02x, sstat0 = %02x, sstat1 = %02x, dstat = %02x\n",
+		host->host_no, istat, sstat0, sstat1, dstat);
+    printk("scsi%d: dsp = %08x (script[0x%04x]), dsps = %08x, scratch = %08x\n",
+		host->host_no, dsp,
+		((u32)bus_to_virt(dsp) - (u32)hostdata->script)/4, dsps, scratch);
 
     for (target = 0; target < 7; target++) {
 	if ((cmd = hostdata->target[target].cur_cmd)) {
@@ -1604,10 +1763,10 @@
 int
 sim710_release(struct Scsi_Host *host)
 {
+    ncr_halt(host);
+    free_pages(host->hostdata[0], hostdata_order);
     free_irq(host->irq, host);
-#ifdef IO_MAPPED
     release_region((u32)host->base, 64);
-#endif
     return 1;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)