patch-2.1.36 linux/drivers/scsi/wd33c93.c
Next file: linux/drivers/scsi/wd33c93.h
Previous file: linux/drivers/scsi/t128.c
Back to the patch index
Back to the overall index
- Lines: 479
- Date:
Thu Apr 17 13:20:47 1997
- Orig file:
v2.1.35/linux/drivers/scsi/wd33c93.c
- Orig date:
Fri Dec 20 01:20:02 1996
diff -u --recursive --new-file v2.1.35/linux/drivers/scsi/wd33c93.c linux/drivers/scsi/wd33c93.c
@@ -28,9 +28,9 @@
*
* - Target Disconnection/Reconnection is now supported. Any
* system with more than one device active on the SCSI bus
- * will benefit from this. The driver defaults to what I'm
- * 'adaptive disconnect' - meaning that each command is
- * evaluated individually as to whether or not it should
+ * will benefit from this. The driver defaults to what I
+ * call 'adaptive disconnect' - meaning that each command
+ * is evaluated individually as to whether or not it should
* be run with the option to disconnect/reselect (if the
* device chooses), or as a "SCSI-bus-hog".
*
@@ -87,23 +87,19 @@
#include "hosts.h"
-#define PROC_INTERFACE /* add code for /proc/scsi/wd33c93/xxx interface */
-#ifdef PROC_INTERFACE
-#define PROC_STATISTICS /* add code for keeping various real time stats */
-#endif
-
-#define SYNC_DEBUG /* extra info on sync negotiation printed */
-#undef DEBUGGING_ON /* enable command-line debugging bitmask */
-#define DEBUG_DEFAULTS 0 /* default debugging bitmask */
-
-#define WD33C93_VERSION "1.23"
-#define WD33C93_DATE "04/Nov/1996"
+#define WD33C93_VERSION "1.24"
+#define WD33C93_DATE "29/Jan/1997"
-#ifdef DEBUGGING_ON
-#define DB(f,a) if (hostdata->args & (f)) a;
-#else
-#define DB(f,a)
-#endif
+/*
+ * Note - the following defines have been moved to 'wd33c93.h':
+ *
+ * PROC_INTERFACE
+ * PROC_STATISTICS
+ * SYNC_DEBUG
+ * DEBUGGING_ON
+ * DEBUG_DEFAULTS
+ *
+ */
#include "wd33c93.h"
@@ -118,10 +114,11 @@
* keywords (lower case required) and arguments:
*
* - nosync:bitmask -bitmask is a byte where the 1st 7 bits correspond with
- * the 7 possible SCSI devices. Set a bit to prevent sync
- * negotiation on that device. To maintain backwards
- * compatibility, a command-line such as "wd33c93=255" will
- * be automatically translated to "wd33c93=nosync:0xff".
+ * the 7 possible SCSI devices. Set a bit to negotiate for
+ * asynchronous transfers on that device. To maintain
+ * backwards compatibility, a command-line such as
+ * "wd33c93=255" will be automatically translated to
+ * "wd33c93=nosync:0xff".
* - nodma:x -x = 1 to disable DMA, x = 0 to enable it. Argument is
* optional - if not present, same as "nodma:1".
* - period:ns -ns is the minimum # of nanoseconds in a SCSI data transfer
@@ -166,7 +163,7 @@
-inline uchar read_wd33c93(wd33c93_regs *regp,uchar reg_num)
+static inline uchar read_wd33c93(wd33c93_regs *regp,uchar reg_num)
{
regp->SASR = reg_num;
return(regp->SCMD);
@@ -176,21 +173,21 @@
#define READ_AUX_STAT() (regp->SASR)
-inline void write_wd33c93(wd33c93_regs *regp,uchar reg_num, uchar value)
+static inline void write_wd33c93(wd33c93_regs *regp,uchar reg_num, uchar value)
{
regp->SASR = reg_num;
regp->SCMD = value;
}
-inline void write_wd33c93_cmd(wd33c93_regs *regp, uchar cmd)
+static inline void write_wd33c93_cmd(wd33c93_regs *regp, uchar cmd)
{
regp->SASR = WD_COMMAND;
regp->SCMD = cmd;
}
-inline uchar read_1_byte(wd33c93_regs *regp)
+static inline uchar read_1_byte(wd33c93_regs *regp)
{
uchar asr;
uchar x = 0;
@@ -206,7 +203,7 @@
}
-void write_wd33c93_count(wd33c93_regs *regp,unsigned long value)
+static void write_wd33c93_count(wd33c93_regs *regp,unsigned long value)
{
regp->SASR = WD_TRANSFER_COUNT_MSB;
regp->SCMD = value >> 16;
@@ -215,7 +212,7 @@
}
-unsigned long read_wd33c93_count(wd33c93_regs *regp)
+static unsigned long read_wd33c93_count(wd33c93_regs *regp)
{
unsigned long value;
@@ -265,7 +262,7 @@
{1000,0x00},
{0, 0} };
-int round_period(unsigned int period)
+static int round_period(unsigned int period)
{
int x;
@@ -278,7 +275,7 @@
return 7;
}
-uchar calc_sync_xfer(unsigned int period, unsigned int offset)
+static uchar calc_sync_xfer(unsigned int period, unsigned int offset)
{
uchar result;
@@ -290,14 +287,13 @@
-void wd33c93_execute(struct Scsi_Host *instance);
+static void wd33c93_execute(struct Scsi_Host *instance);
int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{
-struct WD33C93_hostdata *hostdata;
-Scsi_Cmnd *tmp;
-
- disable_irq(cmd->host->irq);
+ struct WD33C93_hostdata *hostdata;
+ Scsi_Cmnd *tmp;
+ unsigned long flags;
hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata;
@@ -351,6 +347,9 @@
* sense data is not lost before REQUEST_SENSE executes.
*/
+ save_flags(flags);
+ cli();
+
if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {
cmd->host_scribble = (uchar *)hostdata->input_Q;
hostdata->input_Q = cmd;
@@ -370,7 +369,7 @@
DB(DB_QUEUE_COMMAND,printk(")Q-%ld ",cmd->pid))
- enable_irq(cmd->host->irq);
+ restore_flags(flags);
return 0;
}
@@ -381,15 +380,18 @@
* 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.
+ *
+ * wd33c93_execute() is always called with interrupts disabled or from
+ * the wd33c93_intr itself, which means that a wd33c93 interrupt
+ * cannot occur while we are in here.
*/
-void wd33c93_execute (struct Scsi_Host *instance)
+static void wd33c93_execute (struct Scsi_Host *instance)
{
struct WD33C93_hostdata *hostdata;
wd33c93_regs *regp;
Scsi_Cmnd *cmd, *prev;
int i;
- disable_irq(instance->irq);
hostdata = (struct WD33C93_hostdata *)instance->hostdata;
regp = hostdata->regp;
@@ -399,7 +401,6 @@
DB(DB_EXECUTE,printk(")EX-0 "))
- enable_irq(instance->irq);
return;
}
@@ -423,7 +424,6 @@
DB(DB_EXECUTE,printk(")EX-1 "))
- enable_irq(instance->irq);
return;
}
@@ -500,6 +500,7 @@
#endif
no:
+
write_wd33c93(regp, WD_SOURCE_ID, ((cmd->SCp.phase)?SRCID_ER:0));
write_wd33c93(regp, WD_TARGET_LUN, cmd->lun);
@@ -525,17 +526,14 @@
* sync_xfer[] entry is initialized to the default/safe value. SS_UNSET
* means that the parameters are undetermined as yet, and that we
* need to send an SDTR message to this device after selection is
- * complete. We set SS_FIRST to tell the interrupt routine to do so,
- * unless we've been asked not to try synchronous transfers on this
- * target (and _all_ luns within it): In this case we set SS_SET to
- * make the defaults final.
- */
- if (hostdata->sync_stat[cmd->target] == SS_UNSET) {
- if (hostdata->no_sync & (1 << cmd->target))
- hostdata->sync_stat[cmd->target] = SS_SET;
- else
+ * complete: We set SS_FIRST to tell the interrupt routine to do so.
+ * If we've been asked not to try synchronous transfers on this
+ * target (and _all_ luns within it), we'll still send the SDTR message
+ * later, but at that time we'll negotiate for async by specifying a
+ * sync fifo depth of 0.
+ */
+ if (hostdata->sync_stat[cmd->target] == SS_UNSET)
hostdata->sync_stat[cmd->target] = SS_FIRST;
- }
hostdata->state = S_SELECTING;
write_wd33c93_count(regp,0); /* guarantee a DATA_PHASE interrupt */
write_wd33c93_cmd(regp, WD_CMD_SEL_ATN);
@@ -600,13 +598,11 @@
*/
DB(DB_EXECUTE,printk("%s%ld)EX-2 ",(cmd->SCp.phase)?"d:":"",cmd->pid))
-
- enable_irq(instance->irq);
}
-void transfer_pio(wd33c93_regs *regp, uchar *buf, int cnt,
+static void transfer_pio(wd33c93_regs *regp, uchar *buf, int cnt,
int data_in_dir, struct WD33C93_hostdata *hostdata)
{
uchar asr;
@@ -642,7 +638,7 @@
-void transfer_bytes(wd33c93_regs *regp, Scsi_Cmnd *cmd, int data_in_dir)
+static void transfer_bytes(wd33c93_regs *regp, Scsi_Cmnd *cmd, int data_in_dir)
{
struct WD33C93_hostdata *hostdata;
unsigned long length;
@@ -725,7 +721,7 @@
Scsi_Cmnd *patch, *cmd;
wd33c93_regs *regp;
uchar asr, sr, phs, id, lun, *ucp, msg;
-unsigned long length;
+unsigned long length, flags;
hostdata = (struct WD33C93_hostdata *)instance->hostdata;
regp = hostdata->regp;
@@ -734,6 +730,8 @@
if (!(asr & ASR_INT) || (asr & ASR_BSY))
return;
+ save_flags(flags);
+
#ifdef PROC_STATISTICS
hostdata->int_cnt++;
#endif
@@ -776,7 +774,6 @@
case CSR_TIMEOUT:
DB(DB_INTR,printk("TIMEOUT"))
- disable_irq(instance->irq);
if (hostdata->state == S_RUNNING_LEVEL2)
hostdata->connected = NULL;
else {
@@ -789,11 +786,22 @@
hostdata->state = S_UNCONNECTED;
cmd->scsi_done(cmd);
+ /* From esp.c:
+ * There is a window of time within the scsi_done() path
+ * of execution where interrupts are turned back on full
+ * blast and left that way. During that time we could
+ * reconnect to a disconnected command, then we'd bomb
+ * out below. We could also end up executing two commands
+ * at _once_. ...just so you know why the restore_flags()
+ * is here...
+ */
+
+ restore_flags(flags);
+
/* We are not connected to a target - check to see if there
* are commands waiting to be executed.
*/
- enable_irq(instance->irq);
wd33c93_execute(instance);
break;
@@ -801,7 +809,6 @@
/* Note: this interrupt should not occur in a LEVEL2 command */
case CSR_SELECT:
- disable_irq(instance->irq);
DB(DB_INTR,printk("SELECT"))
hostdata->connected = cmd = (Scsi_Cmnd *)hostdata->selecting;
@@ -820,13 +827,23 @@
hostdata->sync_stat[cmd->target] = SS_WAITING;
- /* tack on a 2nd message to ask about synchronous transfers */
+/* Tack on a 2nd message to ask about synchronous transfers. If we've
+ * been asked to do only asynchronous transfers on this device, we
+ * request a fifo depth of 0, which is equivalent to async - should
+ * solve the problems some people have had with GVP's Guru ROM.
+ */
hostdata->outgoing_msg[1] = EXTENDED_MESSAGE;
hostdata->outgoing_msg[2] = 3;
hostdata->outgoing_msg[3] = EXTENDED_SDTR;
+ if (hostdata->no_sync & (1 << cmd->target)) {
+ hostdata->outgoing_msg[4] = hostdata->default_sx_per/4;
+ hostdata->outgoing_msg[5] = 0;
+ }
+ else {
hostdata->outgoing_msg[4] = OPTIMUM_SX_PER/4;
hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;
+ }
hostdata->outgoing_len = 6;
}
else
@@ -891,7 +908,6 @@
case CSR_SRV_REQ |PHS_MESS_IN:
DB(DB_INTR,printk("MSG_IN="))
- disable_irq(instance->irq);
msg = read_1_byte(regp);
sr = read_wd33c93(regp, WD_SCSI_STATUS); /* clear interrupt */
@@ -1034,13 +1050,13 @@
write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
hostdata->state = S_CONNECTED;
}
+ restore_flags(flags);
break;
/* Note: this interrupt will occur only after a LEVEL2 command */
case CSR_SEL_XFER_DONE:
- disable_irq(instance->irq);
/* Make sure that reselection is enabled at this point - it may
* have been turned off for the command that just completed.
@@ -1065,7 +1081,7 @@
/* We are no longer connected to a target - check to see if
* there are commands waiting to be executed.
*/
- enable_irq(instance->irq);
+ restore_flags(flags);
wd33c93_execute(instance);
}
else {
@@ -1124,8 +1140,6 @@
* so we treat it as a normal command-complete-disconnect.
*/
- disable_irq(instance->irq);
-
/* Make sure that reselection is enabled at this point - it may
* have been turned off for the command that just completed.
*/
@@ -1149,13 +1163,13 @@
/* We are no longer connected to a target - check to see if
* there are commands waiting to be executed.
*/
- enable_irq(instance->irq);
+ /* look above for comments on scsi_done() */
+ restore_flags(flags);
wd33c93_execute(instance);
break;
case CSR_DISC:
- disable_irq(instance->irq);
/* Make sure that reselection is enabled at this point - it may
* have been turned off for the command that just completed.
@@ -1177,6 +1191,7 @@
else if (cmd->SCp.Status != GOOD)
cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
cmd->scsi_done(cmd);
+ restore_flags(flags);
break;
case S_PRE_TMP_DISC:
case S_RUNNING_LEVEL2:
@@ -1198,7 +1213,6 @@
/* We are no longer connected to a target - check to see if
* there are commands waiting to be executed.
*/
- enable_irq(instance->irq);
wd33c93_execute(instance);
break;
@@ -1206,8 +1220,6 @@
case CSR_RESEL_AM:
DB(DB_INTR,printk("RESEL"))
- disable_irq(instance->irq);
-
/* 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. */
@@ -1306,15 +1318,13 @@
printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--",asr,sr,phs);
}
- enable_irq(instance->irq);
-
DB(DB_INTR,printk("} "))
}
-void reset_wd33c93(struct Scsi_Host *instance)
+static void reset_wd33c93(struct Scsi_Host *instance)
{
struct WD33C93_hostdata *hostdata;
wd33c93_regs *regp;
@@ -1595,7 +1605,7 @@
/* check_setup_strings() returns index if key found, 0 if not
*/
-int check_setup_strings(char *key, int *flags, int *val, char *buf)
+static int check_setup_strings(char *key, int *flags, int *val, char *buf)
{
int x;
char *cp;
@@ -1724,16 +1734,17 @@
reset_wd33c93(instance);
sti();
- printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d\n",instance->host_no,
+ printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d",instance->host_no,
(hostdata->chip==C_WD33C93)?"WD33c93":
(hostdata->chip==C_WD33C93A)?"WD33c93A":
(hostdata->chip==C_WD33C93B)?"WD33c93B":"unknown",
hostdata->microcode,hostdata->no_sync,hostdata->no_dma);
#ifdef DEBUGGING_ON
- printk(" debug_flags=0x%02x setup_strings=",hostdata->args);
+ printk(" debug_flags=0x%02x\n",hostdata->args);
#else
- printk(" debugging=OFF setup_strings=");
+ printk(" debugging=OFF\n");
#endif
+ printk(" setup_strings=");
for (i=0; i<MAX_SETUP_STRINGS; i++)
printk("%s,",setup_strings[i]);
printk("\n");
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov