patch-1.3.60 linux/drivers/scsi/g_NCR5380.c

Next file: linux/drivers/scsi/g_NCR5380.h
Previous file: linux/drivers/scsi/README.g_NCR5380
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.59/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c
@@ -1,5 +1,3 @@
-#define AUTOSENSE
-
 /*
  * Generic Generic NCR5380 driver
  *	
@@ -9,6 +7,9 @@
  *	drew@colorado.edu
  *      +1 (303) 440-4894
  *
+ * NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin
+ *    K.Lentin@cs.monash.edu.au
+ *
  * ALPHA RELEASE 1. 
  *
  * For more information, please consult 
@@ -43,9 +44,9 @@
  *     used on the LILO command line to override the defaults.
  *
  * 2.  With the GENERIC_NCR5380_OVERRIDE compile time define.  This is 
- *     specified as an array of address, irq tuples.  Ie, for
- *     one board at the default 0xcc000 address, IRQ5, no dma, I could 
- *     say  -DGENERIC_NCR5380_OVERRIDE={{0xcc000, 5, DMA_NONE}}
+ *     specified as an array of address, irq, dma, board tuples.  Ie, for
+ *     one board at 0x350, IRQ5, no dma, I could say  
+ *     -DGENERIC_NCR5380_OVERRIDE={{0xcc000, 5, DMA_NONE, BOARD_NCR5380}}
  * 
  * -1 should be specified for no or DMA interrupt, -2 to autoprobe for an 
  * 	IRQ line if overridden on the command line.
@@ -56,6 +57,21 @@
  */
 
 #define AUTOPROBE_IRQ
+#define AUTOSENSE
+
+#include <linux/config.h>
+
+#ifdef CONFIG_SCSI_GENERIC_NCR53C400
+#define NCR53C400_PSEUDO_DMA 1
+#define PSEUDO_DMA
+#define NCR53C400
+#endif
+#if defined(CONFIG_SCSI_G_NCR5380_PORT) && defined(CONFIG_SCSI_G_NCR5380_MEM)
+#error You can not configure the Generic NCR 5380 SCSI Driver for memory mapped I/O and port mapped I/O at the same time (yet)
+#endif
+#if !defined(CONFIG_SCSI_G_NCR5380_PORT) && !defined(CONFIG_SCSI_G_NCR5380_MEM)
+#error You must configure the Generic NCR 5380 SCSI Driver for one of memory mapped I/O and port mapped I/O.
+#endif
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -67,6 +83,7 @@
 #include "g_NCR5380.h"
 #include "NCR5380.h"
 #include "constants.h"
+#include "sd.h"
 #include<linux/stat.h>
 
 struct proc_dir_entry proc_scsi_g_ncr5380 = {
@@ -75,9 +92,10 @@
 };
 
 static struct override {
-    int port;
+	NCR5380_implementation_fields;
     int irq;
     int dma;
+    int board;	/* Use NCR53c400, Ricoh, etc. extensions ? */
 } overrides 
 #ifdef GENERIC_NCR5380_OVERRIDE 
     [] = GENERIC_NCR5380_OVERRIDE
@@ -88,26 +106,65 @@
 #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
 
 /*
- * Function : generic_NCR5380_setup(char *str, int *ints)
+ * Function : static internal_setup(int board, char *str, int *ints)
  *
  * Purpose : LILO command line initialization of the overrides array,
  * 
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- *	equal to the number of ints.
+ * Inputs : board - either BOARD_NCR5380 for a normal NCR5380 board, 
+ * 	or BOARD_NCR53C400 for a NCR53C400 board. str - unused, ints - 
+ *	array of integer parameters with ints[0] equal to the number of ints.
  *
  */
 
-void generic_NCR5380_setup(char *str, int *ints) {
+static void internal_setup(int board, char *str, int *ints) {
     static int commandline_current = 0;
-    if (ints[0] != 2) 
-	printk("generic_NCR5380_setup : usage ncr5380=port,irq,dma\n");
-    else 
-	if (commandline_current < NO_OVERRIDES) {
-	    overrides[commandline_current].port = ints[1];
-	    overrides[commandline_current].irq = ints[2];
+    switch (board) {
+    case BOARD_NCR5380:
+	if (ints[0] != 2 && ints[0] != 3) 
+	    printk("generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n");
+	return;
+    case BOARD_NCR53C400:
+	if (ints[0] != 2)
+	    printk("generic_NCR53C400_setup : usage ncr53c400= " STRVAL(NCR5380_map_name) ",irq\n");
+	return;
+    }
+
+    if (commandline_current < NO_OVERRIDES) {
+	overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type)ints[1];
+	overrides[commandline_current].irq = ints[2];
+	if (ints[0] == 3) 
 	    overrides[commandline_current].dma = ints[3];
+	else 
+	    overrides[commandline_current].dma = DMA_NONE;
+	overrides[commandline_current].board = board;
 	    ++commandline_current;
-	}
+    }
+}
+
+/*
+ * Function : generic_NCR5380_setup (char *str, int *ints)
+ *
+ * Purpose : LILO command line initialization of the overrides array,
+ * 
+ * Inputs : str - unused, ints - array of integer paramters with ints[0] 
+ * 	equal to the number of ints.
+ */
+
+void generic_NCR5380_setup (char *str, int *ints) {
+    internal_setup (BOARD_NCR5380, str, ints);
+}
+
+/*
+ * Function : generic_NCR53C400_setup (char *str, int *ints)
+ *
+ * Purpose : LILO command line initialization of the overrides array,
+ * 
+ * Inputs : str - unused, ints - array of integer paramters with ints[0] 
+ * 	equal to the number of ints.
+ */
+
+void generic_NCR53C400_setup (char *str, int *ints) {
+    internal_setup (BOARD_NCR53C400, str, ints);
 }
 
 /* 
@@ -125,18 +182,28 @@
 int generic_NCR5380_detect(Scsi_Host_Template * tpnt) {
     static int current_override = 0;
     int count;
+    int flags = 0;
     struct Scsi_Host *instance;
 
     tpnt->proc_dir = &proc_scsi_g_ncr5380;
 
     for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
-	if (!(overrides[current_override].port))
+	if (!(overrides[current_override].NCR5380_map_name))
 	    continue;
 
+	switch (overrides[current_override].board) {
+	case BOARD_NCR5380:
+	    flags = FLAG_NO_PSEUDO_DMA;
+	    break;
+	case BOARD_NCR53C400:
+	    flags = FLAG_NCR53C400;
+	    break;
+	}
+
 	instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
-	instance->io_port = overrides[current_override].port;
+	instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name;
 
-	NCR5380_init(instance, 0);
+	NCR5380_init(instance, flags);
 
 	if (overrides[current_override].irq != IRQ_AUTO)
 	    instance->irq = overrides[current_override].irq;
@@ -155,7 +222,7 @@
 	    printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
 	}
 
-	printk("scsi%d : at port %d", instance->host_no, instance->io_port);
+	printk("scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int)instance->NCR5380_instance_name);
 	if (instance->irq == IRQ_NONE)
 	    printk (" interrupts disabled");
 	else 
@@ -172,9 +239,329 @@
 }
 
 const char * generic_NCR5380_info (void) {
-    static const char string[]="";
+    static const char string[]="Generic NCR5380/53C400 Info";
     return string;
 }
+
+int generic_NCR5380_release_resources(struct Scsi_Host * instance)
+{
+    NCR5380_local_declare();
+
+    NCR5380_setup(instance);
+
+    free_irq(instance->irq);
+
+	return 0;
+}
+
+#ifdef BIOSPARAM
+/*
+ * Function : int generic_NCR5380_biosparam(Disk * disk, kdev_t dev, int *ip)
+ *
+ * Purpose : Generates a BIOS / DOS compatable H-C-S mapping for 
+ *	the specified device / size.
+ * 
+ * Inputs : size = size of device in sectors (512 bytes), dev = block device
+ *	major / minor, ip[] = {heads, sectors, cylinders}  
+ *
+ * Returns : allways 0 (success), initializes ip
+ *	
+ */
+
+/* 
+ * XXX Most SCSI boards use this mapping, I could be incorrect.  Some one
+ * using hard disks on a trantor should verify that this mapping corresponds
+ * to that used by the BIOS / ASPI driver by running the linux fdisk program
+ * and matching the H_C_S coordinates to what DOS uses.
+ */
+
+int generic_NCR5380_biosparam(Disk * disk, kdev_t dev, int *ip)
+{
+  int size = disk->capacity;
+  ip[0] = 64;
+  ip[1] = 32;
+  ip[2] = size >> 11;
+  return 0;
+}
+#endif
+
+int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout)
+{
+	int len = 0;
+	struct Scsi_Host *scsi_ptr;
+
+	for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr=scsi_ptr->next)
+		if (scsi_ptr->host_no == hostno)
+			break;
+
+	len += sprintf(buffer+len, "SCSI host number %d : %s\n", scsi_ptr->host_no,  scsi_ptr->hostt->name);
+	len += sprintf(buffer+len, "Generic NCR5380 driver version %d\n", GENERIC_NCR5380_PUBLIC_RELEASE);
+	len += sprintf(buffer+len, "NCR5380 driver core version %d\n", NCR5380_PUBLIC_RELEASE);
+#ifdef NCR53C400
+	len += sprintf(buffer+len, "NCR53C400 driver extension version %d\n", NCR53C400_PUBLIC_RELEASE);
+	len += sprintf(buffer+len, "NCR53C400 card%s detected\n",  (((struct NCR5380_hostdata *)scsi_ptr->hostdata)->flags & FLAG_NCR53C400)?"":" not");
+# if NCR53C400_PSEUDO_DMA
+	len += sprintf(buffer+len, "NCR53C400 pseudo DMA being used\n");
+# endif
+#else
+	len += sprintf(buffer+len, "NO NCR53C400 driver extensions\n");
+#endif
+	len += sprintf(buffer+len, "Using %s mapping at %s 0x%x, ", STRVAL(NCR5380_map_config), STRVAL(NCR5380_map_name), scsi_ptr->NCR5380_instance_name);
+	if (scsi_ptr->irq == IRQ_NONE)
+		len += sprintf(buffer+len, "interrupts disabled\n");
+	else
+		len += sprintf(buffer+len, "on interrupt %d\n", scsi_ptr->irq);
+
+	*start = buffer + offset;
+	len -= offset;
+	if (len > length)
+		len = length;
+	return len;
+}
+
+#if NCR53C400_PSEUDO_DMA
+static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,    int len)
+{
+    int blocks = len / 128;
+    int start = 0;
+    int i;
+    int bl;
+    NCR5380_local_declare();
+
+    NCR5380_setup(instance);
+
+#if (NDEBUG & NDEBUG_C400_PREAD)
+    printk("53C400r: About to read %d blocks for %d bytes\n", blocks, len);
+#endif
+
+    NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR);
+    NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
+    while (1) {
+    
+#if (NDEBUG & NDEBUG_C400_PREAD)
+	printk("53C400r: %d blocks left\n", blocks);
+#endif
+
+	if ((bl=NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
+#if (NDEBUG & NDEBUG_C400_PREAD)
+	    if (blocks)
+		printk("53C400r: blocks still == %d\n", blocks);
+	    else
+		printk("53C400r: Exiting loop\n");
+#endif
+	    break;
+	}
+
+#if 1
+	if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
+	    printk("53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
+	    return -1;
+	}
+#endif
+
+#if (NDEBUG & NDEBUG_C400_PREAD)
+	printk("53C400r: Waiting for buffer, bl=%d\n", bl);
+#endif
+
+	while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+	    ;
+#if (NDEBUG & NDEBUG_C400_PREAD)
+	printk("53C400r: Transferring 128 bytes\n");
+#endif
+
+#ifdef CONFIG_SCSI_G_NCR5380_PORT
+	for (i=0; i<128; i++)
+	    dst[start+i] = NCR5380_read(C400_HOST_BUFFER);
+#else
+	/* implies CONFIG_SCSI_G_NCR5380_MEM */
+	memmove(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
+#endif
+	start+=128;
+	blocks--;
+    }
+
+#if (NDEBUG & NDEBUG_C400_PREAD)
+    printk("53C400r: EXTRA: Waiting for buffer\n");
+#endif
+    while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+	;
+
+#if (NDEBUG & NDEBUG_C400_PREAD)
+    printk("53C400r: Transferring EXTRA 128 bytes\n");
+#endif
+#ifdef CONFIG_SCSI_G_NCR5380_PORT
+	for (i=0; i<128; i++)
+	    dst[start+i] = NCR5380_read(C400_HOST_BUFFER);
+#else
+	/* implies CONFIG_SCSI_G_NCR5380_MEM */
+	memmove(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
+#endif
+    start+=128;
+    blocks--;
+
+#if (NDEBUG & NDEBUG_C400_PREAD)
+    printk("53C400r: Final values: blocks=%d   start=%d\n", blocks, start);
+#endif
+
+    if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
+	printk("53C400r: no 53C80 gated irq after transfer");
+#if (NDEBUG & NDEBUG_C400_PREAD)
+    else
+	printk("53C400r: Got 53C80 interupt and tried to clear it\n");
+#endif
+
+/* DON'T DO THIS - THEY NEVER ARRIVE!
+    printk("53C400r: Waiting for 53C80 registers\n");
+    while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG)
+	;
+*/
+
+    if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
+	printk("53C400r: no end dma signal\n");
+#if (NDEBUG & NDEBUG_C400_PREAD)
+    else
+	printk("53C400r: end dma as expected\n");
+#endif
+
+    NCR5380_write(MODE_REG, MR_BASE);
+    NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+    return 0;
+}
+		
+static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src,    int len)
+{
+    int blocks = len / 128;
+    int start = 0;
+    int i;
+    int bl;
+    NCR5380_local_declare();
+
+    NCR5380_setup(instance);
+
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+    printk("53C400w: About to write %d blocks for %d bytes\n", blocks, len);
+#endif
+
+    NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
+    NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
+    while (1) {
+	if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
+	    printk("53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
+	    return -1;
+	}
+
+	if ((bl=NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+	    if (blocks)
+		printk("53C400w: exiting loop, blocks still == %d\n", blocks);
+	    else
+		printk("53C400w: exiting loop\n");
+#endif
+	    break;
+	}
+
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+	printk("53C400w: %d blocks left\n", blocks);
+
+	printk("53C400w: waiting for buffer, bl=%d\n", bl);
+#endif
+	while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+	    ;
+
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+	printk("53C400w: transferring 128 bytes\n");
+#endif
+#ifdef CONFIG_SCSI_G_NCR5380_PORT
+	for (i=0; i<128; i++)
+	    NCR5380_write(C400_HOST_BUFFER, src[start+i]);
+#else
+	/* implies CONFIG_SCSI_G_NCR5380_MEM */
+	memmove(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
+#endif
+	start+=128;
+	blocks--;
+    }
+    if (blocks) {
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+	printk("53C400w: EXTRA waiting for buffer\n");
+#endif
+	while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+	    ;
+
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+	printk("53C400w: transferring EXTRA 128 bytes\n");
+#endif
+#ifdef CONFIG_SCSI_G_NCR5380_PORT
+	for (i=0; i<128; i++)
+	    NCR5380_write(C400_HOST_BUFFER, src[start+i]);
+#else
+	/* implies CONFIG_SCSI_G_NCR5380_MEM */
+	memmove(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
+#endif
+	start+=128;
+	blocks--;
+    }
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+    else
+	printk("53C400w: No EXTRA required\n");
+#endif
+    
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+    printk("53C400w: Final values: blocks=%d   start=%d\n", blocks, start);
+#endif
+
+#if 0
+    printk("53C400w: waiting for registers to be available\n");
+    THEY NEVER DO!
+    while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG)
+	;
+    printk("53C400w: Got em\n");
+#endif
+
+    /* Let's wait for this instead - could be ugly */
+    /* All documentation says to check for this. Maybe my hardware is too
+     * fast. Waiting for it seems to work fine! KLL
+     */
+    while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
+	;
+
+    /*
+     * I know. i is certainly != 0 here but the loop is new. See previous
+     * comment.
+     */
+    if (i) {
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+	prink("53C400w: got 53C80 gated irq (last block)\n");
+#endif
+	if (!((i=NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER))
+	    printk("53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n",i);
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+	else
+	    printk("53C400w: Got END OF DMA\n");
+#endif
+    }
+    else
+	printk("53C400w: no 53C80 gated irq after transfer (last block)\n");
+
+#if 0
+    if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) {
+	printk("53C400w: no end dma signal\n");
+    }
+#endif
+
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+    printk("53C400w: waiting for last byte...\n");
+#endif
+    while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
+    	;
+
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+    printk("53C400w:     got last byte.\n");
+    printk("53C400w: pwrite exiting with status 0, whoopee!\n");
+#endif
+    return 0;
+}
+#endif /* PSEUDO_DMA */
 
 #include "NCR5380.c"
 #ifdef MODULE

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this