* SCSI RAM driver
@ 2008-02-18 6:36 Matthew Wilcox
2008-02-19 13:14 ` FUJITA Tomonori
0 siblings, 1 reply; 5+ messages in thread
From: Matthew Wilcox @ 2008-02-18 6:36 UTC (permalink / raw)
To: linux-scsi; +Cc: Kristen Carlson Accardi
This is the first release of a driver we've been using internally at Intel
for a few weeks which is as low-latency as possible. It's designed to
let us find latency issues elsewhere in the storage stack (eg filesystem,
block layer, scsi layer)
There are a few different options, controlled through module parameters.
The sector size and disc capacity are load-time parameters, but the
parameters affecting performance are tweakable at runtime.
Arguably, this driver should be merged into scsi_debug. I didn't want to
trip over Doug's toes while developing this driver, and the two drivers
do have very different objectives. scsi_debug is obviously a lot more
fully-featured and implements lots of bits of the spec I simply haven't
bothered with. Like MODE SENSE ;-)
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index a5f0aaa..e8dd685 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1499,6 +1499,16 @@ config SCSI_DEBUG
information. This driver is primarily of use to those testing the
SCSI and block subsystems. If unsure, say N.
+config SCSI_RAM
+ tristate "SCSI RAM-based host"
+ depends on SCSI
+ help
+ This driver simulates a host adapter with one disc attached.
+ The primary purpose of this driver is for performance testing
+ of the fs/block/scsi stack; as such it attempts to simulate a
+ disc which is as fast as RAM. If you are unsure how to answer
+ this question, say N.
+
config SCSI_MESH
tristate "MESH (Power Mac internal SCSI) support"
depends on PPC32 && PPC_PMAC && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 925c26b..95466d8 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -133,6 +133,7 @@ obj-$(CONFIG_SCSI_ENCLOSURE) += ses.o
# This goes last, so that "real" scsi devices probe earlier
obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
+obj-$(CONFIG_SCSI_RAM) += scsi_ram.o
obj-$(CONFIG_SCSI_WAIT_SCAN) += scsi_wait_scan.o
diff --git a/drivers/scsi/scsi_ram.c b/drivers/scsi/scsi_ram.c
new file mode 100644
index 0000000..f097aee
--- /dev/null
+++ b/drivers/scsi/scsi_ram.c
@@ -0,0 +1,618 @@
+/*
+ * scsi_ram.c - A RAM-based SCSI driver for Linux.
+ *
+ * This driver is intended to run as fast as possible, hence the options
+ * to discard writes and reads.
+ * By default, it'll allocate half a gigabyte of RAM to use as a ramdisc;
+ * you can change this with the `capacity' module parameter.
+ *
+ * (C) Copyright 2007-2008 Intel Corporation
+ * Author: Matthew Wilcox <willy@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#undef DEBUG
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_dbg.h>
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Matthew Wilcox <willy@linux.intel.com>");
+
+#define DRV_NAME "scsi_ram"
+
+static unsigned int sector_size = 512;
+module_param(sector_size, uint, 0444);
+MODULE_PARM_DESC(sector_size, "Size of sectors");
+
+static unsigned int capacity = 1024 * 1024;
+module_param(capacity, uint, 0444);
+MODULE_PARM_DESC(capacity, "Number of logical blocks in device");
+
+static int throw_away_writes;
+module_param(throw_away_writes, int, 0644);
+MODULE_PARM_DESC(throw_away_writes, "Discard all writes to the device");
+
+static int throw_away_reads;
+module_param(throw_away_reads, int, 0644);
+MODULE_PARM_DESC(throw_away_reads, "Don't actually read data from the device");
+
+static int use_thread = 1;
+module_param(use_thread, int, 0644);
+MODULE_PARM_DESC(use_thread, "Use a separate thread to do data accesses");
+
+static void copy_buffer(struct scsi_cmnd *cmnd, char *buf, int len)
+{
+ char *p;
+ struct scatterlist *sg;
+ int i;
+
+ scsi_for_each_sg(cmnd, sg, scsi_sg_count(cmnd), i) {
+ int tocopy = sg->length;
+ if (tocopy > len)
+ tocopy = len;
+
+ p = kmap_atomic(sg_page(sg), KM_USER0);
+ memcpy(p + sg->offset, buf, tocopy);
+ kunmap_atomic(p, KM_USER0);
+
+ len -= tocopy;
+ if (!len)
+ break;
+ buf += tocopy;
+ }
+
+ scsi_set_resid(cmnd, len);
+}
+
+static char inquiry[57] = {
+ 0, 0, 5, 0x22, 52, 0, 0, 0x0a, /* 0-7 */
+ 'L', 'i', 'n', 'u', 'x', ' ', ' ', ' ', /* 8-15 */
+ 'R', 'A', 'M', ' ', 'D', 'r', 'i', 'v', /* 16-23 */
+ 'e', ' ', ' ', ' ', ' ', ' ', ' ', ' ', /* 24-31 */
+ '0', '.', '0', '1', 0, 0, 0, 0, /* 32-39 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 40-47 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 48-55 */
+ 0 /* 56 */
+};
+
+static char report_luns[] = {
+ 0, 0, 0, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * SCSI requires quantities to be written MSB. They're frequently misaligned,
+ * so don't mess about with cpu_to_beN, just access it byte-wise
+ */
+static void scsi_ram_put_u32(unsigned char *addr, unsigned int data)
+{
+ addr[0] = data >> 24;
+ addr[1] = data >> 16;
+ addr[2] = data >> 8;
+ addr[3] = data;
+}
+
+static unsigned int scsi_ram_get_u16(unsigned char *addr)
+{
+ unsigned int data;
+ data = addr[0] << 8;
+ data |= addr[1];
+
+ return data;
+}
+
+static unsigned int scsi_ram_get_u24(unsigned char *addr)
+{
+ unsigned int data;
+ data = addr[0] << 16;
+ data |= addr[1] << 8;
+ data |= addr[2];
+
+ return data;
+}
+
+static unsigned int scsi_ram_get_u32(unsigned char *addr)
+{
+ unsigned int data;
+ data = addr[0] << 24;
+ data |= addr[1] << 16;
+ data |= addr[2] << 8;
+ data |= addr[3];
+
+ return data;
+}
+
+static void scsi_ram_setup_sense(struct scsi_cmnd *cmnd, unsigned char key,
+ unsigned char asc, unsigned char ascq)
+{
+ if (0) {
+ cmnd->sense_buffer[0] = 0x72;
+ cmnd->sense_buffer[1] = key;
+ cmnd->sense_buffer[2] = asc;
+ cmnd->sense_buffer[3] = ascq;
+ cmnd->sense_buffer[7] = 0;
+ } else {
+ cmnd->sense_buffer[0] = 0x70;
+ cmnd->sense_buffer[1] = 0;
+ cmnd->sense_buffer[2] = key;
+ cmnd->sense_buffer[7] = 11;
+ cmnd->sense_buffer[12] = asc;
+ cmnd->sense_buffer[13] = ascq;
+ }
+}
+
+static void scsi_ram_inquiry(struct scsi_cmnd *cmnd)
+{
+ if (cmnd->cmnd[1] & 1) {
+ switch (cmnd->cmnd[2]) {
+ default:
+ scsi_ram_setup_sense(cmnd, ILLEGAL_REQUEST, 0x24, 0);
+ cmnd->result = SAM_STAT_CHECK_CONDITION;
+ }
+ } else {
+ copy_buffer(cmnd, inquiry, sizeof(inquiry));
+ }
+}
+
+static void scsi_ram_read_capacity(struct scsi_cmnd *cmnd)
+{
+ char buf[8];
+ scsi_ram_put_u32(buf, capacity - 1);
+ scsi_ram_put_u32(buf + 4, sector_size);
+ copy_buffer(cmnd, buf, sizeof(buf));
+}
+
+static void scsi_ram_mode_sense(struct scsi_cmnd *cmnd)
+{
+
+}
+
+
+static struct page **scsi_ram_data_array;
+
+/*
+ * We could steal the pages we need from the requests as they come in, which
+ * is what rd.c does. However, that's not a realistic simulator of how a
+ * device would work. We want the request pages to get freed and go back into
+ * the page allocator.
+ */
+static int scsi_ram_alloc_data(void)
+{
+ unsigned long pages = capacity / PAGE_SIZE * sector_size;
+ unsigned int i;
+
+ scsi_ram_data_array = kmalloc(pages * sizeof(void *), GFP_KERNEL);
+ if (!scsi_ram_data_array)
+ return -ENOMEM;
+
+ for (i = 0; i < pages; i++) {
+ struct page *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+ scsi_ram_data_array[i] = page;
+
+ /* scsi_ram_free_data will be called on failure */
+ if (!page)
+ return -ENOMEM;
+ clear_highpage(page);
+ }
+
+ return 0;
+}
+
+static void scsi_ram_free_data(void)
+{
+ unsigned long pages = capacity / PAGE_SIZE * sector_size;
+ unsigned int i;
+
+ if (!scsi_ram_data_array)
+ return;
+
+ for (i = 0; i < pages; i++) {
+ struct page *page = scsi_ram_data_array[i];
+ if (!page)
+ break;
+ __free_page(page);
+ }
+
+ kfree(scsi_ram_data_array);
+}
+
+static void scsi_ram_too_big(struct scsi_cmnd *cmnd, unsigned int start,
+ unsigned int len)
+{
+ printk("Request exceeded device capacity! %u %u\n", start, len);
+ scsi_ram_setup_sense(cmnd, ILLEGAL_REQUEST, 0x21, 0);
+ cmnd->result = SAM_STAT_CHECK_CONDITION;
+}
+
+static void *get_data_page(unsigned int pfn)
+{
+ return kmap_atomic(scsi_ram_data_array[pfn], KM_USER0);
+}
+
+static void put_data_page(void *addr)
+{
+ kunmap_atomic(addr, KM_USER0);
+}
+
+static void *get_sg_page(struct page *page)
+{
+ return kmap_atomic(page, KM_USER1);
+}
+
+static void put_sg_page(void *addr)
+{
+ kunmap_atomic(addr, KM_USER1);
+}
+
+static void scsi_ram_read(struct scsi_cmnd *cmnd, unsigned int startB,
+ unsigned int lenB)
+{
+ unsigned long start = startB * sector_size;
+ unsigned long len = lenB * sector_size;
+ struct scatterlist *sg;
+ unsigned i, from_off = start % PAGE_SIZE, data_pfn = start / PAGE_SIZE;
+
+ if (startB > capacity || (startB + lenB) > capacity)
+ return scsi_ram_too_big(cmnd, startB, lenB);
+
+ if (throw_away_reads)
+ return;
+
+ scsi_for_each_sg(cmnd, sg, scsi_sg_count(cmnd), i) {
+ struct page *sgpage = sg_page(sg);
+ unsigned int to_off = sg->offset;
+ unsigned int sg_copy = sg->length;
+ if (sg_copy > len)
+ sg_copy = len;
+ len -= sg_copy;
+
+ while (sg_copy > 0) {
+ char *vto, *vfrom;
+ unsigned int page_copy;
+
+ if (from_off > to_off)
+ page_copy = PAGE_SIZE - from_off;
+ else
+ page_copy = PAGE_SIZE - to_off;
+ if (page_copy > sg_copy)
+ page_copy = sg_copy;
+
+ vfrom = get_data_page(data_pfn);
+ vto = get_sg_page(sgpage);
+ memcpy(vto + to_off, vfrom + from_off, page_copy);
+ put_sg_page(vto);
+ put_data_page(vfrom);
+
+ from_off += page_copy;
+ if (from_off == PAGE_SIZE) {
+ from_off = 0;
+ data_pfn++;
+ }
+ to_off += page_copy;
+ if (to_off == PAGE_SIZE) {
+ to_off = 0;
+ sgpage++;
+ }
+ sg_copy -= page_copy;
+ }
+ if (!len)
+ break;
+ }
+}
+
+static void scsi_ram_write(struct scsi_cmnd *cmnd, unsigned int startB,
+ unsigned int lenB)
+{
+ unsigned long start = startB * sector_size;
+ unsigned long len = lenB * sector_size;
+ struct scatterlist *sg;
+ unsigned i, to_off = start % PAGE_SIZE, data_pfn = start / PAGE_SIZE;
+
+ if (startB > capacity || (startB + lenB) > capacity)
+ return scsi_ram_too_big(cmnd, startB, lenB);
+
+ if (throw_away_writes)
+ return;
+
+ scsi_for_each_sg(cmnd, sg, scsi_sg_count(cmnd), i) {
+ struct page *sgpage = sg_page(sg);
+ unsigned int from_off = sg->offset;
+ unsigned int sg_copy = sg->length;
+ if (sg_copy > len)
+ sg_copy = len;
+ len -= sg_copy;
+
+ while (sg_copy > 0) {
+ char *vto, *vfrom;
+ unsigned int page_copy;
+
+ if (from_off > to_off)
+ page_copy = PAGE_SIZE - from_off;
+ else
+ page_copy = PAGE_SIZE - to_off;
+ if (page_copy > sg_copy)
+ page_copy = sg_copy;
+
+ vfrom = get_sg_page(sgpage);
+ vto = get_data_page(data_pfn);
+ memcpy(vto + to_off, vfrom + from_off, page_copy);
+ put_data_page(vto);
+ put_sg_page(vfrom);
+
+ from_off += page_copy;
+ if (from_off == PAGE_SIZE) {
+ from_off = 0;
+ sgpage++;
+ }
+ to_off += page_copy;
+ if (to_off == PAGE_SIZE) {
+ to_off = 0;
+ data_pfn++;
+ }
+ sg_copy -= page_copy;
+ }
+ if (!len)
+ break;
+ }
+}
+
+static void scsi_ram_read_6(struct scsi_cmnd *cmnd)
+{
+ unsigned int first_block = scsi_ram_get_u24(cmnd->cmnd + 1) & 0x1fffff;
+ unsigned int length = cmnd->cmnd[4];
+ if (!length)
+ length = 256;
+ scsi_ram_read(cmnd, first_block, length);
+}
+
+static void scsi_ram_read_10(struct scsi_cmnd *cmnd)
+{
+ unsigned int first_block = scsi_ram_get_u32(cmnd->cmnd + 2);
+ unsigned int length = scsi_ram_get_u16(cmnd->cmnd + 7);
+ scsi_ram_read(cmnd, first_block, length);
+}
+
+static void scsi_ram_write_6(struct scsi_cmnd *cmnd)
+{
+ unsigned int first_block = scsi_ram_get_u24(cmnd->cmnd + 1) & 0x1fffff;
+ unsigned int length = cmnd->cmnd[4];
+ if (!length)
+ length = 256;
+ scsi_ram_write(cmnd, first_block, length);
+}
+
+static void scsi_ram_write_10(struct scsi_cmnd *cmnd)
+{
+ unsigned int first_block = scsi_ram_get_u32(cmnd->cmnd + 2);
+ unsigned int length = scsi_ram_get_u16(cmnd->cmnd + 7);
+ scsi_ram_write(cmnd, first_block, length);
+}
+
+static void scsi_ram_execute_command(struct scsi_cmnd *cmnd)
+{
+#ifdef DEBUG
+ scsi_print_command(cmnd);
+#endif
+
+ switch (cmnd->cmnd[0]) {
+ case INQUIRY:
+ scsi_ram_inquiry(cmnd);
+ break;
+ case REPORT_LUNS:
+ copy_buffer(cmnd, report_luns, sizeof(report_luns));
+ break;
+ case TEST_UNIT_READY:
+ cmnd->result = 0;
+ break;
+ case READ_CAPACITY:
+ scsi_ram_read_capacity(cmnd);
+ break;
+ case MODE_SENSE:
+ scsi_ram_mode_sense(cmnd);
+ break;
+ case READ_6:
+ scsi_ram_read_6(cmnd);
+ break;
+ case READ_10:
+ scsi_ram_read_10(cmnd);
+ break;
+ case WRITE_6:
+ scsi_ram_write_6(cmnd);
+ break;
+ case WRITE_10:
+ scsi_ram_write_10(cmnd);
+ break;
+ default:
+ cmnd->result = DID_ABORT << 16;
+ }
+
+ cmnd->scsi_done(cmnd);
+}
+
+struct scsi_ram_device {
+ struct list_head commands;
+ struct Scsi_Host *host;
+ struct task_struct *thread;
+};
+
+static struct scsi_ram_device *scsi_ram_devices[16];
+
+/* Overrides scsi_pointer */
+struct scsi_ram_cmnd {
+ struct list_head queue;
+};
+
+static int scsi_ram_device_thread(void *data)
+{
+ struct scsi_ram_device *ram_device = data;
+ struct Scsi_Host *host = ram_device->host;
+
+ while (!kthread_should_stop()) {
+ struct scsi_cmnd *cmnd;
+ struct scsi_ram_cmnd *ram_cmnd;
+
+ spin_lock_irq(host->host_lock);
+ if (list_empty(&ram_device->commands)) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irq(host->host_lock);
+ schedule();
+ continue;
+ }
+
+ ram_cmnd = list_first_entry(&ram_device->commands,
+ struct scsi_ram_cmnd, queue);
+ list_del(&ram_cmnd->queue);
+ spin_unlock_irq(host->host_lock);
+
+ cmnd = container_of((struct scsi_pointer *)ram_cmnd,
+ struct scsi_cmnd, SCp);
+ scsi_ram_execute_command(cmnd);
+ }
+ __set_current_state(TASK_RUNNING);
+
+ return 0;
+}
+
+static int scsi_ram_queuecommand(struct scsi_cmnd *cmnd,
+ void (*done)(struct scsi_cmnd *))
+{
+ struct scsi_ram_cmnd *ram_cmnd = (void *)&cmnd->SCp;
+ struct scsi_ram_device *ram_device = scsi_ram_devices[cmnd->device->id];
+
+ pr_debug("%s: Queueing command\n", DRV_NAME);
+ if (!ram_device)
+ goto bad_device;
+
+ cmnd->scsi_done = done;
+ if (use_thread) {
+ if (list_empty(&ram_device->commands))
+ wake_up_process(ram_device->thread);
+ list_add_tail(&ram_cmnd->queue, &ram_device->commands);
+ } else {
+ scsi_ram_execute_command(cmnd);
+ }
+
+ return 0;
+
+ bad_device:
+ cmnd->result = DID_BAD_TARGET << 16;
+ done(cmnd);
+ return 0;
+}
+
+static int scsi_ram_slave_alloc(struct scsi_device *sdev)
+{
+ struct scsi_ram_device *ram_device;
+
+ pr_debug("%s: slave_alloc %d:%d\n", DRV_NAME, sdev->id, sdev->lun);
+
+ /* For the moment, create only device 0, lun 0 */
+ if (sdev->id != 0)
+ return 0;
+ if (sdev->lun != 0)
+ return 0;
+
+ ram_device = kmalloc(sizeof(*ram_device), GFP_KERNEL);
+ if (!ram_device)
+ goto nomem;
+ INIT_LIST_HEAD(&ram_device->commands);
+ ram_device->host = sdev->host;
+ if (scsi_ram_alloc_data())
+ goto nomem;
+ ram_device->thread = kthread_run(scsi_ram_device_thread, ram_device,
+ "scsi_ram_%d", sdev->id);
+ if (IS_ERR(ram_device->thread))
+ goto nomem;
+
+ scsi_ram_devices[sdev->id] = ram_device;
+ return 0;
+
+ nomem:
+ scsi_ram_free_data();
+ kfree(ram_device);
+ return -ENOMEM;
+}
+
+static void scsi_ram_slave_destroy(struct scsi_device *sdev)
+{
+ struct scsi_ram_device *ram_device = scsi_ram_devices[sdev->id];
+
+ pr_debug("%s: slave_destroy %d:%d\n", DRV_NAME, sdev->id, sdev->lun);
+ if (!ram_device)
+ return;
+ if (sdev->lun != 0)
+ return;
+
+ kthread_stop(ram_device->thread);
+ scsi_ram_free_data();
+ kfree(ram_device);
+ scsi_ram_devices[sdev->id] = NULL;
+}
+
+static int scsi_ram_eh_host_reset_handler(struct scsi_cmnd *scmd)
+{
+ pr_debug("%s: eh_host_reset_handler\n", DRV_NAME);
+ return 0;
+}
+
+static struct scsi_host_template scsi_ram_template = {
+ .name = DRV_NAME,
+ .proc_name = DRV_NAME,
+ .queuecommand = scsi_ram_queuecommand,
+ .eh_host_reset_handler = scsi_ram_eh_host_reset_handler,
+ .slave_alloc = scsi_ram_slave_alloc,
+ .slave_destroy = scsi_ram_slave_destroy,
+ .can_queue = 64,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .max_sectors = 1024,
+ .cmd_per_lun = 64,
+ .skip_settle_delay = 1,
+ .use_clustering = DISABLE_CLUSTERING,
+};
+
+static struct Scsi_Host *scsi_ram_host;
+
+static int __init scsi_ram_init(void)
+{
+ int error;
+
+ scsi_ram_host = scsi_host_alloc(&scsi_ram_template, 0);
+ if (!scsi_ram_host)
+ return -ENOMEM;
+
+ error = scsi_add_host(scsi_ram_host, NULL);
+ if (error)
+ goto free_host;
+
+ scsi_scan_host(scsi_ram_host);
+ return 0;
+
+ free_host:
+ scsi_host_put(scsi_ram_host);
+ return error;
+}
+
+static void __exit scsi_ram_exit(void)
+{
+ scsi_remove_host(scsi_ram_host);
+ scsi_host_put(scsi_ram_host);
+}
+
+module_init(scsi_ram_init);
+module_exit(scsi_ram_exit);
--
Intel are signing my paycheques ... these opinions are still mine
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours. We can't possibly take such
a retrograde step."
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: SCSI RAM driver
2008-02-18 6:36 SCSI RAM driver Matthew Wilcox
@ 2008-02-19 13:14 ` FUJITA Tomonori
2008-02-19 13:31 ` Matthew Wilcox
0 siblings, 1 reply; 5+ messages in thread
From: FUJITA Tomonori @ 2008-02-19 13:14 UTC (permalink / raw)
To: matthew; +Cc: linux-scsi, kristen.c.accardi, fujita.tomonori
On Sun, 17 Feb 2008 23:36:59 -0700
Matthew Wilcox <matthew@wil.cx> wrote:
>
> This is the first release of a driver we've been using internally at Intel
> for a few weeks which is as low-latency as possible. It's designed to
> let us find latency issues elsewhere in the storage stack (eg filesystem,
> block layer, scsi layer)
>
> There are a few different options, controlled through module parameters.
> The sector size and disc capacity are load-time parameters, but the
> parameters affecting performance are tweakable at runtime.
>
> Arguably, this driver should be merged into scsi_debug. I didn't want to
> trip over Doug's toes while developing this driver, and the two drivers
> do have very different objectives. scsi_debug is obviously a lot more
> fully-featured and implements lots of bits of the spec I simply haven't
> bothered with. Like MODE SENSE ;-)
I see that two drivers have very different objectives but if we add
use_thread option to scsi_debug (we can do easily), it seems that
scsi_debug can provide all the features that scsi_ram does.
If we clean up scsi_debug driver, can scsi_debug work as a nice scsi
ram driver?
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: SCSI RAM driver
2008-02-19 13:14 ` FUJITA Tomonori
@ 2008-02-19 13:31 ` Matthew Wilcox
2008-02-19 13:46 ` FUJITA Tomonori
0 siblings, 1 reply; 5+ messages in thread
From: Matthew Wilcox @ 2008-02-19 13:31 UTC (permalink / raw)
To: FUJITA Tomonori; +Cc: linux-scsi, kristen.c.accardi, fujita.tomonori, dougg
On Tue, Feb 19, 2008 at 10:14:53PM +0900, FUJITA Tomonori wrote:
> I see that two drivers have very different objectives but if we add
> use_thread option to scsi_debug (we can do easily), it seems that
> scsi_debug can provide all the features that scsi_ram does.
It's not just use_thread. It's also discard_read/discard_write.
And scsi_ram has a different data storage model from scsi_debug --
scsi_debug simulates an arbitrarily sized disc by wrapping around some
small (virtually) contiguous allocation of pages; scsi_ram actually
allocates the amount of ram that it's told to. This can be solved with
another module parameter, of course.
I'm in no way opposed to merging the two; it's a question of whether
Doug will mind me doing some surgery on his driver.
--
Intel are signing my paycheques ... these opinions are still mine
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours. We can't possibly take such
a retrograde step."
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: SCSI RAM driver
2008-02-19 13:31 ` Matthew Wilcox
@ 2008-02-19 13:46 ` FUJITA Tomonori
2008-03-02 10:59 ` FUJITA Tomonori
0 siblings, 1 reply; 5+ messages in thread
From: FUJITA Tomonori @ 2008-02-19 13:46 UTC (permalink / raw)
To: matthew; +Cc: tomof, linux-scsi, kristen.c.accardi, fujita.tomonori, dougg
On Tue, 19 Feb 2008 06:31:20 -0700
Matthew Wilcox <matthew@wil.cx> wrote:
> On Tue, Feb 19, 2008 at 10:14:53PM +0900, FUJITA Tomonori wrote:
> > I see that two drivers have very different objectives but if we add
> > use_thread option to scsi_debug (we can do easily), it seems that
> > scsi_debug can provide all the features that scsi_ram does.
>
> It's not just use_thread. It's also discard_read/discard_write.
scsi_debug has a similar option, fake_rw, which discards both read and
write data.
> And scsi_ram has a different data storage model from scsi_debug --
> scsi_debug simulates an arbitrarily sized disc by wrapping around some
> small (virtually) contiguous allocation of pages; scsi_ram actually
> allocates the amount of ram that it's told to. This can be solved with
> another module parameter, of course.
IIRC, if virtual_gb option is set to zero, scsi_debug allocates the
amount of ram that it's told to.
> I'm in no way opposed to merging the two; it's a question of whether
> Doug will mind me doing some surgery on his driver.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: SCSI RAM driver
2008-02-19 13:46 ` FUJITA Tomonori
@ 2008-03-02 10:59 ` FUJITA Tomonori
0 siblings, 0 replies; 5+ messages in thread
From: FUJITA Tomonori @ 2008-03-02 10:59 UTC (permalink / raw)
To: matthew; +Cc: linux-scsi, kristen.c.accardi, fujita.tomonori, dougg
On Tue, 19 Feb 2008 22:46:57 +0900
FUJITA Tomonori <tomof@acm.org> wrote:
> On Tue, 19 Feb 2008 06:31:20 -0700
> Matthew Wilcox <matthew@wil.cx> wrote:
>
> > On Tue, Feb 19, 2008 at 10:14:53PM +0900, FUJITA Tomonori wrote:
> > > I see that two drivers have very different objectives but if we add
> > > use_thread option to scsi_debug (we can do easily), it seems that
> > > scsi_debug can provide all the features that scsi_ram does.
> >
> > It's not just use_thread. It's also discard_read/discard_write.
>
> scsi_debug has a similar option, fake_rw, which discards both read and
> write data.
>
>
> > And scsi_ram has a different data storage model from scsi_debug --
> > scsi_debug simulates an arbitrarily sized disc by wrapping around some
> > small (virtually) contiguous allocation of pages; scsi_ram actually
> > allocates the amount of ram that it's told to. This can be solved with
> > another module parameter, of course.
>
> IIRC, if virtual_gb option is set to zero, scsi_debug allocates the
> amount of ram that it's told to.
I think that there are only two different features between scsi_debug
and scsi_ram.
The first one is the thread option, a kernel thread per device
executes scsi commands. Adding the option to scsi_debug is not so
difficult though scsi_debug could create a device in the queuecommand
path so we need some modifications to scsi_debug to drop the host_lock
in the path.
The second one is how to allocate memory for logical unit's contents.
scsi_debug uses vmalloc so there is a limit to the capacity of a that
scsi_debug can support. scsi_ram allocates multiple pages so there is
no limit in scsi_ram. However, I think that we could live without this
feature (but I'm happy to send a patch to convert scsi_debug to use
scsi_ram's way if you want).
Architectures that we might want to use scsi_ram with (e.g., x86_64),
vmalloc can allocate huge memory. The advantage of vmalloc, a
continuous memory area, makes the driver simpler a bit (and it enables
scsi_debug to use the APIs to copies data between a sglist and a
buffer, which also works well for other LLDs).
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2008-03-02 10:59 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-02-18 6:36 SCSI RAM driver Matthew Wilcox
2008-02-19 13:14 ` FUJITA Tomonori
2008-02-19 13:31 ` Matthew Wilcox
2008-02-19 13:46 ` FUJITA Tomonori
2008-03-02 10:59 ` FUJITA Tomonori
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).