[...]

Willy pointed out a bogus hunk in the original patch that should not
have been there.  Retransmit with that removed. Also mark scsi_cmnd_serial
inline.

This patch fixes one of Christroph's fixme comments in the SCSI midlayer.

The selection of the serial number and pid for commands was done
by a global variable and not SMP safe. The race was not very
serious because it was only used for error handling, but it's
still better to fix it.

I audited all the drivers and none seemed to use them 
for anything interesting, so I just made it a per host counter
protected by host lock.

(in fact they could be probably removed because they only see
to be used as a flag in exception handling and for debugging.
The patch would be unfortunately quite big because a lot
of driver printks use them) 

This should be slight faster on SMP too because the cache line of
the counter won't bounce around the machine. 


diff -u linux-2.6.11rc3/drivers/scsi/scsi.c-SCSISER 
linux-2.6.11rc3/drivers/scsi/scsi.c
--- linux-2.6.11rc3/drivers/scsi/scsi.c-SCSISER 2005-02-04 09:13:14.000000000 
+0100
+++ linux-2.6.11rc3/drivers/scsi/scsi.c 2005-02-05 12:02:50.000000000 +0100
@@ -88,12 +88,6 @@
                                COMMAND_SIZE((cmd)->cmnd[0]) : (cmd)->cmd_len)
 
 /*
- * Data declarations.
- */
-unsigned long scsi_pid;
-static unsigned long serial_number;
-
-/*
  * Note - the initial logging level can be set here to log events at boot time.
  * After the system is up, you may enable logging via the /proc interface.
  */
@@ -510,6 +504,21 @@
 }
 #endif
 
+/* 
+ * Assign a serial number and pid to the request for error recovery
+ * and debugging purposes.  Protected by the Host_Lock of host.
+ */
+static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct 
scsi_cmnd *cmd)
+{
+       cmd->serial_number = host->cmd_serial_number++;
+       if (cmd->serial_number == 0) 
+               cmd->serial_number = host->cmd_serial_number++;
+       
+       cmd->pid = host->cmd_pid++;
+       if (cmd->pid == 0)
+               cmd->pid = host->cmd_pid++;
+}
+
 /*
  * Function:    scsi_dispatch_command
  *
@@ -556,13 +565,6 @@
                goto out;
        }
 
-       /* Assign a unique nonzero serial_number. */
-       /* XXX(hch): this is racy */
-       if (++serial_number == 0)
-               serial_number = 1;
-       cmd->serial_number = serial_number;
-       cmd->pid = scsi_pid++;
-
        /* 
         * If SCSI-2 or lower, store the LUN value in cmnd.
         */
@@ -593,6 +595,10 @@
                host->resetting = 0;
        }
 
+       /* 
+        * AK: unlikely race here: for some reason the timer could
+        * expire before the serial number is set up below.
+        */
        scsi_add_timer(cmd, cmd->timeout_per_command, scsi_times_out);
 
        scsi_log_send(cmd);
@@ -619,6 +625,8 @@
        }
 
        spin_lock_irqsave(host->host_lock, flags);
+       scsi_cmd_get_serial(host, cmd); 
+
        if (unlikely(test_bit(SHOST_CANCEL, &host->shost_state))) {
                cmd->result = (DID_NO_CONNECT << 16);
                scsi_done(cmd);
diff -u linux-2.6.11rc3/include/scsi/scsi_cmnd.h-SCSISER 
linux-2.6.11rc3/include/scsi/scsi_cmnd.h
--- linux-2.6.11rc3/include/scsi/scsi_cmnd.h-SCSISER    2004-05-10 
09:44:25.000000000 +0200
+++ linux-2.6.11rc3/include/scsi/scsi_cmnd.h    2005-02-05 09:28:31.000000000 
+0100
@@ -54,6 +54,7 @@
         * completed and the SCSI Command structure has already being reused
         * for another command, so that we can avoid incorrectly aborting or
         * resetting the new command.
+        * The serial number is only unique per host.
         */
        unsigned long serial_number;
        unsigned long serial_number_at_timeout;
@@ -139,7 +140,7 @@
        int result;             /* Status code from lower level driver */
 
        unsigned char tag;      /* SCSI-II queued command tag */
-       unsigned long pid;      /* Process ID, starts at 0 */
+       unsigned long pid;      /* Process ID, starts at 0. Unique per host. */
 };
 
 /*
diff -u linux-2.6.11rc3/include/scsi/scsi_host.h-SCSISER 
linux-2.6.11rc3/include/scsi/scsi_host.h
--- linux-2.6.11rc3/include/scsi/scsi_host.h-SCSISER    2005-02-04 
09:13:50.000000000 +0100
+++ linux-2.6.11rc3/include/scsi/scsi_host.h    2005-02-05 12:02:17.000000000 
+0100
@@ -483,7 +483,12 @@
        short unsigned int sg_tablesize;
        short unsigned int max_sectors;
        unsigned long dma_boundary;
-
+       /* 
+        * Used to assign serial numbers to the cmds.
+        * Protected by the host lock.
+        */
+       unsigned long cmd_serial_number, cmd_pid; 
+       
        unsigned unchecked_isa_dma:1;
        unsigned use_clustering:1;
        unsigned use_blk_tcq:1;
-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to