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

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