Index: linux-2.6.9-5.0.3.EL/drivers/scsi/Kconfig\r
===================================================================\r
-Index: linux-2.6.9/drivers/scsi/Kconfig
+Index: linux+rhel4+chaos/drivers/scsi/Kconfig
===================================================================
---- linux-2.6.9.orig/drivers/scsi/Kconfig 2007-07-23 14:19:13.000000000 +0400
-+++ linux-2.6.9/drivers/scsi/Kconfig 2007-07-26 14:16:36.000000000 +0400
+--- linux+rhel4+chaos.orig/drivers/scsi/Kconfig
++++ linux+rhel4+chaos/drivers/scsi/Kconfig
@@ -61,6 +61,14 @@ config SCSI_DUMP
help
SCSI dump support
config CHR_DEV_ST
tristate "SCSI tape support"
depends on SCSI
-Index: linux-2.6.9/drivers/scsi/scsi_proc.c
+Index: linux+rhel4+chaos/drivers/scsi/sd.c
===================================================================
---- linux-2.6.9.orig/drivers/scsi/scsi_proc.c 2007-03-13 02:47:28.000000000 +0300
-+++ linux-2.6.9/drivers/scsi/scsi_proc.c 2007-07-26 14:16:36.000000000 +0400
-@@ -38,7 +38,8 @@
- /* 4K page size, but our output routines, use some slack for overruns */
- #define PROC_BLOCK_SIZE (3*1024)
-
--static struct proc_dir_entry *proc_scsi;
-+struct proc_dir_entry *proc_scsi;
-+EXPORT_SYMBOL(proc_scsi);
-
- /* Protect sht->present and sht->proc_dir */
- static DECLARE_MUTEX(global_host_template_sem);
-Index: linux-2.6.9/drivers/scsi/sd.c
-===================================================================
---- linux-2.6.9.orig/drivers/scsi/sd.c 2007-03-13 02:47:27.000000000 +0300
-+++ linux-2.6.9/drivers/scsi/sd.c 2007-07-28 14:55:56.000000000 +0400
-@@ -63,6 +63,67 @@
+--- linux+rhel4+chaos.orig/drivers/scsi/sd.c
++++ linux+rhel4+chaos/drivers/scsi/sd.c
+@@ -63,6 +63,38 @@
#include "scsi_logging.h"
+ iostat_counter_t iostat_read_histogram[IOSTAT_NCOUNTERS];
+ iostat_counter_t iostat_write_histogram[IOSTAT_NCOUNTERS];
+ struct timeval iostat_timeval;
-+
-+ /* queue depth: how well the pipe is filled up */
-+ unsigned long long iostat_queue_ticks[IOSTAT_NCOUNTERS];
-+ unsigned long long iostat_queue_ticks_sum;
-+ unsigned long iostat_queue_depth;
-+ unsigned long iostat_queue_stamp;
-+
-+ /* seeks: how linear the traffic is */
-+ unsigned long long iostat_next_sector;
-+ unsigned long long iostat_seek_sectors;
-+ unsigned long long iostat_seeks;
-+ unsigned long long iostat_sectors;
-+ unsigned long long iostat_reqs;
-+ unsigned long iostat_read_reqs;
-+ unsigned long iostat_write_reqs;
-+
-+ /* process time: how long it takes to process requests */
-+ unsigned long iostat_rtime[IOSTAT_NCOUNTERS];
-+ unsigned long iostat_wtime[IOSTAT_NCOUNTERS];
-+
-+ /* queue time: how long process spent in elevator's queue */
-+ unsigned long iostat_rtime_in_queue[IOSTAT_NCOUNTERS];
-+ unsigned long iostat_wtime_in_queue[IOSTAT_NCOUNTERS];
-+
-+ char iostat_name[32];
-+
-+ /* must be the last field, as it's used to know size to be memset'ed */
-+ spinlock_t iostat_lock;
-+} ____cacheline_aligned_in_smp iostat_stats_t;
++} iostat_stats_t;
+
+iostat_stats_t **sd_iostats;
++spinlock_t sd_iostats_lock;
+struct proc_dir_entry *sd_iostats_procdir;
+char sd_iostats_procdir_name[] = "sd_iostats";
+
+extern void sd_iostats_init(void);
+extern void sd_iostats_init_disk(struct gendisk *);
+extern void sd_iostats_fini(void);
-+void sd_iostats_start_req(struct scsi_cmnd *SCpnt);
-+void sd_iostats_finish_req(struct scsi_cmnd *SCpnt);
++extern void sd_iostats_bump(int disk, unsigned int nsect, int iswrite);
+#else
+static inline void sd_iostats_init(void) {}
+static inline void sd_iostats_init_disk(struct gendisk *disk) {}
+static inline void sd_iostats_fini(void) {}
-+static inline void sd_iostats_start_req(struct scsi_cmnd *SCpnt) {}
-+static inline void sd_iostats_finish_req(struct scsi_cmnd *SCpnt) {}
++static inline void sd_iostats_bump(int disk, unsigned int nsect, int iswrite) {}
+#endif
+
/*
* More than enough for everybody ;) The huge number of majors
* is a leftover from 16bit dev_t days, we don't really need that
-@@ -76,6 +137,7 @@
+@@ -76,6 +108,7 @@
*/
#define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26)
/*
* Time out in seconds for disks and Magneto-opticals (which are slower).
*/
-@@ -278,6 +340,8 @@ static int sd_init_command(struct scsi_c
+@@ -278,6 +311,9 @@ static int sd_init_command(struct scsi_c
SCSI_LOG_HLQUEUE(2, printk("%s : block=%llu\n",
disk->disk_name, (unsigned long long)block));
-+ sd_iostats_start_req(SCpnt);
++ sd_iostats_bump(scsi_disk(disk)->index, this_count,
++ rq_data_dir(SCpnt->request) == WRITE);
+
/*
* If we have a 1K hardware sectorsize, prevent access to single
* 512 byte sectors. In theory we could handle this - in fact
-@@ -474,6 +538,7 @@ static int sd_open(struct inode *inode,
+@@ -474,6 +510,7 @@ static int sd_open(struct inode *inode,
scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT);
}
return 0;
error_out:
-@@ -849,6 +914,9 @@ static void sd_rw_intr(struct scsi_cmnd
- break;
- }
+@@ -500,8 +537,20 @@ static int sd_release(struct inode *inod
+
+ SCSI_LOG_HLQUEUE(3, printk("sd_release: disk=%s\n", disk->disk_name));
+
+- if (!--sdkp->openers && sdev->removable) {
+- if (scsi_block_when_processing_errors(sdev))
++ if (!--sdkp->openers) {
++ /*
++ * Remove sd_iostats information about this disk
++ */
++ if (sd_iostats_procdir != NULL) {
++ remove_proc_entry(disk->disk_name, sd_iostats_procdir);
++ }
++ if (sd_iostats != NULL) {
++ if (sd_iostats[sdkp->index] != NULL) {
++ kfree (sd_iostats[sdkp->index]);
++ sd_iostats[sdkp->index] = NULL;
++ }
++ }
++ if (sdev->removable && scsi_block_when_processing_errors(sdev))
+ scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
}
-+
-+ sd_iostats_finish_req(SCpnt);
-+
- /*
- * This calls the generic completion function, now that we know
- * how many actual sectors finished, and how many sectors we need
-@@ -1575,6 +1643,481 @@ static void sd_shutdown(struct device *d
+
+@@ -1575,6 +1624,342 @@ static void sd_shutdown(struct device *d
sd_sync_cache(sdp);
}
+static int
+sd_iostats_seq_show(struct seq_file *seq, void *v)
+{
-+ struct timeval now;
-+ struct gendisk *disk = seq->private;
-+ iostat_stats_t *stats;
-+ unsigned long long read_len;
-+ unsigned long long read_len_tot;
-+ unsigned long read_num;
-+ unsigned long read_num_tot;
-+ unsigned long long write_len;
-+ unsigned long long write_len_tot;
-+ unsigned long write_num;
-+ unsigned long write_num_tot;
-+ int i;
-+ int maxi;
-+
-+ if (sd_iostats == NULL) {
-+ printk(KERN_ERR "sd_iostats_seq_show: NULL stats array\n");
-+ BUG();
-+ }
-+
-+ stats = sd_iostats[scsi_disk(disk)->index];
-+ if (stats == NULL) {
-+ printk(KERN_ERR "sd_iostats_seq_show: NULL stats entry\n");
++ struct timeval now;
++ struct gendisk *disk;
++ iostat_stats_t *stats;
++ unsigned long long read_len;
++ unsigned long long read_len_tot;
++ unsigned long read_num;
++ unsigned long read_num_tot;
++ unsigned long long write_len;
++ unsigned long long write_len_tot;
++ unsigned long write_num;
++ unsigned long write_num_tot;
++ int i;
++ int maxi;
++
++ if (seq == NULL || seq->private == NULL) {
++ printk(KERN_ERR "sd_iostats_seq_show: NULL disk\n");
+ BUG();
+ }
+
-+ do_gettimeofday(&now);
-+ now.tv_sec -= stats->iostat_timeval.tv_sec;
-+ now.tv_usec -= stats->iostat_timeval.tv_usec;
-+ if (now.tv_usec < 0) {
-+ now.tv_usec += 1000000;
-+ now.tv_sec--;
-+ }
-+
-+ /* this sampling races with updates */
-+ seq_printf(seq, "index: %lu snapshot_time: %lu.%06lu\n",
-+ (unsigned long) scsi_disk(disk)->index,
-+ now.tv_sec, now.tv_usec);
-+
-+ for (i = IOSTAT_NCOUNTERS - 1; i > 0; i--)
-+ if (stats->iostat_read_histogram[i].iostat_count != 0 ||
-+ stats->iostat_write_histogram[i].iostat_count != 0)
-+ break;
-+ maxi = i;
-+
-+ seq_printf(seq, "%8s %8s %12s %8s %12s\n", "size",
-+ "reads", "total", "writes", "total");
-+
-+ read_len_tot = write_len_tot = 0;
-+ read_num_tot = write_num_tot = 0;
-+ for (i = 0; i <= maxi; i++) {
-+ read_len = stats->iostat_read_histogram[i].iostat_size;
-+ read_len_tot += read_len;
-+ read_num = stats->iostat_read_histogram[i].iostat_count;
-+ read_num_tot += read_num;
-+
-+ write_len = stats->iostat_write_histogram[i].iostat_size;
-+ write_len_tot += write_len;
-+ write_num = stats->iostat_write_histogram[i].iostat_count;
-+ write_num_tot += write_num;
-+
-+ seq_printf (seq, "%8d %8lu %12llu %8lu %12llu\n",
-+ 512<<i, read_num, read_len, write_num, write_len);
-+ }
++ disk = seq->private;
+
-+ seq_printf(seq, "%8s %8lu %12llu %8lu %12llu\n\n", "total",
-+ read_num_tot, read_len_tot,
-+ write_num_tot, write_len_tot);
-+
-+ seq_printf(seq, "%8s %8s %8s\n", "qdepth", "ticks", "%");
-+ for (i = 0; i < IOSTAT_NCOUNTERS; i++) {
-+ unsigned long long ticks, percent;
-+ ticks = stats->iostat_queue_ticks[i];
-+ if (ticks == 0)
-+ continue;
-+ percent = stats->iostat_queue_ticks[i] * 100;
-+ do_div(percent, stats->iostat_queue_ticks_sum);
-+ seq_printf(seq, "%8d %8llu %8llu\n", i, ticks, percent);
++ if (scsi_disk(disk) == NULL || (disk->flags & GENHD_FL_UP) == 0) {
++ seq_printf(seq, "sd_iostats_seq_show: Device %s "
++ "does not exist\n", disk->disk_name);
++ return 0;
+ }
+
-+ if (stats->iostat_reqs != 0) {
-+ unsigned long long aveseek = 0, percent = 0;
-+
-+ if (stats->iostat_seeks) {
-+ aveseek = stats->iostat_seek_sectors;
-+ do_div(aveseek, stats->iostat_seeks);
-+ percent = stats->iostat_seeks * 100;
-+ do_div(percent, stats->iostat_reqs);
-+ }
-+
-+ seq_printf(seq, "\n%llu sectors in %llu reqs: %llu seek(s) over "
-+ "%llu sectors in ave, %llu%% of all reqs\n",
-+ stats->iostat_sectors, stats->iostat_reqs,
-+ stats->iostat_seeks, aveseek, percent);
-+ }
++ if (sd_iostats == NULL) {
++ printk(KERN_ERR "sd_iostats_seq_show: NULL stats array\n");
++ BUG();
++ }
+
-+ seq_printf(seq, "\n%16s %8s %8s %8s %8s\n", "process time", "reads",
-+ "%%", "writes", "%%");
-+ for (i = 0; i < IOSTAT_NCOUNTERS; i++) {
-+ unsigned long read_percent = 0, write_percent = 0;
-+ if (stats->iostat_wtime[i] == 0 &&
-+ stats->iostat_rtime[i] == 0)
-+ continue;
-+ if (stats->iostat_read_reqs)
-+ read_percent = stats->iostat_rtime[i] * 100 /
-+ stats->iostat_read_reqs;
-+ if (stats->iostat_write_reqs)
-+ write_percent = stats->iostat_wtime[i] * 100 /
-+ stats->iostat_write_reqs;
-+ seq_printf(seq, "%16u %8lu %8lu %8lu %8lu\n",
-+ jiffies_to_msecs(((1UL << i) >> 1) << 1),
-+ stats->iostat_rtime[i], read_percent,
-+ stats->iostat_wtime[i], write_percent);
-+ }
++ stats = sd_iostats[scsi_disk(disk)->index];
++ if (stats == NULL) {
++ seq_printf(seq, "sd_iostats_seq_show: sd_iostats "
++ "entry %d does not exist\n",
++ scsi_disk(disk)->index);
++ return 0;
++ }
+
-+ seq_printf(seq, "\n%16s %8s %8s %8s %8s\n", "time in queue", "reads",
-+ "%%", "writes", "%%");
-+ for (i = 0; i < IOSTAT_NCOUNTERS; i++) {
-+ unsigned long read_percent = 0, write_percent = 0;
-+ if (stats->iostat_wtime_in_queue[i] == 0 &&
-+ stats->iostat_rtime_in_queue[i] == 0)
-+ continue;
-+ if (stats->iostat_read_reqs)
-+ read_percent = stats->iostat_rtime_in_queue[i] * 100 /
-+ stats->iostat_read_reqs;
-+ if (stats->iostat_write_reqs)
-+ write_percent = stats->iostat_wtime_in_queue[i] * 100 /
-+ stats->iostat_write_reqs;
-+ seq_printf(seq, "%16u %8lu %8lu %8lu %8lu\n",
-+ jiffies_to_msecs(((1UL << i) >> 1) << 1),
-+ stats->iostat_rtime_in_queue[i],
-+ read_percent,
-+ stats->iostat_wtime_in_queue[i],
-+ write_percent);
-+ }
++ do_gettimeofday(&now);
++ now.tv_sec -= stats->iostat_timeval.tv_sec;
++ now.tv_usec -= stats->iostat_timeval.tv_usec;
++ if (now.tv_usec < 0) {
++ now.tv_usec += 1000000;
++ now.tv_sec--;
++ }
+
-+ return 0;
++ /* this sampling races with updates */
++ seq_printf(seq, "index: %lu snapshot_time: %lu.%06lu\n",
++ scsi_disk(disk)->index, now.tv_sec, now.tv_usec);
++
++ for (i = IOSTAT_NCOUNTERS - 1; i > 0; i--)
++ if (stats->iostat_read_histogram[i].iostat_count != 0 ||
++ stats->iostat_write_histogram[i].iostat_count != 0)
++ break;
++ maxi = i;
++
++ seq_printf(seq, "%8s %8s %12s %8s %12s\n", "size",
++ "reads", "total", "writes", "total");
++
++ read_len_tot = write_len_tot = 0;
++ read_num_tot = write_num_tot = 0;
++ for (i = 0; i <= maxi; i++) {
++ read_len = stats->iostat_read_histogram[i].iostat_size;
++ read_len_tot += read_len;
++ read_num = stats->iostat_read_histogram[i].iostat_count;
++ read_num_tot += read_num;
++
++ write_len = stats->iostat_write_histogram[i].iostat_size;
++ write_len_tot += write_len;
++ write_num = stats->iostat_write_histogram[i].iostat_count;
++ write_num_tot += write_num;
++
++ seq_printf (seq, "%8d %8lu %12llu %8lu %12llu\n",
++ 512<<i, read_num, read_len, write_num, write_len);
++ }
++
++ seq_printf(seq, "%8s %8lu %12llu %8lu %12llu\n", "total",
++ read_num_tot, read_len_tot,
++ write_num_tot, write_len_tot);
++ return 0;
+}
+
+static void *
+sd_iostats_seq_start(struct seq_file *p, loff_t *pos)
+{
-+ return (*pos == 0) ? (void *)1 : NULL;
++ return (*pos == 0) ? (void *)1 : NULL;
+}
+
+static void *
+sd_iostats_seq_next(struct seq_file *p, void *v, loff_t *pos)
+{
-+ ++*pos;
-+ return NULL;
++ ++*pos;
++ return NULL;
+}
+
+static void
+}
+
+static struct seq_operations sd_iostats_seqops = {
-+ .start = sd_iostats_seq_start,
-+ .stop = sd_iostats_seq_stop,
-+ .next = sd_iostats_seq_next,
-+ .show = sd_iostats_seq_show,
++ .start = sd_iostats_seq_start,
++ .stop = sd_iostats_seq_stop,
++ .next = sd_iostats_seq_next,
++ .show = sd_iostats_seq_show,
+};
+
+static int
+sd_iostats_seq_open (struct inode *inode, struct file *file)
+{
-+ int rc;
++ int rc;
+
-+ rc = seq_open(file, &sd_iostats_seqops);
-+ if (rc != 0)
-+ return rc;
++ rc = seq_open(file, &sd_iostats_seqops);
++ if (rc != 0)
++ return rc;
+
-+ ((struct seq_file *)file->private_data)->private = PDE(inode)->data;
-+ return 0;
++ ((struct seq_file *)file->private_data)->private = PDE(inode)->data;
++ return 0;
+}
+
+static ssize_t
+sd_iostats_seq_write(struct file *file, const char *buffer,
+ size_t len, loff_t *off)
+{
-+ struct seq_file *seq = file->private_data;
-+ struct gendisk *disk = seq->private;
-+ iostat_stats_t *stats = sd_iostats[scsi_disk(disk)->index];
-+ unsigned long flags;
-+ unsigned long qdepth;
-+
-+
-+ spin_lock_irqsave (&stats->iostat_lock, flags);
-+ qdepth = stats->iostat_queue_depth;
-+ memset (stats, 0, offsetof(iostat_stats_t, iostat_lock));
-+ do_gettimeofday(&stats->iostat_timeval);
-+ stats->iostat_queue_stamp = jiffies;
-+ stats->iostat_queue_depth = qdepth;
-+ spin_unlock_irqrestore (&stats->iostat_lock, flags);
-+
-+ return len;
++ struct seq_file *seq = file->private_data;
++ struct gendisk *disk = seq->private;
++ iostat_stats_t *stats = sd_iostats[scsi_disk(disk)->index];
++ unsigned long flags;
++
++
++ spin_lock_irqsave (&sd_iostats_lock, flags);
++ memset (stats, 0, sizeof(*stats));
++ do_gettimeofday(&stats->iostat_timeval);
++ spin_unlock_irqrestore (&sd_iostats_lock, flags);
++
++ return len;
+}
+
+static struct file_operations sd_iostats_proc_fops = {
-+ .owner = THIS_MODULE,
-+ .open = sd_iostats_seq_open,
-+ .read = seq_read,
-+ .write = sd_iostats_seq_write,
-+ .llseek = seq_lseek,
-+ .release = seq_release,
++ .owner = THIS_MODULE,
++ .open = sd_iostats_seq_open,
++ .read = seq_read,
++ .write = sd_iostats_seq_write,
++ .llseek = seq_lseek,
++ .release = seq_release,
+};
+
+extern struct proc_dir_entry *proc_scsi;
+void
+sd_iostats_init(void)
+{
-+ int i;
-+
-+ sd_iostats = kmalloc(SD_STATS * sizeof(iostat_stats_t *), GFP_KERNEL);
-+ if (sd_iostats == NULL) {
-+ printk(KERN_WARNING "Can't keep sd iostats: "
-+ "ENOMEM allocating stats array size %d\n",
-+ SD_STATS * sizeof(iostat_stats_t *));
-+ return;
-+ }
++ int i;
+
-+ for (i = 0; i < SD_STATS; i++)
-+ sd_iostats[i] = NULL;
++ spin_lock_init(&sd_iostats_lock);
+
-+ if (proc_scsi == NULL) {
-+ printk(KERN_WARNING "No access to sd iostats: "
-+ "proc_scsi is NULL\n");
-+ return;
-+ }
++ sd_iostats = kmalloc(SD_STATS * sizeof(iostat_stats_t *), GFP_KERNEL);
++ if (sd_iostats == NULL) {
++ printk(KERN_WARNING "Can't keep sd iostats: "
++ "ENOMEM allocating stats array size %ld\n",
++ SD_STATS * sizeof(iostat_stats_t *));
++ return;
++ }
++
++ for (i = 0; i < SD_STATS; i++)
++ sd_iostats[i] = NULL;
++
++ if (proc_scsi == NULL) {
++ printk(KERN_WARNING "No access to sd iostats: "
++ "proc_scsi is NULL\n");
++ return;
++ }
+
-+ sd_iostats_procdir = create_proc_entry(sd_iostats_procdir_name,
-+ S_IFDIR | S_IRUGO | S_IXUGO,
-+ proc_scsi);
-+ if (sd_iostats_procdir == NULL) {
-+ printk(KERN_WARNING "No access to sd iostats: "
-+ "can't create /proc/scsi/%s\n", sd_iostats_procdir_name);
-+ return;
++ sd_iostats_procdir = create_proc_entry(sd_iostats_procdir_name,
++ S_IFDIR | S_IRUGO | S_IXUGO,
++ proc_scsi);
++ if (sd_iostats_procdir == NULL) {
++ printk(KERN_WARNING "No access to sd iostats: "
++ "can't create /proc/scsi/%s\n", sd_iostats_procdir_name);
++ return;
+ }
+}
+
+void
+sd_iostats_init_disk(struct gendisk *disk)
+{
-+ struct proc_dir_entry *pde;
-+ unsigned long flags;
-+ iostat_stats_t *stats;
-+
-+ if (sd_iostats == NULL || sd_iostats_procdir == NULL)
-+ return;
-+
-+ if (scsi_disk(disk)->index > SD_STATS) {
-+ printk(KERN_ERR "sd_iostats_init_disk: "
-+ "unexpected disk index %d(%d)\n",
-+ scsi_disk(disk)->index, SD_STATS);
-+ return;
-+ }
-+
-+ if (sd_iostats[scsi_disk(disk)->index] != NULL)
-+ return;
-+
-+ stats = kmalloc(sizeof(*stats), GFP_KERNEL);
-+ if (stats == NULL) {
-+ printk(KERN_WARNING "Can't keep %s iostats: "
-+ "ENOMEM allocating stats size %d\n",
-+ disk->disk_name, sizeof(*stats));
-+ return;
-+ }
-+
-+ memset (stats, 0, sizeof(*stats));
-+ do_gettimeofday(&stats->iostat_timeval);
-+ stats->iostat_queue_stamp = jiffies;
-+ spin_lock_init(&stats->iostat_lock);
-+
++ struct proc_dir_entry *pde;
++ unsigned long flags;
++ iostat_stats_t *stats;
++
++ if (sd_iostats == NULL ||
++ sd_iostats_procdir == NULL)
++ return;
++
++ if (scsi_disk(disk)->index > SD_STATS) {
++ printk(KERN_ERR "sd_iostats_init_disk: "
++ "unexpected disk index %d(%d)\n",
++ scsi_disk(disk)->index, SD_STATS);
++ return;
++ }
+
-+ spin_lock_irqsave(&stats->iostat_lock, flags);
++ if (sd_iostats[scsi_disk(disk)->index] != NULL)
++ return;
+
-+ if (sd_iostats[scsi_disk(disk)->index] != NULL) {
-+ spin_unlock_irqrestore(&stats->iostat_lock, flags);
-+ kfree (stats);
-+ return;
-+ }
++ stats = kmalloc(sizeof(*stats), GFP_KERNEL);
++ if (stats == NULL) {
++ printk(KERN_WARNING "Can't keep %s iostats: "
++ "ENOMEM allocating stats size %ld\n",
++ disk->disk_name, sizeof(*stats));
++ return;
++ }
+
-+ sd_iostats[scsi_disk(disk)->index] = stats;
++ memset (stats, 0, sizeof(*stats));
++ do_gettimeofday(&stats->iostat_timeval);
+
-+ spin_unlock_irqrestore(&stats->iostat_lock, flags);
++ spin_lock_irqsave(&sd_iostats_lock, flags);
+
-+ strncpy(stats->iostat_name, disk->disk_name,
-+ sizeof(stats->iostat_name)-1);
++ if (sd_iostats[scsi_disk(disk)->index] != NULL) {
++ spin_unlock_irqrestore(&sd_iostats_lock, flags);
++ kfree (stats);
++ return;
++ }
+
-+ pde = create_proc_entry(stats->iostat_name, S_IRUGO | S_IWUSR,
-+ sd_iostats_procdir);
-+ if (pde == NULL) {
-+ printk(KERN_WARNING "Can't create /proc/scsi/%s/%s\n",
-+ sd_iostats_procdir_name, disk->disk_name);
-+ } else {
-+ pde->proc_fops = &sd_iostats_proc_fops;
-+ pde->data = disk;
-+ }
++ sd_iostats[scsi_disk(disk)->index] = stats;
++
++ spin_unlock_irqrestore(&sd_iostats_lock, flags);
++
++ pde = create_proc_entry(disk->disk_name, S_IRUGO | S_IWUSR,
++ sd_iostats_procdir);
++ if (pde == NULL) {
++ printk(KERN_WARNING "Can't create /proc/scsi/%s/%s\n",
++ sd_iostats_procdir_name, disk->disk_name);
++ } else {
++ pde->proc_fops = &sd_iostats_proc_fops;
++ pde->data = disk;
++ }
+}
+
-+void sd_iostats_fini(void)
++static void sd_devname(unsigned int disknum, char *buffer)
+{
-+ int i;
-+
-+ if (sd_iostats == NULL)
-+ return;
-+
-+ for (i = 0; i < SD_STATS; i++) {
-+ if (sd_iostats[i] == NULL)
-+ continue;
-+ if (sd_iostats_procdir != NULL)
-+ remove_proc_entry(sd_iostats[i]->iostat_name,
-+ sd_iostats_procdir);
-+ kfree(sd_iostats[i]);
-+ }
-+
-+ if (proc_scsi != NULL && sd_iostats_procdir != NULL)
-+ remove_proc_entry(sd_iostats_procdir_name, proc_scsi);
-+
-+ sd_iostats_procdir = NULL;
-+ kfree(sd_iostats);
-+ sd_iostats = NULL;
++ if (disknum < 26)
++ sprintf(buffer, "sd%c", 'a' + disknum);
++ else {
++ unsigned int min1;
++ unsigned int min2;
++ /*
++ * For larger numbers of disks, we need to go to a new
++ * naming scheme.
++ */
++ min1 = disknum / 26;
++ min2 = disknum % 26;
++ sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2);
++ }
+}
+
-+void sd_iostats_finish_req(struct scsi_cmnd *SCpnt)
++void
++sd_iostats_fini(void)
+{
-+ struct request *rq = SCpnt->request;
-+ iostat_stats_t *stats;
-+ unsigned long *tcounter;
-+ int tbucket;
-+ int tmp;
-+ unsigned long irqflags;
-+ int disk, i;
-+
-+ disk = scsi_disk(rq->rq_disk)->index;
-+
-+ if (sd_iostats == NULL)
-+ return;
-+
-+ if (disk < 0 || disk >= SD_STATS) {
-+ printk(KERN_ERR "sd_iostats_bump: unexpected disk index "
-+ "%d([0-%d])\n", disk, SD_STATS);
-+ BUG();
-+ }
-+
-+ stats = sd_iostats[disk];
-+ if (stats == NULL)
-+ return;
-+
-+ tmp = jiffies - rq->start_time;
-+ for (tbucket = 0; tmp > 1; tbucket++)
-+ tmp >>= 1;
-+ if (tbucket >= IOSTAT_NCOUNTERS)
-+ tbucket = IOSTAT_NCOUNTERS - 1;
-+ //printk("%u ticks in D to %u\n", jiffies - rq->start_time, tbucket);
-+
-+ tcounter = rq_data_dir(rq) == WRITE ?
-+ &stats->iostat_wtime[tbucket] : &stats->iostat_rtime[tbucket];
-+
-+ spin_lock_irqsave(&stats->iostat_lock, irqflags);
-+
-+ /* update delay stats */
-+ (*tcounter)++;
-+
-+ /* update queue depth stats */
-+ i = stats->iostat_queue_depth;
-+ if (i >= IOSTAT_NCOUNTERS)
-+ i = IOSTAT_NCOUNTERS - 1;
-+ stats->iostat_queue_ticks[i] += jiffies - stats->iostat_queue_stamp;
-+ stats->iostat_queue_ticks_sum += jiffies - stats->iostat_queue_stamp;
-+ stats->iostat_queue_depth--;
-+
-+ /* update seek stats. XXX: not sure about nr_sectors */
-+ stats->iostat_sectors += rq->nr_sectors;
-+ stats->iostat_reqs++;
-+ if (rq->sector != stats->iostat_next_sector) {
-+ stats->iostat_seek_sectors +=
-+ rq->sector > stats->iostat_next_sector ?
-+ rq->sector - stats->iostat_next_sector :
-+ stats->iostat_next_sector - rq->sector;
-+ stats->iostat_seeks++;
-+ }
-+ stats->iostat_next_sector = rq->sector + rq->nr_sectors;
-+
-+ stats->iostat_queue_stamp = jiffies;
-+
-+ spin_unlock_irqrestore(&stats->iostat_lock, irqflags);
++ char name[6];
++ int i;
++
++ if (sd_iostats_procdir != NULL) {
++ for (i = 0; i < SD_STATS; i++) {
++ sd_devname(i, name);
++ remove_proc_entry(name, sd_iostats_procdir);
++ }
++
++ if (proc_scsi == NULL) {
++ printk(KERN_ERR "sd_iostats_fini: proc_scsi NULL\n");
++ BUG();
++ }
++ remove_proc_entry(sd_iostats_procdir_name,
++ proc_scsi);
++
++ sd_iostats_procdir = NULL;
++ }
++
++ if (sd_iostats != NULL) {
++ for (i = 0; i < SD_STATS; i++) {
++ if (sd_iostats[i] != NULL)
++ kfree (sd_iostats[i]);
++ }
++
++ kfree(sd_iostats);
++ sd_iostats = NULL;
++ }
+}
+
-+void sd_iostats_start_req(struct scsi_cmnd *SCpnt)
++void
++sd_iostats_bump(int disk, unsigned int nsect, int iswrite)
+{
-+ struct request *rq = SCpnt->request;
-+ iostat_stats_t *stats;
-+ iostat_counter_t *counter;
-+ int bucket;
-+ int tbucket;
-+ int tmp;
-+ unsigned long irqflags;
-+ int disk, i;
-+ int nsect;
-+
-+ disk = scsi_disk(rq->rq_disk)->index;
-+
-+ if (sd_iostats == NULL)
-+ return;
-+
-+ if (disk < 0 || disk >= SD_STATS) {
-+ printk(KERN_ERR "sd_iostats_bump: unexpected disk index %d([0-%d])\n",
-+ disk, SD_STATS);
-+ BUG();
-+ }
-+
-+ stats = sd_iostats[disk];
-+ if (stats == NULL)
-+ return;
-+
-+ nsect = SCpnt->request_bufflen >> 9;
-+ for (bucket = 0, tmp = nsect; tmp > 1; bucket++)
-+ tmp >>= 1;
++ iostat_stats_t *stats;
++ iostat_counter_t *counter;
++ int bucket;
++ int tmp;
++ unsigned long irqflags;
++
++ if (sd_iostats == NULL)
++ return;
++
++ if (disk < 0 || disk >= SD_STATS) {
++ printk(KERN_ERR "sd_iostats_bump: unexpected disk index %d([0-%d])\n",
++ disk, SD_STATS);
++ BUG();
++ }
+
-+ if (bucket >= IOSTAT_NCOUNTERS) {
-+ printk (KERN_ERR "sd_iostats_bump: nsect %d too big\n", nsect);
-+ BUG();
-+ }
++ for (bucket = 0, tmp = nsect; tmp > 1; bucket++)
++ tmp /= 2;
+
-+ counter = rq_data_dir(rq) == WRITE ?
-+ &stats->iostat_write_histogram[bucket] :
-+ &stats->iostat_read_histogram[bucket];
-+
-+ tmp = jiffies - rq->start_time;
-+ for (tbucket = 0; tmp > 1; tbucket++)
-+ tmp >>= 1;
-+ if (tbucket >= IOSTAT_NCOUNTERS)
-+ tbucket = IOSTAT_NCOUNTERS - 1;
-+ //printk("%u ticks in Q to %u\n", jiffies - rq->start_time, tbucket);
-+
-+ /* an ugly hack to know exact processing time. the right
-+ * solution is to add one more field to struct request
-+ * hopefully it will break nothing ... */
-+ rq->start_time = jiffies;
-+
-+ spin_lock_irqsave(&stats->iostat_lock, irqflags);
-+
-+ /* update queue depth stats */
-+ i = stats->iostat_queue_depth;
-+ if (i >= IOSTAT_NCOUNTERS)
-+ i = IOSTAT_NCOUNTERS - 1;
-+ stats->iostat_queue_ticks[i] += jiffies - stats->iostat_queue_stamp;
-+ stats->iostat_queue_ticks_sum += jiffies - stats->iostat_queue_stamp;
-+ stats->iostat_queue_depth++;
-+
-+ /* update delay stats */
-+ if (rq_data_dir(rq) == WRITE) {
-+ stats->iostat_wtime_in_queue[tbucket]++;
-+ stats->iostat_write_reqs++;
-+ } else {
-+ stats->iostat_rtime_in_queue[tbucket]++;
-+ stats->iostat_read_reqs++;
-+ }
++ if (bucket >= IOSTAT_NCOUNTERS) {
++ printk (KERN_ERR "sd_iostats_bump: nsect %d too big\n", nsect);
++ BUG();
++ }
+
-+ /* update size stats */
-+ counter->iostat_size += nsect;
-+ counter->iostat_count++;
++ spin_lock_irqsave(&sd_iostats_lock, irqflags);
++
++ stats = sd_iostats[disk];
++ if (stats != NULL) {
++ counter = iswrite ?
++ &stats->iostat_write_histogram[bucket] :
++ &stats->iostat_read_histogram[bucket];
+
-+ stats->iostat_queue_stamp = jiffies;
++ counter->iostat_size += nsect;
++ counter->iostat_count++;
++ }
+
-+ spin_unlock_irqrestore(&stats->iostat_lock, irqflags);
++ spin_unlock_irqrestore(&sd_iostats_lock, irqflags);
+}
+#endif
+
/**
* init_sd - entry point for this driver (both when built in or when
* a module).
-@@ -1584,6 +2127,7 @@ static void sd_shutdown(struct device *d
+@@ -1584,6 +1969,7 @@ static void sd_shutdown(struct device *d
static int __init init_sd(void)
{
int majors = 0, i;
SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
-@@ -1594,7 +2138,10 @@ static int __init init_sd(void)
+@@ -1594,7 +1980,10 @@ static int __init init_sd(void)
if (!majors)
return -ENODEV;
}
/**
-@@ -1608,6 +2155,7 @@ static void __exit exit_sd(void)
+@@ -1608,6 +1997,7 @@ static void __exit exit_sd(void)
SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
scsi_unregister_driver(&sd_template.gendrv);
for (i = 0; i < SD_MAJORS; i++)
unregister_blkdev(sd_major(i), "sd");
+Index: linux+rhel4+chaos/drivers/scsi/scsi_proc.c
+===================================================================
+--- linux+rhel4+chaos.orig/drivers/scsi/scsi_proc.c
++++ linux+rhel4+chaos/drivers/scsi/scsi_proc.c
+@@ -38,7 +38,8 @@
+ /* 4K page size, but our output routines, use some slack for overruns */
+ #define PROC_BLOCK_SIZE (3*1024)
+
+-static struct proc_dir_entry *proc_scsi;
++struct proc_dir_entry *proc_scsi;
++EXPORT_SYMBOL(proc_scsi);
+
+ /* Protect sht->present and sht->proc_dir */
+ static DECLARE_MUTEX(global_host_template_sem);