summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/in2000.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/in2000.c')
-rw-r--r--drivers/scsi/in2000.c103
1 files changed, 36 insertions, 67 deletions
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index adc7ccf2e..04ecc1511 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -117,34 +117,17 @@
#include <linux/blk.h>
#include <linux/stat.h>
-#include <asm/spinlock.h>
#include "scsi.h"
#include "sd.h"
#include "hosts.h"
-
-#define IN2000_VERSION "1.32"
-#define IN2000_DATE "28/March/1998"
-
-/*
- * Note - the following defines have been moved to 'in2000.h':
- *
- * PROC_INTERFACE
- * PROC_STATISTICS
- * SYNC_DEBUG
- * DEBUGGING_ON
- * DEBUG_DEFAULTS
- * FAST_READ_IO
- * FAST_WRITE_IO
- *
- */
-
+#define IN2000_VERSION "1.33"
+#define IN2000_DATE "26/August/1998"
#include "in2000.h"
-
/*
* 'setup_strings' is a single string used to pass operating parameters and
* settings from the kernel/module command-line to the driver. 'setup_args[]'
@@ -404,6 +387,10 @@ DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld(",cmd->target,cmd->cmnd[0],cmd->pid))
cmd->SCp.Status = ILLEGAL_STATUS_BYTE;
+/* We need to disable interrupts before messing with the input
+ * queue and calling in2000_execute().
+ */
+
save_flags(flags);
cli();
@@ -443,20 +430,19 @@ DB(DB_QUEUE_COMMAND,printk(")Q-%ld ",cmd->pid))
* already connected, we give up immediately. Otherwise, look through
* the input_Q, using the first command we find that's intended
* for a currently non-busy target/lun.
+ * Note that this function is always called with interrupts already
+ * disabled (either from in2000_queuecommand() or in2000_intr()).
*/
static void in2000_execute (struct Scsi_Host *instance)
{
struct IN2000_hostdata *hostdata;
Scsi_Cmnd *cmd, *prev;
-unsigned long flags;
int i;
unsigned short *sp;
unsigned short f;
unsigned short flushbuf[16];
- save_flags(flags);
- cli();
hostdata = (struct IN2000_hostdata *)instance->hostdata;
DB(DB_EXECUTE,printk("EX("))
@@ -465,7 +451,6 @@ DB(DB_EXECUTE,printk("EX("))
DB(DB_EXECUTE,printk(")EX-0 "))
- restore_flags(flags);
return;
}
@@ -489,7 +474,6 @@ DB(DB_EXECUTE,printk(")EX-0 "))
DB(DB_EXECUTE,printk(")EX-1 "))
- restore_flags(flags);
return;
}
@@ -717,7 +701,6 @@ no:
DB(DB_EXECUTE,printk("%s%ld)EX-2 ",(cmd->SCp.phase)?"d:":"",cmd->pid))
- restore_flags(flags);
}
@@ -842,15 +825,10 @@ int i;
}
-/* It appears that the Linux interrupt dispatcher calls this
- * function in a non-reentrant fashion. What that means to us
- * is that we can use an SA_INTERRUPT type of interrupt (which
- * is faster), and do an sti() right away to let timer, serial,
- * etc. ints happen.
- *
- * WHOA! Wait a minute, pardner! Does this hold when more than
- * one card has been detected?? I doubt it. Maybe better
- * re-think the multiple card capability....
+/* We need to use spin_lock_irqsave() & spin_unlock_irqrestore() in this
+ * function in order to work in an SMP environment. (I'd be surprised
+ * if the driver is ever used by anyone on a real multi-CPU motherboard,
+ * but it _does_ need to be able to compile and run in an SMP kernel.)
*/
static void in2000_intr (int irqnum, void * dev_id, struct pt_regs *ptregs)
@@ -863,6 +841,7 @@ int i,j;
unsigned long length;
unsigned short *sp;
unsigned short f;
+unsigned long flags;
for (instance = instance_list; instance; instance = instance->next) {
if (instance->irq == irqnum)
@@ -874,6 +853,10 @@ unsigned short f;
}
hostdata = (struct IN2000_hostdata *)instance->hostdata;
+/* Get the spin_lock and disable further ints, for SMP */
+
+ CLISPIN_LOCK(flags);
+
#ifdef PROC_STATISTICS
hostdata->int_cnt++;
#endif
@@ -1008,6 +991,9 @@ DB(DB_FIFO,printk("{W:%02x} ",read1_io(IO_FIFO_COUNT)))
}
write1_io(0, IO_LED_OFF);
+
+/* release the SMP spin_lock and restore irq state */
+ CLISPIN_UNLOCK(flags);
return;
}
@@ -1023,6 +1009,9 @@ DB(DB_FIFO,printk("{W:%02x} ",read1_io(IO_FIFO_COUNT)))
if (!cmd && (sr != CSR_RESEL_AM && sr != CSR_TIMEOUT && sr != CSR_SELECT)) {
printk("\nNR:wd-intr-1\n");
write1_io(0, IO_LED_OFF);
+
+/* release the SMP spin_lock and restore irq state */
+ CLISPIN_UNLOCK(flags);
return;
}
@@ -1084,13 +1073,10 @@ DB(DB_TRANSFER,printk("(%p,%d)",cmd->SCp.ptr,cmd->SCp.this_residual))
/* Respond to the specific WD3393 interrupt - there are quite a few! */
switch (sr) {
- unsigned long flags;
case CSR_TIMEOUT:
DB(DB_INTR,printk("TIMEOUT"))
- save_flags(flags);
- cli();
if (hostdata->state == S_RUNNING_LEVEL2)
hostdata->connected = NULL;
else {
@@ -1108,7 +1094,6 @@ CHECK_NULL(cmd,"csr_timeout")
* are commands waiting to be executed.
*/
- restore_flags(flags);
in2000_execute(instance);
break;
@@ -1116,7 +1101,6 @@ CHECK_NULL(cmd,"csr_timeout")
/* Note: this interrupt should not occur in a LEVEL2 command */
case CSR_SELECT:
- cli();
DB(DB_INTR,printk("SELECT"))
hostdata->connected = cmd = (Scsi_Cmnd *)hostdata->selecting;
CHECK_NULL(cmd,"csr_select")
@@ -1206,7 +1190,6 @@ DB(DB_INTR,printk("%02x",cmd->SCp.Status))
case CSR_SRV_REQ |PHS_MESS_IN:
DB(DB_INTR,printk("MSG_IN="))
- cli();
msg = read_1_byte(hostdata);
sr = read_3393(hostdata,WD_SCSI_STATUS); /* clear interrupt */
@@ -1355,8 +1338,6 @@ printk("sync_xfer=%02x",hostdata->sync_xfer[cmd->target]);
/* Note: this interrupt will occur only after a LEVEL2 command */
case CSR_SEL_XFER_DONE:
- save_flags(flags);
- cli();
/* Make sure that reselection is enabled at this point - it may
* have been turned off for the command that just completed.
@@ -1383,7 +1364,6 @@ DB(DB_INTR,printk(":%d.%d",cmd->SCp.Status,lun))
* there are commands waiting to be executed.
*/
- restore_flags(flags);
in2000_execute(instance);
}
else {
@@ -1442,8 +1422,6 @@ DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0]))
* so we treat it as a normal command-complete-disconnect.
*/
- save_flags(flags);
- cli();
/* Make sure that reselection is enabled at this point - it may
* have been turned off for the command that just completed.
@@ -1453,6 +1431,9 @@ DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0]))
if (cmd == NULL) {
printk(" - Already disconnected! ");
hostdata->state = S_UNCONNECTED;
+
+/* release the SMP spin_lock and restore irq state */
+ CLISPIN_UNLOCK(flags);
return;
}
DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid))
@@ -1469,14 +1450,11 @@ DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid))
* there are commands waiting to be executed.
*/
- restore_flags(flags);
in2000_execute(instance);
break;
case CSR_DISC:
- save_flags(flags);
- cli();
/* Make sure that reselection is enabled at this point - it may
* have been turned off for the command that just completed.
@@ -1521,7 +1499,6 @@ DB(DB_INTR,printk(":%d",cmd->SCp.Status))
* there are commands waiting to be executed.
*/
- restore_flags(flags);
in2000_execute(instance);
break;
@@ -1529,8 +1506,6 @@ DB(DB_INTR,printk(":%d",cmd->SCp.Status))
case CSR_RESEL_AM:
DB(DB_INTR,printk("RESEL"))
- cli();
-
/* First we have to make sure this reselection didn't */
/* happen during Arbitration/Selection of some other device. */
/* If yes, put losing command back on top of input_Q. */
@@ -1633,16 +1608,12 @@ DB(DB_INTR,printk("-%ld",cmd->pid))
DB(DB_INTR,printk("} "))
+/* release the SMP spin_lock and restore irq state */
+ CLISPIN_UNLOCK(flags);
+
}
-static void do_in2000_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
- unsigned long flags;
- spin_lock_irqsave(&io_request_lock, flags);
- in2000_intr(irq, dev_id, regs);
- spin_unlock_irqrestore(&io_request_lock, flags);
-}
#define RESET_CARD 0
#define RESET_CARD_AND_BUS 1
@@ -1827,7 +1798,6 @@ unsigned long timeout;
cmd->result = DID_ABORT << 16;
cmd->scsi_done(cmd);
-/* sti();*/
in2000_execute (instance);
restore_flags(flags);
@@ -1858,7 +1828,6 @@ unsigned long timeout;
* broke.
*/
-/* sti();*/
in2000_execute (instance);
restore_flags(flags);
@@ -1876,7 +1845,7 @@ static char setup_buffer[SETUP_BUFFER_SIZE];
static char setup_used[MAX_SETUP_ARGS];
static int done_setup = 0;
-void in2000_setup (char *str, int *ints)
+in2000__INITFUNC( void in2000_setup (char *str, int *ints) )
{
int i;
char *p1,*p2;
@@ -1908,7 +1877,7 @@ char *p1,*p2;
/* check_setup_args() returns index if key found, 0 if not
*/
-static int check_setup_args(char *key, int *flags, int *val, char *buf)
+in2000__INITFUNC( static int check_setup_args(char *key, int *flags, int *val, char *buf) )
{
int x;
char *cp;
@@ -1940,21 +1909,21 @@ char *cp;
* special macros declared in 'asm/io.h'. We use readb() and readl()
* when reading from the card's BIOS area in in2000_detect().
*/
-static const unsigned int *bios_tab[] = {
+static const unsigned int *bios_tab[] in2000__INITDATA = {
(unsigned int *)0xc8000,
(unsigned int *)0xd0000,
(unsigned int *)0xd8000,
0
};
-static const unsigned short base_tab[] = {
+static const unsigned short base_tab[] in2000__INITDATA = {
0x220,
0x200,
0x110,
0x100,
};
-static const int int_tab[] = {
+static const int int_tab[] in2000__INITDATA = {
15,
14,
11,
@@ -1962,7 +1931,7 @@ static const int int_tab[] = {
};
-int in2000_detect(Scsi_Host_Template * tpnt)
+in2000__INITFUNC( int in2000_detect(Scsi_Host_Template * tpnt) )
{
struct Scsi_Host *instance;
struct IN2000_hostdata *hostdata;
@@ -2068,7 +2037,7 @@ char buf[32];
write1_io(0,IO_FIFO_READ); /* start fifo out in read mode */
write1_io(0,IO_INTR_MASK); /* allow all ints */
x = int_tab[(switches & (SW_INT0 | SW_INT1)) >> SW_INT_SHIFT];
- if (request_irq(x, do_in2000_intr, SA_INTERRUPT, "in2000", NULL)) {
+ if (request_irq(x, in2000_intr, SA_INTERRUPT, "in2000", NULL)) {
printk("in2000_detect: Unable to allocate IRQ.\n");
detect_count--;
continue;