-Index: linux-2.6.9-5.0.3.EL/drivers/scsi/Kconfig\r
-===================================================================\r
-Index: linux-2.6.9/drivers/scsi/Kconfig
+Index: linux-2.6.9-67.0.20/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-2.6.9-67.0.20.orig/drivers/scsi/Kconfig
++++ linux-2.6.9-67.0.20/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-2.6.9-67.0.20/drivers/scsi/scsi_proc.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
+--- linux-2.6.9-67.0.20.orig/drivers/scsi/scsi_proc.c
++++ linux-2.6.9-67.0.20/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)
/* Protect sht->present and sht->proc_dir */
static DECLARE_MUTEX(global_host_template_sem);
-Index: linux-2.6.9/drivers/scsi/sd.c
+Index: linux-2.6.9-67.0.20/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-2.6.9-67.0.20.orig/drivers/scsi/sd.c
++++ linux-2.6.9-67.0.20/drivers/scsi/sd.c
+@@ -63,6 +63,63 @@
#include "scsi_logging.h"
+# include <linux/seq_file.h>
+
+typedef struct {
-+ unsigned long long iostat_size;
-+ unsigned long long iostat_count;
++ unsigned long long iostat_size;
++ unsigned long long iostat_count;
+} iostat_counter_t;
+
+#define IOSTAT_NCOUNTERS 16
+typedef struct {
-+ iostat_counter_t iostat_read_histogram[IOSTAT_NCOUNTERS];
-+ iostat_counter_t iostat_write_histogram[IOSTAT_NCOUNTERS];
-+ struct timeval iostat_timeval;
++ 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 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;
++ spinlock_t iostat_lock;
++} ____cacheline_aligned_in_smp iostat_stats_t;
+
-+iostat_stats_t **sd_iostats;
-+struct proc_dir_entry *sd_iostats_procdir;
-+char sd_iostats_procdir_name[] = "sd_iostats";
++struct proc_dir_entry *sd_iostats_procdir = NULL;
++char sd_iostats_procdir_name[] = "sd_iostats";
++static struct file_operations sd_iostats_proc_fops;
+
+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);
+#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) {}
/*
* 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 @@
- */
- #define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26)
+@@ -101,6 +158,9 @@ struct scsi_disk {
+ u8 write_prot;
+ unsigned WCE : 1; /* state of disk WCE bit */
+ unsigned RCD : 1; /* state of disk RCD bit, unused */
++#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
++ iostat_stats_t *stats; /* scsi disk statistics */
++#endif
+ };
-+#define SD_STATS 256
- /*
- * Time out in seconds for disks and Magneto-opticals (which are slower).
- */
-@@ -278,6 +340,8 @@ static int sd_init_command(struct scsi_c
- SCSI_LOG_HLQUEUE(2, printk("%s : block=%llu\n",
- disk->disk_name, (unsigned long long)block));
+ static DEFINE_IDR(sd_index_idr);
+@@ -391,6 +451,8 @@ queue:
+ SCpnt->allowed = SD_MAX_RETRIES;
+ SCpnt->timeout_per_command = timeout;
+ sd_iostats_start_req(SCpnt);
+
/*
- * 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,
- scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT);
- }
-
-+ sd_iostats_init_disk(disk);
- return 0;
-
- error_out:
-@@ -849,6 +914,9 @@ static void sd_rw_intr(struct scsi_cmnd
+ * This is the completion routine we use. This is matched in terms
+ * of capability to this function.
+@@ -849,6 +911,9 @@ static void sd_rw_intr(struct scsi_cmnd
break;
}
}
/*
* 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
+@@ -1487,6 +1552,36 @@ static int sd_probe(struct device *dev)
+ gd->flags |= GENHD_FL_REMOVABLE;
+ gd->queue = sdkp->device->request_queue;
+
++#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
++ sdkp->stats = kzalloc(sizeof(iostat_stats_t), GFP_KERNEL);
++ if (!sdkp->stats) {
++ printk(KERN_WARNING "cannot allocate iostat structure for"
++ "%s\n", gd->disk_name);
++ } else {
++ do_gettimeofday(&sdkp->stats->iostat_timeval);
++ sdkp->stats->iostat_queue_stamp = jiffies;
++ spin_lock_init(&sdkp->stats->iostat_lock);
++ if (sd_iostats_procdir) {
++ struct proc_dir_entry *pde;
++ pde = create_proc_entry(gd->disk_name, S_IRUGO | S_IWUSR,
++ sd_iostats_procdir);
++ if (!pde) {
++ printk(KERN_WARNING "Can't create /proc/scsi/"
++ "%s/%s\n",
++ sd_iostats_procdir_name,
++ gd->disk_name);
++ kfree(sdkp->stats);
++ sdkp->stats = NULL;
++ } else {
++ pde->proc_fops = &sd_iostats_proc_fops;
++ pde->data = gd;
++ }
++ } else {
++ kfree(sdkp->stats);
++ sdkp->stats = NULL;
++ }
++ }
++#endif
+ dev_set_drvdata(dev, sdkp);
+ add_disk(gd);
+
+@@ -1549,8 +1644,14 @@ static void scsi_disk_release(struct kre
+
+ disk->private_data = NULL;
+
++#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
++ if (sdkp->stats) {
++ remove_proc_entry(disk->disk_name, sd_iostats_procdir);
++ kfree(sdkp->stats);
++ sdkp->stats = NULL;
++ }
++#endif
+ put_disk(disk);
+-
+ kfree(sdkp);
+ }
+
+@@ -1575,6 +1676,366 @@ static void sd_shutdown(struct device *d
sd_sync_cache(sdp);
}
+ 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];
++ stats = scsi_disk(disk)->stats;
+ if (stats == NULL) {
+ printk(KERN_ERR "sd_iostats_seq_show: NULL stats entry\n");
+ BUG();
+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)
+
+static ssize_t
+sd_iostats_seq_write(struct file *file, const char *buffer,
-+ size_t len, loff_t *off)
++ 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];
++ iostat_stats_t *stats = scsi_disk(disk)->stats;
+ unsigned long flags;
+ unsigned long qdepth;
+
+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;
-+ }
-+
-+ 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");
+ 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);
-+
-+
-+ spin_lock_irqsave(&stats->iostat_lock, flags);
-+
-+ if (sd_iostats[scsi_disk(disk)->index] != NULL) {
-+ spin_unlock_irqrestore(&stats->iostat_lock, flags);
-+ kfree (stats);
-+ return;
-+ }
-+
-+ sd_iostats[scsi_disk(disk)->index] = stats;
-+
-+ spin_unlock_irqrestore(&stats->iostat_lock, flags);
-+
-+ strncpy(stats->iostat_name, disk->disk_name,
-+ sizeof(stats->iostat_name)-1);
-+
-+ 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;
+ }
+}
+
+void sd_iostats_fini(void)
+{
-+ 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;
+}
+
+void sd_iostats_finish_req(struct scsi_cmnd *SCpnt)
+ 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();
-+ }
++ unsigned long i;
+
-+ stats = sd_iostats[disk];
++ stats = scsi_disk(rq->rq_disk)->stats;
+ if (stats == NULL)
+ return;
+
+ i = IOSTAT_NCOUNTERS - 1;
+ stats->iostat_queue_ticks[i] += jiffies - stats->iostat_queue_stamp;
+ stats->iostat_queue_ticks_sum += jiffies - stats->iostat_queue_stamp;
++ BUG_ON(stats->iostat_queue_depth == 0);
+ stats->iostat_queue_depth--;
+
+ /* update seek stats. XXX: not sure about nr_sectors */
+ int tbucket;
+ int tmp;
+ unsigned long irqflags;
-+ int disk, i;
++ unsigned long 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];
++ stats = scsi_disk(rq->rq_disk)->stats;
+ if (stats == NULL)
+ return;
+
/**
* 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 +2045,7 @@ static void sd_shutdown(struct device *d
static int __init init_sd(void)
{
int majors = 0, i;
-+ int rc = 0;
++ int rc = 0;
SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
-@@ -1594,7 +2138,10 @@ static int __init init_sd(void)
+@@ -1594,7 +2056,11 @@ static int __init init_sd(void)
if (!majors)
return -ENODEV;
- return scsi_register_driver(&sd_template.gendrv);
-+ rc = scsi_register_driver(&sd_template.gendrv);
-+ if (rc == 0)
-+ sd_iostats_init();
-+ return rc;
++ sd_iostats_init();
++ rc = scsi_register_driver(&sd_template.gendrv);
++ if (rc)
++ sd_iostats_fini();
++ return rc;
}
/**
-@@ -1608,6 +2155,7 @@ static void __exit exit_sd(void)
-
- SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
-
-+ sd_iostats_fini();
+@@ -1611,6 +2077,7 @@ static void __exit exit_sd(void)
scsi_unregister_driver(&sd_template.gendrv);
for (i = 0; i < SD_MAJORS; i++)
unregister_blkdev(sd_major(i), "sd");
++ sd_iostats_fini();
+ }
+
+ MODULE_LICENSE("GPL");