From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
To: <linux-kernel@vger.kernel.org>
Cc: linuxppc-dev@ozlabs.org
Subject: [RFC/PATCH] Block device for the ISS simulator
Date: Fri, 03 Oct 2008 10:08:42 +1000 [thread overview]
Message-ID: <20081003000904.0A812DDEEE@ozlabs.org> (raw)
The ISS simulator is a simple powerpc simulator used among other things
for hardware bringup. It implements a simple memory mapped block device
interface.
This is a simple block driver that attaches to it. Note that the choice
of a major device number is fishy, though because it's a simulator and
not real hardware, it's not necessarily a big deal.
Comments welcome,
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
(And yes, I will try to get ISS to implement an IDE emulation instead
but that's not what's there at this stage)
arch/powerpc/boot/dts/iss4xx.dts | 5
drivers/block/Kconfig | 4
drivers/block/Makefile | 1
drivers/block/iss_blk.c | 365 +++++++++++++++++++++++++++++++++++++++
4 files changed, 375 insertions(+)
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-work/drivers/block/iss_blk.c 2008-09-23 11:12:03.000000000 +1000
@@ -0,0 +1,365 @@
+/*
+ * Simple block device for the ISS simulator
+ */
+
+#undef DEBUG
+
+#include <linux/major.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/ioctl.h>
+#include <linux/blkdev.h>
+#include <linux/of.h>
+
+#include <asm/io.h>
+
+#define MAJOR_NR 63 /* FIXME */
+#define NUM_ISS_BLK_MINOR 4
+
+/* Command codes */
+enum {
+ ISS_BD_CMD_NOP = 0,
+ ISS_BD_CMD_OPEN = 1,
+ ISS_BD_CMD_CLOSE = 2,
+ ISS_BD_CMD_READ = 3,
+ ISS_BD_CMD_WRITE = 4,
+ ISS_BD_CMD_STATUS = 5,
+ ISS_BD_CMD_CHKCHANGE = 6,
+ ISS_BD_CMD_SYNC = 7,
+ ISS_BD_CMD_GET_BLKSIZE = 8,
+ ISS_BD_CMD_GET_DEVSIZE = 9,
+};
+
+/* Status codes */
+enum {
+ ISS_BD_STATUS_OK = 0,
+ ISS_BD_STATUS_OP_ER = 1, /* Open error */
+ ISS_BD_ALREADY_OPEN = 2, /* Block file already open */
+ ISS_BD_NOT_OPEN = 3, /* Block file not open */
+ ISS_BD_BAD_DEV_NUM = 4, /* Bad device number */
+ ISS_BD_BAD_SEC_CNT = 5, /* Bad sector number */
+ ISS_BD_SEEK_ERROR = 6, /* Bad sector count */
+ ISS_BD_RW_ERROR = 7, /* Read/Write error */
+ ISS_BD_SIZE_ERROR = 8, /* Unable to determine file size */
+};
+
+struct iss_blk_regs {
+ u8 cmd;
+ u8 pad0[3];
+ u32 stat;
+ u32 sector;
+ u32 count;
+ u32 devno;
+ u32 size;
+ u8 pad1[0x1e8];
+ u8 data[0x800];
+};
+
+struct iss_blk {
+ struct gendisk *disk;
+ unsigned int devno;
+ unsigned int sectsize;
+ unsigned int capacity;
+ unsigned int present;
+ unsigned int changed;
+} iss_blks[NUM_ISS_BLK_MINOR];
+
+static spinlock_t iss_blk_qlock;
+static spinlock_t iss_blk_reglock;
+static struct iss_blk_regs __iomem *iss_blk_regs;
+
+static void iss_blk_setup(struct iss_blk *ib)
+{
+ unsigned long flags;
+ u32 stat;
+
+ pr_debug("iss_blk_setup %d\n", ib->devno);
+
+ spin_lock_irqsave(&iss_blk_reglock, flags);
+ out_8(iss_blk_regs->data, 0);
+ out_be32(&iss_blk_regs->devno, ib->devno);
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_OPEN);
+ stat = in_be32(&iss_blk_regs->stat);
+ if (stat != ISS_BD_STATUS_OK) {
+ pr_debug(" -> no file\n");
+ goto failed;
+ }
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_GET_BLKSIZE);
+ ib->sectsize = in_be32(&iss_blk_regs->size);
+ if (ib->sectsize != 512) {
+ pr_err("issblk: unsupported sector size %d\n", ib->sectsize);
+ goto failed;
+ }
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_GET_DEVSIZE);
+ ib->capacity = in_be32(&iss_blk_regs->size);
+ ib->present = 1;
+ ib->changed = 0;
+ spin_unlock_irqrestore(&iss_blk_reglock, flags);
+
+ pr_debug(" -> 0x%x sectors 0f %d bytes\n",
+ ib->capacity, ib->sectsize);
+
+ blk_queue_bounce_limit(ib->disk->queue, BLK_BOUNCE_HIGH);
+ blk_queue_hardsect_size(ib->disk->queue, ib->sectsize);
+ set_capacity(ib->disk, ib->capacity);
+ return;
+
+ failed:
+ spin_unlock_irqrestore(&iss_blk_reglock, flags);
+}
+
+static int __iss_blk_read(struct iss_blk *ib, void *buffer,
+ unsigned long sector, unsigned long count)
+{
+ unsigned long lcount, flags;
+ u32 stat;
+
+ pr_debug("__iss_blk_read 0x%ld sectors @ 0x%lx\n", count, sector);
+
+ while(count) {
+ lcount = min(count, 4ul);
+ spin_lock_irqsave(&iss_blk_reglock, flags);
+ out_be32(&iss_blk_regs->devno, ib->devno);
+ out_be32(&iss_blk_regs->sector, sector);
+ out_be32(&iss_blk_regs->count, lcount);
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_READ);
+ stat = in_be32(&iss_blk_regs->stat);
+ if (stat != ISS_BD_STATUS_OK) {
+ spin_unlock_irqrestore(&iss_blk_reglock, flags);
+ return -EIO;
+ }
+ memcpy_fromio(buffer, &iss_blk_regs->data, lcount * ib->sectsize);
+ spin_unlock_irqrestore(&iss_blk_reglock, flags);
+ count -= lcount;
+ sector += lcount;
+ buffer += lcount * ib->sectsize;
+ }
+ return 0;
+}
+
+static int __iss_blk_write(struct iss_blk *ib, void *buffer,
+ unsigned long sector, unsigned long count)
+{
+ unsigned long lcount, flags;
+ u32 stat;
+
+ pr_debug("__iss_blk_write 0x%ld sectors @ 0x%lx\n", count, sector);
+
+ while(count) {
+ lcount = min(count, 4ul);
+ spin_lock_irqsave(&iss_blk_reglock, flags);
+ out_be32(&iss_blk_regs->devno, ib->devno);
+ out_be32(&iss_blk_regs->sector, sector);
+ out_be32(&iss_blk_regs->count, lcount);
+ memcpy_toio(&iss_blk_regs->data, buffer, lcount * ib->sectsize);
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_WRITE);
+ stat = in_be32(&iss_blk_regs->stat);
+ spin_unlock_irqrestore(&iss_blk_reglock, flags);
+ if (stat != ISS_BD_STATUS_OK)
+ return -EIO;
+ count -= lcount;
+ sector += lcount;
+ buffer += lcount * ib->sectsize;
+ }
+ return 0;
+}
+
+static void iss_blk_do_request(struct request_queue * q)
+{
+ struct iss_blk *ib = q->queuedata;
+ struct request *req;
+ int rc = 0;
+
+ pr_debug("iss_do_request dev %d\n", ib->devno);
+
+ while ((req = elv_next_request(q)) != NULL) {
+ pr_debug(" -> req @ %p, changed: %d\n", req, ib->changed);
+ if (ib->changed) {
+ end_request(req, 0); /* failure */
+ continue;
+ }
+ switch (rq_data_dir(req)) {
+ case READ:
+ rc = __iss_blk_read(ib, req->buffer, req->sector,
+ req->current_nr_sectors);
+ break;
+ case WRITE:
+ rc = __iss_blk_write(ib, req->buffer, req->sector,
+ req->current_nr_sectors);
+ };
+
+ pr_debug(" -> ending request, rc = %d\n", rc);
+ if (rc)
+ end_request(req, 0); /* failure */
+ else
+ end_request(req, 1); /* success */
+ }
+}
+
+static int iss_blk_release(struct inode *inode, struct file *file)
+{
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct iss_blk *ib = disk->private_data;
+ unsigned long flags;
+
+ pr_debug("issblk%d: release !\n", disk->first_minor);
+
+ spin_lock_irqsave(&iss_blk_reglock, flags);
+ out_be32(&iss_blk_regs->devno, ib->devno);
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_SYNC);
+ spin_unlock_irqrestore(&iss_blk_reglock, flags);
+
+ return 0;
+}
+
+static int iss_blk_revalidate(struct gendisk *disk)
+{
+ struct iss_blk *ib = disk->private_data;
+ unsigned long flags;
+
+ pr_debug("issblk%d: revalidate !\n", disk->first_minor);
+
+ if (ib->present && ib->changed) {
+ spin_lock_irqsave(&iss_blk_reglock, flags);
+ out_be32(&iss_blk_regs->devno, ib->devno);
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_CLOSE);
+ ib->present = ib->changed = 0;
+ spin_unlock_irqrestore(&iss_blk_reglock, flags);
+ }
+ iss_blk_setup(ib);
+ return 0;
+}
+
+static int iss_blk_media_changed(struct gendisk *disk)
+{
+ struct iss_blk *ib = disk->private_data;
+
+ pr_debug("issblk%d: media_changed !\n", disk->first_minor);
+
+ /* Not implemented -> query change status from ISS */
+
+ return ib->changed;
+}
+
+static int iss_blk_open(struct inode *inode, struct file *file)
+{
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct iss_blk *ib = disk->private_data;
+
+ pr_debug("issblk%d: open !\n", disk->first_minor);
+
+ check_disk_change(inode->i_bdev);
+ if (ib->changed)
+ iss_blk_setup(ib);
+ if (!ib->present)
+ return -ENOMEDIUM;
+ return 0;
+}
+
+static struct block_device_operations iss_blk_fops = {
+ .owner = THIS_MODULE,
+ .open = iss_blk_open,
+ .release = iss_blk_release,
+ .media_changed = iss_blk_media_changed,
+ .revalidate_disk = iss_blk_revalidate,
+};
+
+static int __init iss_blk_init(void)
+{
+ struct device_node *np;
+ int i;
+
+ pr_debug("iss_regs offsets:\n");
+ pr_debug(" cmd : 0x%x\n", offsetof(struct iss_blk_regs, cmd));
+ pr_debug(" stat : 0x%x\n", offsetof(struct iss_blk_regs, stat));
+ pr_debug(" sector : 0x%x\n", offsetof(struct iss_blk_regs, sector));
+ pr_debug(" count : 0x%x\n", offsetof(struct iss_blk_regs, count));
+ pr_debug(" devno : 0x%x\n", offsetof(struct iss_blk_regs, devno));
+ pr_debug(" size : 0x%x\n", offsetof(struct iss_blk_regs, size));
+ pr_debug(" data : 0x%x\n", offsetof(struct iss_blk_regs, data));
+
+ np = of_find_node_by_path("/iss-block");
+ if (np == NULL)
+ return -ENODEV;
+ iss_blk_regs = of_iomap(np, 0);
+ if (iss_blk_regs == NULL) {
+ pr_err("issblk: Failed to map registers\n");
+ return -ENOMEM;
+ }
+
+ if (register_blkdev(MAJOR_NR, "iss_blk"))
+ return -EIO;
+
+ spin_lock_init(&iss_blk_qlock);
+ spin_lock_init(&iss_blk_reglock);
+
+ printk(KERN_INFO "ISS Block driver initializing for %d minors\n",
+ NUM_ISS_BLK_MINOR);
+
+ for (i = 0; i < NUM_ISS_BLK_MINOR; i++) {
+ struct gendisk *disk = alloc_disk(1);
+ struct request_queue *q;
+ struct iss_blk *ib = &iss_blks[i];
+
+ if (!disk) {
+ pr_err("issblk%d: Failed to allocate disk\n", i);
+ break;
+ }
+
+ q = blk_init_queue(iss_blk_do_request, &iss_blk_qlock);
+ if (q == NULL) {
+ pr_err("issblk%d: Failed to init queue\n", i);
+ put_disk(disk);
+ break;
+ }
+ q->queuedata = ib;
+
+ ib->disk = disk;
+ ib->devno = i;
+ ib->present = 0;
+ ib->changed = 0;
+ ib->capacity = 0;
+ ib->sectsize = 512;
+
+ disk->major = MAJOR_NR;
+ disk->first_minor = i;
+ disk->fops = &iss_blk_fops;
+ disk->private_data = &iss_blks[i];
+ disk->flags = GENHD_FL_REMOVABLE;
+ disk->queue = q;
+ sprintf(disk->disk_name, "issblk%d", i);
+
+ iss_blk_setup(ib);
+
+ add_disk(disk);
+ }
+
+ return 0;
+}
+
+static void __exit iss_blk_exit(void)
+{
+ int i;
+
+ unregister_blkdev(MAJOR_NR, "iss_blk");
+
+ for (i = 0; i < NUM_ISS_BLK_MINOR; i++) {
+ struct iss_blk *ib = &iss_blks[i];
+
+ if (ib->present) {
+ out_be32(&iss_blk_regs->devno, ib->devno);
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_CLOSE);
+ }
+ }
+}
+
+module_init(iss_blk_init);
+module_exit(iss_blk_exit);
+
+MODULE_DESCRIPTION("ISS Simulator Block Device");
+MODULE_LICENSE("GPL");
Index: linux-work/drivers/block/Kconfig
===================================================================
--- linux-work.orig/drivers/block/Kconfig 2008-07-17 14:43:58.000000000 +1000
+++ linux-work/drivers/block/Kconfig 2008-09-23 11:12:03.000000000 +1000
@@ -357,6 +357,10 @@ config BLK_DEV_XIP
will prevent RAM block device backing store memory from being
allocated from highmem (only a problem for highmem systems).
+config BLK_DEV_ISS
+ bool "Support ISS Simulator Block Device"
+ default n
+
config CDROM_PKTCDVD
tristate "Packet writing on CD/DVD media"
depends on !UML
Index: linux-work/drivers/block/Makefile
===================================================================
--- linux-work.orig/drivers/block/Makefile 2008-07-17 14:43:58.000000000 +1000
+++ linux-work/drivers/block/Makefile 2008-09-23 11:12:03.000000000 +1000
@@ -30,5 +30,6 @@ obj-$(CONFIG_VIODASD) += viodasd.o
obj-$(CONFIG_BLK_DEV_SX8) += sx8.o
obj-$(CONFIG_BLK_DEV_UB) += ub.o
obj-$(CONFIG_BLK_DEV_HD) += hd.o
+obj-$(CONFIG_BLK_DEV_ISS) += iss_blk.o
obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o
Index: linux-work/arch/powerpc/boot/dts/iss4xx.dts
===================================================================
--- linux-work.orig/arch/powerpc/boot/dts/iss4xx.dts 2008-09-23 11:12:02.000000000 +1000
+++ linux-work/arch/powerpc/boot/dts/iss4xx.dts 2008-09-23 11:12:03.000000000 +1000
@@ -101,6 +101,11 @@
};
};
+ iss-block {
+ compatible = "ibm,iss-sim-block-device";
+ reg = <0 0xEF701000 0x1000>;
+ };
+
chosen {
linux,stdout-path = "/plb/opb/serial@40000200";
};
WARNING: multiple messages have this Message-ID (diff)
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
To: <linux-kernel@vger.kernel.org>
Cc: <linuxppc-dev@ozlabs.org>, Josh Boyer <jwboyer@linux.vnet.ibm.com>
Subject: [RFC/PATCH] Block device for the ISS simulator
Date: Fri, 03 Oct 2008 10:08:42 +1000 [thread overview]
Message-ID: <20081003000904.0A812DDEEE@ozlabs.org> (raw)
The ISS simulator is a simple powerpc simulator used among other things
for hardware bringup. It implements a simple memory mapped block device
interface.
This is a simple block driver that attaches to it. Note that the choice
of a major device number is fishy, though because it's a simulator and
not real hardware, it's not necessarily a big deal.
Comments welcome,
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
(And yes, I will try to get ISS to implement an IDE emulation instead
but that's not what's there at this stage)
arch/powerpc/boot/dts/iss4xx.dts | 5
drivers/block/Kconfig | 4
drivers/block/Makefile | 1
drivers/block/iss_blk.c | 365 +++++++++++++++++++++++++++++++++++++++
4 files changed, 375 insertions(+)
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-work/drivers/block/iss_blk.c 2008-09-23 11:12:03.000000000 +1000
@@ -0,0 +1,365 @@
+/*
+ * Simple block device for the ISS simulator
+ */
+
+#undef DEBUG
+
+#include <linux/major.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/ioctl.h>
+#include <linux/blkdev.h>
+#include <linux/of.h>
+
+#include <asm/io.h>
+
+#define MAJOR_NR 63 /* FIXME */
+#define NUM_ISS_BLK_MINOR 4
+
+/* Command codes */
+enum {
+ ISS_BD_CMD_NOP = 0,
+ ISS_BD_CMD_OPEN = 1,
+ ISS_BD_CMD_CLOSE = 2,
+ ISS_BD_CMD_READ = 3,
+ ISS_BD_CMD_WRITE = 4,
+ ISS_BD_CMD_STATUS = 5,
+ ISS_BD_CMD_CHKCHANGE = 6,
+ ISS_BD_CMD_SYNC = 7,
+ ISS_BD_CMD_GET_BLKSIZE = 8,
+ ISS_BD_CMD_GET_DEVSIZE = 9,
+};
+
+/* Status codes */
+enum {
+ ISS_BD_STATUS_OK = 0,
+ ISS_BD_STATUS_OP_ER = 1, /* Open error */
+ ISS_BD_ALREADY_OPEN = 2, /* Block file already open */
+ ISS_BD_NOT_OPEN = 3, /* Block file not open */
+ ISS_BD_BAD_DEV_NUM = 4, /* Bad device number */
+ ISS_BD_BAD_SEC_CNT = 5, /* Bad sector number */
+ ISS_BD_SEEK_ERROR = 6, /* Bad sector count */
+ ISS_BD_RW_ERROR = 7, /* Read/Write error */
+ ISS_BD_SIZE_ERROR = 8, /* Unable to determine file size */
+};
+
+struct iss_blk_regs {
+ u8 cmd;
+ u8 pad0[3];
+ u32 stat;
+ u32 sector;
+ u32 count;
+ u32 devno;
+ u32 size;
+ u8 pad1[0x1e8];
+ u8 data[0x800];
+};
+
+struct iss_blk {
+ struct gendisk *disk;
+ unsigned int devno;
+ unsigned int sectsize;
+ unsigned int capacity;
+ unsigned int present;
+ unsigned int changed;
+} iss_blks[NUM_ISS_BLK_MINOR];
+
+static spinlock_t iss_blk_qlock;
+static spinlock_t iss_blk_reglock;
+static struct iss_blk_regs __iomem *iss_blk_regs;
+
+static void iss_blk_setup(struct iss_blk *ib)
+{
+ unsigned long flags;
+ u32 stat;
+
+ pr_debug("iss_blk_setup %d\n", ib->devno);
+
+ spin_lock_irqsave(&iss_blk_reglock, flags);
+ out_8(iss_blk_regs->data, 0);
+ out_be32(&iss_blk_regs->devno, ib->devno);
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_OPEN);
+ stat = in_be32(&iss_blk_regs->stat);
+ if (stat != ISS_BD_STATUS_OK) {
+ pr_debug(" -> no file\n");
+ goto failed;
+ }
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_GET_BLKSIZE);
+ ib->sectsize = in_be32(&iss_blk_regs->size);
+ if (ib->sectsize != 512) {
+ pr_err("issblk: unsupported sector size %d\n", ib->sectsize);
+ goto failed;
+ }
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_GET_DEVSIZE);
+ ib->capacity = in_be32(&iss_blk_regs->size);
+ ib->present = 1;
+ ib->changed = 0;
+ spin_unlock_irqrestore(&iss_blk_reglock, flags);
+
+ pr_debug(" -> 0x%x sectors 0f %d bytes\n",
+ ib->capacity, ib->sectsize);
+
+ blk_queue_bounce_limit(ib->disk->queue, BLK_BOUNCE_HIGH);
+ blk_queue_hardsect_size(ib->disk->queue, ib->sectsize);
+ set_capacity(ib->disk, ib->capacity);
+ return;
+
+ failed:
+ spin_unlock_irqrestore(&iss_blk_reglock, flags);
+}
+
+static int __iss_blk_read(struct iss_blk *ib, void *buffer,
+ unsigned long sector, unsigned long count)
+{
+ unsigned long lcount, flags;
+ u32 stat;
+
+ pr_debug("__iss_blk_read 0x%ld sectors @ 0x%lx\n", count, sector);
+
+ while(count) {
+ lcount = min(count, 4ul);
+ spin_lock_irqsave(&iss_blk_reglock, flags);
+ out_be32(&iss_blk_regs->devno, ib->devno);
+ out_be32(&iss_blk_regs->sector, sector);
+ out_be32(&iss_blk_regs->count, lcount);
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_READ);
+ stat = in_be32(&iss_blk_regs->stat);
+ if (stat != ISS_BD_STATUS_OK) {
+ spin_unlock_irqrestore(&iss_blk_reglock, flags);
+ return -EIO;
+ }
+ memcpy_fromio(buffer, &iss_blk_regs->data, lcount * ib->sectsize);
+ spin_unlock_irqrestore(&iss_blk_reglock, flags);
+ count -= lcount;
+ sector += lcount;
+ buffer += lcount * ib->sectsize;
+ }
+ return 0;
+}
+
+static int __iss_blk_write(struct iss_blk *ib, void *buffer,
+ unsigned long sector, unsigned long count)
+{
+ unsigned long lcount, flags;
+ u32 stat;
+
+ pr_debug("__iss_blk_write 0x%ld sectors @ 0x%lx\n", count, sector);
+
+ while(count) {
+ lcount = min(count, 4ul);
+ spin_lock_irqsave(&iss_blk_reglock, flags);
+ out_be32(&iss_blk_regs->devno, ib->devno);
+ out_be32(&iss_blk_regs->sector, sector);
+ out_be32(&iss_blk_regs->count, lcount);
+ memcpy_toio(&iss_blk_regs->data, buffer, lcount * ib->sectsize);
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_WRITE);
+ stat = in_be32(&iss_blk_regs->stat);
+ spin_unlock_irqrestore(&iss_blk_reglock, flags);
+ if (stat != ISS_BD_STATUS_OK)
+ return -EIO;
+ count -= lcount;
+ sector += lcount;
+ buffer += lcount * ib->sectsize;
+ }
+ return 0;
+}
+
+static void iss_blk_do_request(struct request_queue * q)
+{
+ struct iss_blk *ib = q->queuedata;
+ struct request *req;
+ int rc = 0;
+
+ pr_debug("iss_do_request dev %d\n", ib->devno);
+
+ while ((req = elv_next_request(q)) != NULL) {
+ pr_debug(" -> req @ %p, changed: %d\n", req, ib->changed);
+ if (ib->changed) {
+ end_request(req, 0); /* failure */
+ continue;
+ }
+ switch (rq_data_dir(req)) {
+ case READ:
+ rc = __iss_blk_read(ib, req->buffer, req->sector,
+ req->current_nr_sectors);
+ break;
+ case WRITE:
+ rc = __iss_blk_write(ib, req->buffer, req->sector,
+ req->current_nr_sectors);
+ };
+
+ pr_debug(" -> ending request, rc = %d\n", rc);
+ if (rc)
+ end_request(req, 0); /* failure */
+ else
+ end_request(req, 1); /* success */
+ }
+}
+
+static int iss_blk_release(struct inode *inode, struct file *file)
+{
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct iss_blk *ib = disk->private_data;
+ unsigned long flags;
+
+ pr_debug("issblk%d: release !\n", disk->first_minor);
+
+ spin_lock_irqsave(&iss_blk_reglock, flags);
+ out_be32(&iss_blk_regs->devno, ib->devno);
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_SYNC);
+ spin_unlock_irqrestore(&iss_blk_reglock, flags);
+
+ return 0;
+}
+
+static int iss_blk_revalidate(struct gendisk *disk)
+{
+ struct iss_blk *ib = disk->private_data;
+ unsigned long flags;
+
+ pr_debug("issblk%d: revalidate !\n", disk->first_minor);
+
+ if (ib->present && ib->changed) {
+ spin_lock_irqsave(&iss_blk_reglock, flags);
+ out_be32(&iss_blk_regs->devno, ib->devno);
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_CLOSE);
+ ib->present = ib->changed = 0;
+ spin_unlock_irqrestore(&iss_blk_reglock, flags);
+ }
+ iss_blk_setup(ib);
+ return 0;
+}
+
+static int iss_blk_media_changed(struct gendisk *disk)
+{
+ struct iss_blk *ib = disk->private_data;
+
+ pr_debug("issblk%d: media_changed !\n", disk->first_minor);
+
+ /* Not implemented -> query change status from ISS */
+
+ return ib->changed;
+}
+
+static int iss_blk_open(struct inode *inode, struct file *file)
+{
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct iss_blk *ib = disk->private_data;
+
+ pr_debug("issblk%d: open !\n", disk->first_minor);
+
+ check_disk_change(inode->i_bdev);
+ if (ib->changed)
+ iss_blk_setup(ib);
+ if (!ib->present)
+ return -ENOMEDIUM;
+ return 0;
+}
+
+static struct block_device_operations iss_blk_fops = {
+ .owner = THIS_MODULE,
+ .open = iss_blk_open,
+ .release = iss_blk_release,
+ .media_changed = iss_blk_media_changed,
+ .revalidate_disk = iss_blk_revalidate,
+};
+
+static int __init iss_blk_init(void)
+{
+ struct device_node *np;
+ int i;
+
+ pr_debug("iss_regs offsets:\n");
+ pr_debug(" cmd : 0x%x\n", offsetof(struct iss_blk_regs, cmd));
+ pr_debug(" stat : 0x%x\n", offsetof(struct iss_blk_regs, stat));
+ pr_debug(" sector : 0x%x\n", offsetof(struct iss_blk_regs, sector));
+ pr_debug(" count : 0x%x\n", offsetof(struct iss_blk_regs, count));
+ pr_debug(" devno : 0x%x\n", offsetof(struct iss_blk_regs, devno));
+ pr_debug(" size : 0x%x\n", offsetof(struct iss_blk_regs, size));
+ pr_debug(" data : 0x%x\n", offsetof(struct iss_blk_regs, data));
+
+ np = of_find_node_by_path("/iss-block");
+ if (np == NULL)
+ return -ENODEV;
+ iss_blk_regs = of_iomap(np, 0);
+ if (iss_blk_regs == NULL) {
+ pr_err("issblk: Failed to map registers\n");
+ return -ENOMEM;
+ }
+
+ if (register_blkdev(MAJOR_NR, "iss_blk"))
+ return -EIO;
+
+ spin_lock_init(&iss_blk_qlock);
+ spin_lock_init(&iss_blk_reglock);
+
+ printk(KERN_INFO "ISS Block driver initializing for %d minors\n",
+ NUM_ISS_BLK_MINOR);
+
+ for (i = 0; i < NUM_ISS_BLK_MINOR; i++) {
+ struct gendisk *disk = alloc_disk(1);
+ struct request_queue *q;
+ struct iss_blk *ib = &iss_blks[i];
+
+ if (!disk) {
+ pr_err("issblk%d: Failed to allocate disk\n", i);
+ break;
+ }
+
+ q = blk_init_queue(iss_blk_do_request, &iss_blk_qlock);
+ if (q == NULL) {
+ pr_err("issblk%d: Failed to init queue\n", i);
+ put_disk(disk);
+ break;
+ }
+ q->queuedata = ib;
+
+ ib->disk = disk;
+ ib->devno = i;
+ ib->present = 0;
+ ib->changed = 0;
+ ib->capacity = 0;
+ ib->sectsize = 512;
+
+ disk->major = MAJOR_NR;
+ disk->first_minor = i;
+ disk->fops = &iss_blk_fops;
+ disk->private_data = &iss_blks[i];
+ disk->flags = GENHD_FL_REMOVABLE;
+ disk->queue = q;
+ sprintf(disk->disk_name, "issblk%d", i);
+
+ iss_blk_setup(ib);
+
+ add_disk(disk);
+ }
+
+ return 0;
+}
+
+static void __exit iss_blk_exit(void)
+{
+ int i;
+
+ unregister_blkdev(MAJOR_NR, "iss_blk");
+
+ for (i = 0; i < NUM_ISS_BLK_MINOR; i++) {
+ struct iss_blk *ib = &iss_blks[i];
+
+ if (ib->present) {
+ out_be32(&iss_blk_regs->devno, ib->devno);
+ out_8(&iss_blk_regs->cmd, ISS_BD_CMD_CLOSE);
+ }
+ }
+}
+
+module_init(iss_blk_init);
+module_exit(iss_blk_exit);
+
+MODULE_DESCRIPTION("ISS Simulator Block Device");
+MODULE_LICENSE("GPL");
Index: linux-work/drivers/block/Kconfig
===================================================================
--- linux-work.orig/drivers/block/Kconfig 2008-07-17 14:43:58.000000000 +1000
+++ linux-work/drivers/block/Kconfig 2008-09-23 11:12:03.000000000 +1000
@@ -357,6 +357,10 @@ config BLK_DEV_XIP
will prevent RAM block device backing store memory from being
allocated from highmem (only a problem for highmem systems).
+config BLK_DEV_ISS
+ bool "Support ISS Simulator Block Device"
+ default n
+
config CDROM_PKTCDVD
tristate "Packet writing on CD/DVD media"
depends on !UML
Index: linux-work/drivers/block/Makefile
===================================================================
--- linux-work.orig/drivers/block/Makefile 2008-07-17 14:43:58.000000000 +1000
+++ linux-work/drivers/block/Makefile 2008-09-23 11:12:03.000000000 +1000
@@ -30,5 +30,6 @@ obj-$(CONFIG_VIODASD) += viodasd.o
obj-$(CONFIG_BLK_DEV_SX8) += sx8.o
obj-$(CONFIG_BLK_DEV_UB) += ub.o
obj-$(CONFIG_BLK_DEV_HD) += hd.o
+obj-$(CONFIG_BLK_DEV_ISS) += iss_blk.o
obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o
Index: linux-work/arch/powerpc/boot/dts/iss4xx.dts
===================================================================
--- linux-work.orig/arch/powerpc/boot/dts/iss4xx.dts 2008-09-23 11:12:02.000000000 +1000
+++ linux-work/arch/powerpc/boot/dts/iss4xx.dts 2008-09-23 11:12:03.000000000 +1000
@@ -101,6 +101,11 @@
};
};
+ iss-block {
+ compatible = "ibm,iss-sim-block-device";
+ reg = <0 0xEF701000 0x1000>;
+ };
+
chosen {
linux,stdout-path = "/plb/opb/serial@40000200";
};
next reply other threads:[~2008-10-03 0:08 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-10-03 0:08 Benjamin Herrenschmidt [this message]
2008-10-03 0:08 ` [RFC/PATCH] Block device for the ISS simulator Benjamin Herrenschmidt
2008-10-03 4:44 ` Andi Kleen
2008-10-03 4:44 ` Andi Kleen
2008-10-03 8:35 ` Christoph Hellwig
2008-10-03 8:35 ` Christoph Hellwig
2008-10-03 9:29 ` Benjamin Herrenschmidt
2008-10-03 9:29 ` Benjamin Herrenschmidt
2008-10-03 12:03 ` Josh Boyer
2008-10-03 12:03 ` Josh Boyer
2008-10-03 12:21 ` Benjamin Herrenschmidt
2008-10-03 12:21 ` Benjamin Herrenschmidt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20081003000904.0A812DDEEE@ozlabs.org \
--to=benh@kernel.crashing.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linuxppc-dev@ozlabs.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.