aboutsummaryrefslogtreecommitdiffstats
path: root/xenolinux-2.4.16-sparse/arch
diff options
context:
space:
mode:
authorsmh22@boulderdash.cl.cam.ac.uk <smh22@boulderdash.cl.cam.ac.uk>2003-02-12 18:04:40 +0000
committersmh22@boulderdash.cl.cam.ac.uk <smh22@boulderdash.cl.cam.ac.uk>2003-02-12 18:04:40 +0000
commit5af0f070284de2dd5aa59158f5f5ebd760d899ec (patch)
treeeccce4b0f100a8fb0c5cfc8ac40037c846b588a7 /xenolinux-2.4.16-sparse/arch
parent24116e31a5a2ed3b1dc989c9f9c841f1fc9161d6 (diff)
downloadxen-5af0f070284de2dd5aa59158f5f5ebd760d899ec.tar.gz
xen-5af0f070284de2dd5aa59158f5f5ebd760d899ec.tar.bz2
xen-5af0f070284de2dd5aa59158f5f5ebd760d899ec.zip
bitkeeper revision 1.22.4.1 (3e4a8cb8Aw-XeXojqgYl10tZjNiQyA)
Initial 'debugging' support (aka keyboard and serial rx int handlers :-) Also current state of Alex's IDE stuff (not yet completely working). You need to config this up to use it.
Diffstat (limited to 'xenolinux-2.4.16-sparse/arch')
-rw-r--r--xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c827
-rw-r--r--xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block_test.c233
-rw-r--r--xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c27
3 files changed, 1087 insertions, 0 deletions
diff --git a/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c b/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c
new file mode 100644
index 0000000000..0416b467a7
--- /dev/null
+++ b/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c
@@ -0,0 +1,827 @@
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <linux/fs.h>
+#include <linux/hdreg.h> /* HDIO_GETGEO, et al */
+#include <linux/blkdev.h>
+#include <linux/major.h>
+
+/* NOTE: this is drive independent, so no inclusion of ide.h */
+
+#include <asm/hypervisor-ifs/block.h>
+#include <asm/hypervisor-ifs/hypervisor-if.h>
+#include <asm/io.h>
+#include <asm/uaccess.h> /* put_user() */
+
+#define MAJOR_NR XLBLK_MAJOR /* force defns in blk.h, must preceed include */
+static int xlblk_major = XLBLK_MAJOR;
+
+#include <linux/blk.h> /* must come after definition of MAJOR_NR!! */
+
+/* instead of including linux/ide.h to pick up the definitiong of byte
+ * (and consequently screwing up blk.h, we'll just copy the definition */
+typedef unsigned char byte;
+
+void xlblk_ide_register_disk(int, unsigned long);
+
+#define XLBLK_MAX 2 /* very arbitrary */
+#define XLBLK_MAJOR_NAME "blk"
+#define IDE_PARTN_BITS 6 /* from ide.h::PARTN_BITS */
+#define IDE_PARTN_MASK ((1<<IDE_PARTN_BITS)-1) /* from ide.h::PARTN_MASK */
+static int xlblk_blk_size[XLBLK_MAX];
+static int xlblk_blksize_size[XLBLK_MAX];
+static int xlblk_hardsect_size[XLBLK_MAX];
+static int xlblk_read_ahead[XLBLK_MAX];
+static int xlblk_max_sectors[XLBLK_MAX];
+
+#define XLBLK_RX_IRQ _EVENT_BLK_RX
+#define XLBLK_TX_IRQ _EVENT_BLK_TX
+
+typedef struct xlblk_device
+{
+ struct buffer_head *bh;
+ unsigned int tx_count; /* number of used slots in tx ring */
+} xlblk_device_t;
+
+xlblk_device_t xlblk_device;
+
+/* USE_REQUEST_QUEUE = 1 use (multiple) request queues
+ * = 0 don't use IO request queue
+ */
+#define USE_REQUEST_QUEUE 1
+
+#define XLBLK_DEBUG 0
+#define XLBLK_DEBUG_IOCTL 0
+
+/*
+ * disk management
+ */
+
+xen_disk_info_t xen_disk_info;
+
+/* some declarations */
+void hypervisor_request(void * id,
+ int operation,
+ char * buffer,
+ unsigned long block_number,
+ unsigned short block_size,
+ kdev_t device,
+ int mode);
+
+
+/* ------------------------------------------------------------------------
+ */
+
+static int xenolinux_block_open(struct inode *inode, struct file *filep)
+{
+ if (XLBLK_DEBUG) {
+ printk (KERN_ALERT "xenolinux_block_open\n"); }
+ return 0;
+}
+
+static int xenolinux_block_release(struct inode *inode, struct file *filep)
+{
+ if (XLBLK_DEBUG) {
+ printk (KERN_ALERT "xenolinux_block_release\n"); }
+ return 0;
+}
+
+static int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
+ unsigned command, unsigned long argument)
+{
+ int minor_dev;
+
+ if (XLBLK_DEBUG_IOCTL)
+ {
+ printk (KERN_ALERT "xenolinux_block_ioctl\n");
+ }
+
+ /* check permissions */
+ if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+ if (!inode) return -EINVAL;
+ minor_dev = MINOR(inode->i_rdev);
+ if (minor_dev >= XLBLK_MAX) return -ENODEV;
+
+ if (XLBLK_DEBUG_IOCTL)
+ {
+ printk (KERN_ALERT
+ " command: 0x%x, argument: 0x%lx, minor: 0x%x\n",
+ command, (long) argument, minor_dev);
+ }
+
+ switch (command)
+ {
+ case BLKGETSIZE :
+ {
+ if (XLBLK_DEBUG_IOCTL)
+ {
+ printk (KERN_ALERT
+ " BLKGETSIZE: %x %lx\n", BLKGETSIZE,
+ (long) xen_disk_info.disks[0].capacity);
+ }
+ return put_user(xen_disk_info.disks[0].capacity,
+ (unsigned long *) argument);
+ }
+ case BLKRRPART :
+ {
+ if (XLBLK_DEBUG_IOCTL) {
+ printk (KERN_ALERT " BLKRRPART: %x\n", BLKRRPART); }
+ break;
+ }
+ case BLKSSZGET :
+ {
+ if (XLBLK_DEBUG_IOCTL) {
+ printk (KERN_ALERT " BLKSSZGET: %x 0x%x\n", BLKSSZGET,
+ xlblk_hardsect_size[minor_dev]); }
+ return xlblk_hardsect_size[minor_dev];
+ }
+ case HDIO_GETGEO :
+ {
+ struct hd_geometry *geo = (struct hd_geometry *)argument;
+
+ if (XLBLK_DEBUG_IOCTL) {
+ printk (KERN_ALERT " HDIO_GETGEO: %x\n", HDIO_GETGEO); }
+
+ if (!argument) return -EINVAL;
+ /*
+ if (put_user(0x80, (byte *)&geo->heads)) return -EFAULT;
+ if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT;
+ if (put_user(0x20b, (unsigned short *) &geo->cylinders)) return -EFAULT;
+ */
+ if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT;
+ if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT;
+ if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT;
+ if (put_user(0x106, (unsigned short *) &geo->cylinders)) return -EFAULT;
+
+ return 0;
+ }
+ case HDIO_GETGEO_BIG :
+ {
+ struct hd_big_geometry *geo = (struct hd_big_geometry *) argument;
+
+ if (XLBLK_DEBUG_IOCTL) {
+ printk (KERN_ALERT " HDIO_GETGEO_BIG: %x\n", HDIO_GETGEO_BIG); }
+
+ if (!argument) return -EINVAL;
+ /*
+ if (put_user(0x80, (byte *)&geo->heads)) return -EFAULT;
+ if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT;
+ if (put_user(0x20b, (unsigned int *) &geo->cylinders)) return -EFAULT;
+ */
+ if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT;
+ if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT;
+ if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT;
+ if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT;
+
+ return 0;
+ }
+ default :
+ {
+ if (XLBLK_DEBUG_IOCTL) {
+ printk (KERN_ALERT " eh? unknown ioctl\n"); }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int xenolinux_block_check(kdev_t dev)
+{
+ if (XLBLK_DEBUG) {
+ printk (KERN_ALERT "xenolinux_block_check\n"); }
+ return 0;
+}
+
+static int xenolinux_block_revalidate(kdev_t dev)
+{
+ if (XLBLK_DEBUG) {
+ printk (KERN_ALERT "xenolinux_block_revalidate\n"); }
+ return 0;
+}
+
+/*
+ * hypervisor_request
+ *
+ * request block io
+ *
+ * id: for guest use only.
+ * operation: XEN_BLOCK_READ, XEN_BLOCK_WRITE or XEN_BLOCK_PROBE
+ * buffer: buffer to read/write into. this should be a
+ * virtual address in the guest os.
+ * block_number: block to read
+ * block_size: size of each block
+ * device: ide/hda is 768 or 0x300
+ * mode: XEN_BLOCK_SYNC or XEN_BLOCK_ASYNC. async requests
+ * will queue until a sync request is issued.
+ */
+
+void hypervisor_request(void * id,
+ int operation,
+ char * buffer,
+ unsigned long block_number,
+ unsigned short block_size,
+ kdev_t device,
+ int mode)
+{
+ blk_ring_t *blk_ring = start_info.blk_ring;
+ int position;
+ void *buffer_pa, *buffer_ma;
+ kdev_t phys_device = (kdev_t) 0;
+ unsigned long sector_number = 0;
+
+#if 0
+ printk(KERN_ALERT "[%x]", id);
+ printk (KERN_ALERT
+ "xlblk_req: id:%p op:%d, bf:%p, blk:%lu, sz:%u, dev:%x\n",
+ id, operation, buffer, block_number, block_size, device);
+#endif
+
+ /* XXX SMH: now need to convert guest virtual address to machine address */
+ buffer_pa = (void *)virt_to_phys((unsigned long)buffer);
+ buffer_ma = (void *)phys_to_machine((unsigned long)buffer_pa);
+
+#if 0
+ printk(KERN_ALERT "va %p => pa %p => ma %p\n", buffer, buffer_pa, buffer_ma);
+#endif
+
+ if (operation == XEN_BLOCK_PROBE)
+ {
+ phys_device = (kdev_t) 0;
+ sector_number = 0;
+ }
+ else if (operation == XEN_BLOCK_READ || operation == XEN_BLOCK_WRITE)
+ {
+ /*
+ * map logial major device to the physical device number
+ *
+ * XLBLK_MAJOR -> IDE0_MAJOR (123 -> 3)
+ */
+ if (MAJOR(device) == XLBLK_MAJOR)
+ {
+ phys_device = MKDEV(IDE0_MAJOR, 0);
+ }
+ else
+ {
+ printk (KERN_ALERT
+ "error: xl_block::hypervisor_request: unknown device [0x%x]\n",
+ device);
+ BUG();
+ }
+
+ /*
+ * compute real buffer location on disk
+ * (from ll_rw_block.c::submit_bh)
+ */
+ {
+ int idx = 0;
+
+ struct gendisk *gd = (struct gendisk *) xen_disk_info.disks[idx].gendisk;
+ unsigned int minor = MINOR(device);
+
+ sector_number = block_number /* * block_size >> 9 */;
+
+ if (gd != NULL) /* if we have a partition table... */
+ {
+ sector_number += gd->part[minor & IDE_PARTN_MASK].start_sect;
+ }
+ }
+ }
+
+ /*
+ * CHECK TO SEE IF THERE IS SPACE IN THE RING
+ */
+ if (BLK_TX_RING_INC(blk_ring->tx_prod) == blk_ring->tx_cons)
+ {
+ printk (KERN_ALERT "hypervisor_request: tx_cons: %d, tx_prod:%d",
+ blk_ring->tx_cons, blk_ring->tx_prod);
+ }
+
+ /* fill out a communications ring structure
+ and then trap into the hypervisor */
+ position = blk_ring->tx_prod;
+ blk_ring->tx_ring[position].id = id;
+ blk_ring->tx_ring[position].priority = mode;
+ blk_ring->tx_ring[position].operation = operation;
+ blk_ring->tx_ring[position].buffer = buffer_ma;
+ blk_ring->tx_ring[position].block_number = block_number;
+ blk_ring->tx_ring[position].block_size = block_size;
+ blk_ring->tx_ring[position].device = phys_device;
+ blk_ring->tx_ring[position].sector_number = sector_number;
+
+ blk_ring->tx_prod = BLK_TX_RING_INC(blk_ring->tx_prod);
+
+ if (mode == XEN_BLOCK_SYNC)
+ {
+ /* trap into hypervisor */
+ HYPERVISOR_block_io_op();
+ }
+ else if (mode == XEN_BLOCK_ASYNC)
+ {
+ /* for now, do nothing. the request will go in the ring and
+ the next sync request will trigger the hypervisor to act */
+ }
+ else
+ {
+ /* ummm, unknown mode. */
+ BUG();
+ }
+
+ return;
+}
+
+
+/*
+ * do_xlblk_request
+ *
+ * read a block; request is in a request queue
+ *
+ * TO DO: should probably release the io_request_lock and then re-acquire
+ * (see LDD p. 338)
+ */
+
+static void do_xlblk_request (request_queue_t *rq)
+{
+ struct request *req;
+
+ if (XLBLK_DEBUG)
+ {
+ printk (KERN_ALERT "xlblk.c::do_xlblk_request for '%s'\n", DEVICE_NAME);
+ }
+
+ while (!QUEUE_EMPTY)
+ {
+ struct buffer_head *bh;
+ unsigned long offset;
+ unsigned long length;
+ int rw;
+
+ req = CURRENT;
+
+ if (XLBLK_DEBUG)
+ {
+ printk (KERN_ALERT
+ "do_xlblk_request %p: cmd %i, sec %lx, (%li) bh:%p\n",
+ req, req->cmd, req->sector,
+ req->current_nr_sectors, req->bh);
+ }
+
+ /* is there space in the tx ring for this request?
+ * if the ring is full, then leave the request in the queue
+ *
+ * THIS IS A BIT BOGUS SINCE XEN COULD BE UPDATING TX_CONS
+ * AT THE SAME TIME
+ */
+ {
+ blk_ring_t *blk_ring = start_info.blk_ring;
+
+ if (BLK_RX_RING_INC(blk_ring->tx_prod) == blk_ring->tx_cons)
+ {
+ printk (KERN_ALERT "OOPS, TX LOOKS FULL cons: %d prod: %d\n",
+ blk_ring->tx_cons, blk_ring->tx_prod);
+ break;
+ }
+ }
+
+ req->errors = 0;
+ blkdev_dequeue_request(req);
+
+ bh = req->bh;
+
+ while (bh)
+ {
+
+ offset = bh->b_rsector << 9;
+ length = bh->b_size;
+
+ rw = req->cmd;
+ if (rw == READA) rw= READ;
+ if ((rw != READ) && (rw != WRITE))
+ {
+ printk (KERN_ALERT
+ "XenoLinux Virtual Block Device: bad command: %d\n", rw);
+ BUG();
+ }
+
+ /*
+ if (XLBLK_DEBUG)
+ {
+ printk (KERN_ALERT "xlblk.c::do_xlblk_request\n");
+ printk (KERN_ALERT " b_blocknr: 0x%lx %ld\n",
+ bh->b_blocknr, bh->b_blocknr);
+ printk (KERN_ALERT " b_size: 0x%x %d\n", bh->b_size, bh->b_size);
+ printk (KERN_ALERT " b_dev: 0x%x %d\n", bh->b_dev, bh->b_dev);
+ printk (KERN_ALERT " b_rsector: 0x%lx %ld\n",
+ bh->b_rsector, bh->b_rsector);
+ }
+ */
+
+ hypervisor_request (req, rw == READ ? XEN_BLOCK_READ : XEN_BLOCK_WRITE,
+ bh->b_data, bh->b_rsector, bh->b_size,
+ bh->b_dev, XEN_BLOCK_SYNC);
+
+ bh = bh->b_reqnext;
+ }
+ }
+
+ return;
+}
+
+/*
+ * xenolinux_block_request
+ *
+ * read a block without using a request queue
+ */
+
+static int xenolinux_block_request(request_queue_t *rq,
+ int rw,
+ struct buffer_head *bh)
+{
+ unsigned int minor;
+ unsigned long offset;
+ unsigned long length;
+
+ if (XLBLK_DEBUG) {
+ printk (KERN_ALERT "xlblk.c::xenolinux_block_request: %lx %d %lx\n",
+ (unsigned long) rq, rw, (unsigned long) bh); }
+ /*
+ printk (KERN_ALERT "xlblk.c::xlblk_request: op:%d bh:%p sect:%lu sz:%u\n",
+ rw, bh, bh->b_rsector, bh->b_size);
+ */
+
+ minor = MINOR(bh->b_rdev);
+
+ offset = bh->b_rsector << 9;
+ length = bh->b_size;
+
+ if (rw == READA) rw= READ;
+ if ((rw != READ) && (rw != WRITE))
+ {
+ printk (KERN_ALERT
+ "XenoLinux Virtual Block Device: bad command: %d\n", rw);
+ goto fail;
+ }
+
+ hypervisor_request (bh, rw == READ ? XEN_BLOCK_READ : XEN_BLOCK_WRITE,
+ bh->b_data, bh->b_rsector, bh->b_size,
+ bh->b_dev, XEN_BLOCK_SYNC);
+
+ return 0;
+
+ fail:
+ return 0;
+}
+
+static struct block_device_operations xenolinux_block_fops =
+{
+ open: xenolinux_block_open,
+ release: xenolinux_block_release,
+ ioctl: xenolinux_block_ioctl,
+ check_media_change: xenolinux_block_check,
+ revalidate: xenolinux_block_revalidate,
+};
+
+static void xlblk_rx_int(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ xlblk_device_t *dev = (xlblk_device_t *)dev_id;
+ blk_ring_t *blk_ring = start_info.blk_ring;
+ struct buffer_head *bh;
+ struct request *req;
+ int loop;
+
+ for (loop = blk_ring->rx_cons;
+ loop != blk_ring->rx_prod;
+ loop = BLK_RX_RING_INC(loop))
+ {
+ blk_ring_entry_t *bret = &blk_ring->rx_ring[loop];
+ void *buffer_pa, *buffer_va;
+
+ buffer_pa = machine_to_phys((unsigned long)bret->buffer);
+ buffer_va = phys_to_virt((unsigned long)buffer_pa);
+
+#if 0
+ printk(KERN_ALERT "xlblk_rx_int: buffer ma %p => pa %p => va %p\n",
+ bret->buffer, buffer_pa, buffer_va);
+
+
+ if (XLBLK_DEBUG)
+ {
+ printk (KERN_ALERT
+ "xlblock::xlblk_rx_int [%s]\n",
+ (bret->operation == XEN_BLOCK_READ) ? "read" : "write");
+ printk (KERN_ALERT
+ " vbuf: %lx, pbuf: %lx, blockno: %lx, size: %x, device %x\n",
+ (unsigned long) buffer_va, (unsigned long) bret->buffer,
+ bret->block_number, bret->block_size, bret->device);
+ printk (KERN_ALERT " bret: %p bh: %p\n", bret, bret->id);
+ }
+
+ /*
+ printk (KERN_ALERT
+ "xlblk_rx: id:%p op:%d, bf:%p, blk:%lu, sz:%u, dev:%x\n",
+ bret->id, bret->operation, bret->buffer, bret->block_number,
+ bret->block_size, bret->device);
+ */
+#endif
+
+ if (USE_REQUEST_QUEUE)
+ {
+ req = (struct request *)bret->id;
+ printk(KERN_ALERT "|%x|", req);
+
+ if (!end_that_request_first(req, 1, "NAME"))
+ {
+ blkdev_dequeue_request(req);
+
+ /* should be end_that_request_last(req)
+ to wake up waiting processes (with complete) */
+ blkdev_release_request(req);
+ }
+
+ /*
+ if (XLBLK_DEBUG)
+ {
+ int temp;
+ printk(KERN_ALERT
+ "buff: 0x%p, blkno: 0x%lx, size: 0x%x, device 0x%x [%p]\n",
+ vbuffer, bret->block_number, bret->block_size, bret->device,
+ bh->b_end_io);
+
+ for (temp = 0; temp < bret->block_size; temp++)
+ {
+ if (temp % 16 == 0) printk ("[%4x] ", temp);
+ else if (temp % 4 == 0) printk (" ");
+ printk ("%02x",
+ vbuffer[temp] & 255);
+ if ((temp + 1) % 16 == 0) printk ("\n");
+ }
+ printk ("\n\n");
+ }
+ */
+
+#ifdef BOGUS
+ req = (struct request *)bret->id;
+ while ((bh = req->bh) != NULL)
+ {
+ req->bh = bh->b_reqnext;
+ bh->b_reqnext = NULL;
+ bh->b_end_io(bh,1);
+ }
+ blkdev_release_request(req);
+#endif /* BOGUS */
+ }
+ else
+ {
+ bh = (struct buffer_head *)bret->id;
+ bh->b_end_io(bh,1);
+
+ /*
+ if (XLBLK_DEBUG)
+ {
+ int temp;
+#if 0
+ printk(KERN_ALERT
+ "buff: 0x%p, blkno: 0x%lx, size: 0x%x, device 0x%x [%p]\n",
+ vbuffer, bret->block_number, bret->block_size, bret->device,
+ bh->b_end_io);
+#endif
+
+ for (temp = 0; temp < bret->block_size; temp++)
+ {
+ if (temp % 16 == 0) printk ("[%4x] ", temp);
+ else if (temp % 4 == 0) printk (" ");
+ printk ("%02x",
+ vbuffer[temp] & 255);
+ if ((temp + 1) % 16 == 0) printk ("\n");
+ }
+ printk ("\n\n");
+ }
+ */
+ }
+ }
+
+ blk_ring->rx_cons = loop;
+}
+
+static void xlblk_tx_int(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ if (XLBLK_DEBUG) {
+ printk (KERN_ALERT "--- xlblock::xlblk_tx_int\n"); }
+}
+
+int __init xlblk_init(void)
+{
+ blk_ring_t *blk_ring = start_info.blk_ring;
+ int loop, error, result;
+
+ /*
+ * initialize memory rings to communicate with hypervisor
+ */
+
+ if ( blk_ring == NULL ) return -ENOMEM;
+
+ blk_ring->tx_prod = blk_ring->tx_cons = 0;
+ blk_ring->rx_prod = blk_ring->rx_cons = 0;
+ blk_ring->tx_ring = NULL;
+ blk_ring->rx_ring = NULL;
+
+ blk_ring->tx_ring = kmalloc(BLK_TX_RING_SIZE * sizeof(blk_ring_entry_t),
+ GFP_KERNEL);
+ blk_ring->rx_ring = kmalloc(BLK_RX_RING_SIZE * sizeof(blk_ring_entry_t),
+ GFP_KERNEL);
+
+ if ((blk_ring->tx_ring == NULL) ||
+ (blk_ring->rx_ring == NULL))
+ {
+ printk (KERN_ALERT
+ "error, could not allocate ring memory for block device\n");
+ error = -ENOBUFS;
+ goto fail;
+ }
+
+ /*
+ * setup soft interrupts to communicate with hypervisor
+ */
+
+ error = request_irq(XLBLK_RX_IRQ, xlblk_rx_int, 0, "xlblk-rx",
+ &xlblk_device);
+ if (error)
+ {
+ printk(KERN_ALERT "Could not allocate receive interrupt\n");
+ goto fail;
+ }
+
+ error = request_irq(XLBLK_TX_IRQ, xlblk_tx_int, 0, "xlblk-tx",
+ &xlblk_device);
+ if (error)
+ {
+ printk(KERN_ALERT "Could not allocate transmit interrupt\n");
+ free_irq(XLBLK_RX_IRQ, &xlblk_device);
+ goto fail;
+ }
+
+ /*
+ * get information about physical drives
+ *
+ */
+ {
+ /* NOTE: this should only occur in domain 0 */
+ memset (&xen_disk_info, 0, sizeof(xen_disk_info));
+ xen_disk_info.count = 0;
+
+ hypervisor_request(NULL, XEN_BLOCK_PROBE, (char *) &xen_disk_info,
+ 0, 0, (kdev_t) 0, XEN_BLOCK_SYNC);
+
+ {
+ int loop;
+ for (loop = 0; loop < xen_disk_info.count; loop++)
+ {
+ printk (KERN_ALERT " %2d: type: %d, capacity: %ld\n",
+ loop, xen_disk_info.disks[loop].type,
+ xen_disk_info.disks[loop].capacity);
+ }
+ }
+ }
+
+ /*
+ * initialize device driver
+ */
+
+ SET_MODULE_OWNER(&xenolinux_block_fops);
+
+ result = register_blkdev(xlblk_major, "block", &xenolinux_block_fops);
+ if (result < 0)
+ {
+ printk (KERN_ALERT "xenolinux block: can't get major %d\n", xlblk_major);
+ return result;
+ }
+
+ /* initialize global arrays in drivers/block/ll_rw_block.c */
+ blk_size[xlblk_major] = xlblk_blk_size;
+ blksize_size[xlblk_major] = xlblk_blksize_size;
+ hardsect_size[xlblk_major] = xlblk_hardsect_size;
+ read_ahead[xlblk_major] = xlblk_read_ahead;
+ max_sectors[xlblk_major] = xlblk_max_sectors;
+ for (loop = 0; loop < XLBLK_MAX; loop++)
+ {
+ xlblk_blk_size[loop] = xen_disk_info.disks[0].capacity;
+ xlblk_blksize_size[loop] = 512;
+ xlblk_hardsect_size[loop] = 512;
+ xlblk_read_ahead[loop] = 8;
+ xlblk_max_sectors[loop] = 128;
+ }
+
+ if (USE_REQUEST_QUEUE)
+ {
+ /* NEED TO MODIFY THIS TO HANDLE MULTIPLE QUEUES
+ * also, should replace do_xlblk_request with blk.h::DEVICE_REQUEST
+ */
+ blk_init_queue(BLK_DEFAULT_QUEUE(xlblk_major), do_xlblk_request);
+ blk_queue_headactive(BLK_DEFAULT_QUEUE(xlblk_major), 0);
+ }
+ else
+ {
+ /* we don't use __make_request in ll_rw_blk */
+ blk_queue_make_request(BLK_DEFAULT_QUEUE(xlblk_major),
+ xenolinux_block_request);
+ }
+ xlblk_ide_register_disk(0, xen_disk_info.disks[0].capacity);
+
+ /*
+ * completion
+ */
+ printk(KERN_ALERT
+ "XenoLinux Virtual Block Device Driver installed [device: %d]\n",
+ xlblk_major);
+ return 0;
+
+ fail:
+ if (blk_ring->tx_ring) kfree(blk_ring->tx_ring);
+ if (blk_ring->rx_ring) kfree(blk_ring->rx_ring);
+ return error;
+}
+
+void xlblk_ide_register_disk(int idx, unsigned long capacity)
+{
+ int units;
+ int minors;
+ struct gendisk *gd;
+
+ /* plagarized from ide-probe.c::init_gendisk */
+
+ units = 2; /* from ide.h::MAX_DRIVES */
+
+ minors = units * (1<<IDE_PARTN_BITS);
+ gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
+ gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
+ gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
+ memset(gd->part, 0, minors * sizeof(struct hd_struct));
+
+ gd->major = xlblk_major; /* our major device number */
+ gd->major_name = XLBLK_MAJOR_NAME; /* treated special in genhd.c */
+ gd->minor_shift = IDE_PARTN_BITS; /* num bits for partitions */
+ gd->max_p = 1<<IDE_PARTN_BITS; /* 1 + max partitions / drive */
+ gd->nr_real = units; /* current num real drives */
+ gd->real_devices= NULL; /* ptr to internal data (was: hwif) */
+ gd->next = NULL; /* linked list of major devs */
+ gd->fops = &xenolinux_block_fops; /* file operations */
+ gd->de_arr = kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL);
+ gd->flags = kmalloc (sizeof *gd->flags * units, GFP_KERNEL);
+ if (gd->de_arr) memset (gd->de_arr, 0, sizeof *gd->de_arr * units);
+ if (gd->flags) memset (gd->flags, 0, sizeof *gd->flags * units);
+ add_gendisk(gd);
+
+ xen_disk_info.disks[idx].gendisk = gd;
+
+ /* default disk size is just a big number. in the future, we
+ need a message to probe the devices to determine the actual size */
+ register_disk(gd, MKDEV(xlblk_major, 0), 1<<IDE_PARTN_BITS,
+ &xenolinux_block_fops, capacity);
+
+ return;
+}
+
+static void __exit xlblk_cleanup(void)
+{
+ /* CHANGE FOR MULTIQUEUE */
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(xlblk_major));
+
+ /* clean up global arrays */
+ read_ahead[xlblk_major] = 0;
+ if (blk_size[xlblk_major]) kfree(blk_size[xlblk_major]);
+ blk_size[xlblk_major] = NULL;
+ if (blksize_size[xlblk_major]) kfree(blksize_size[xlblk_major]);
+ blksize_size[xlblk_major] = NULL;
+ if (hardsect_size[xlblk_major]) kfree(hardsect_size[xlblk_major]);
+ hardsect_size[xlblk_major] = NULL;
+
+ /*
+ *
+ * TODO: FOR EACH GENDISK, FREE
+ *
+ */
+
+ if (unregister_blkdev(xlblk_major, "block"))
+ {
+ printk(KERN_ALERT
+ "XenoLinux Virtual Block Device Driver uninstalled with errors\n");
+ }
+ else
+ {
+ printk(KERN_ALERT "XenoLinux Virtual Block Device Driver uninstalled\n");
+ }
+
+ return;
+}
+
+
+#ifdef MODULE
+module_init(xlblk_init);
+module_exit(xlblk_cleanup);
+#endif
diff --git a/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block_test.c b/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block_test.c
new file mode 100644
index 0000000000..cab6d9a330
--- /dev/null
+++ b/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block_test.c
@@ -0,0 +1,233 @@
+/******************************************************************************
+ * xenolinux_block_test.c
+ *
+ */
+#define EXPORT_SYMTAB
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <asm/hypervisor-ifs/block.h>
+#include <asm/hypervisor-ifs/hypervisor-if.h>
+
+/******************************************************************/
+
+static struct proc_dir_entry *bdt;
+static blk_ring_entry_t meta;
+static char * data;
+
+static int proc_read_bdt(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ switch (meta.operation)
+ {
+ case XEN_BLOCK_READ :
+ case XEN_BLOCK_WRITE :
+ {
+ return proc_dump_block(page, start, off, count, eof, data);
+ }
+ case XEN_BLOCK_DEBUG :
+ {
+ return proc_dump_debug(page, start, off, count, eof, data);
+ }
+ default :
+ {
+ printk(KERN_ALERT
+ "block device test error: unknown operation [%c]\n",
+ meta.operation);
+ return -EINVAL;
+ }
+ }
+}
+
+int proc_dump_debug(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char header[100];
+ char dump[1024];
+
+ sprintf (header, "Block Device Test: Debug Dump\n\n");
+
+ sprintf (dump, "%s\n", meta.buffer);
+
+ if (data)
+ {
+ kfree(data);
+ }
+
+ strncpy (page, dump, count);
+ return strlen(page);
+}
+
+int proc_dump_block(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char header[100];
+ char dump[1024];
+ char temp[100];
+ int loop;
+
+ sprintf (header, "Block Device Test\n\n%s blk num: %ld 0x%lx; size: %d 0x%x; device: 0x%x\n",
+ meta.operation == XEN_BLOCK_WRITE ? "write" : "read",
+ meta.block_number, meta.block_number,
+ meta.block_size, meta.block_size,
+ meta.device);
+
+ sprintf (dump, "%s", header);
+
+ if (meta.buffer)
+ {
+ for (loop = 0; loop < 100; loop++)
+ {
+ int i = meta.buffer[loop];
+
+ if (loop % 8 == 0)
+ {
+ sprintf (temp, "[%2d] ", loop);
+ strcat(dump, temp);
+ }
+ else if (loop % 2 == 0)
+ {
+ strcat(dump, " ");
+ }
+
+ sprintf (temp, " 0x%02x", i & 255);
+ strcat(dump, temp);
+ if ((loop + 1) % 8 == 0)
+ {
+ strcat(dump, "\n");
+ }
+ }
+ strcat(dump, "\n\n");
+ }
+
+ if (data)
+ {
+ kfree(data);
+ }
+
+ strncpy (page, dump, count);
+ return strlen(page);
+}
+
+int proc_write_bdt(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ char *local = kmalloc((count + 1) * sizeof(char), GFP_KERNEL);
+ char opcode;
+ int block_number = 0;
+ int block_size = 0;
+ int device = 0;
+ int mode;
+
+ if (copy_from_user(local, buffer, count))
+ {
+ return -EFAULT;
+ }
+ local[count] = '\0';
+
+ sscanf(local, "%c %i %i %i",
+ &opcode, &block_number, &block_size, &device);
+
+ if (opcode == 'r' || opcode == 'R')
+ {
+ meta.operation = XEN_BLOCK_READ;
+ }
+ else if (opcode == 'w' || opcode == 'W')
+ {
+ meta.operation = XEN_BLOCK_WRITE;
+ }
+ else if (opcode == 'd' || opcode == 'D')
+ {
+ meta.operation = XEN_BLOCK_DEBUG;
+ block_size = 10000;
+ }
+ else
+ {
+ printk(KERN_ALERT
+ "block device test error: unknown opcode [%c]\n", opcode);
+ return -EINVAL;
+ }
+
+ if (opcode == 'r' || opcode == 'w' ||
+ opcode == 'd' || opcode == 'D')
+ {
+ mode = XEN_BLOCK_SYNC;
+ }
+ else /* (opcode == 'R' || opcode == 'W') */
+ {
+ mode = XEN_BLOCK_ASYNC;
+ }
+
+ if (data)
+ {
+ kfree(data);
+ }
+ data = kmalloc(block_size * sizeof(char), GFP_KERNEL);
+ if (data == NULL)
+ {
+ kfree(local);
+ return -ENOMEM;
+ }
+
+ meta.block_number = block_number;
+ meta.block_size = block_size;
+ meta.device = device;
+ meta.buffer = data;
+
+ /* submit request */
+ hypervisor_request(0, meta.operation, meta.buffer,
+ meta.block_number, meta.block_size,
+ meta.device, mode);
+
+ kfree(local);
+ return count;
+}
+
+
+static int __init init_module(void)
+{
+ int return_value = 0;
+
+ /* create proc entry */
+ bdt = create_proc_entry("bdt", 0644, NULL);
+ if (bdt == NULL)
+ {
+ return_value = -ENOMEM;
+ goto error;
+ }
+ bdt->data = NULL;
+ bdt->read_proc = proc_read_bdt;
+ bdt->write_proc = proc_write_bdt;
+ bdt->owner = THIS_MODULE;
+
+ memset(&meta, 0, sizeof(meta));
+
+ /* success */
+ printk(KERN_ALERT "XenoLinux Block Device Test installed\n");
+ return 0;
+
+ error:
+ return return_value;
+}
+
+static void __exit cleanup_module(void)
+{
+ if (data)
+ {
+ kfree(data);
+ }
+ printk(KERN_ALERT "XenoLinux Block Device Test uninstalled\n");
+}
+
+module_init(init_module);
+module_exit(cleanup_module);
diff --git a/xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c b/xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c
new file mode 100644
index 0000000000..97d4a65b78
--- /dev/null
+++ b/xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c
@@ -0,0 +1,27 @@
+/*
+ * domain 0 block driver interface
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+static int __init init_module(void)
+{
+ request_module("xl_block");
+ printk("Successfully installed domain 0 block interface\n");
+
+
+ return 0;
+}
+
+static void __exit cleanup_module(void)
+{
+ printk("Successfully de-installed domain-0 block interface\n");
+ return 0;
+}
+
+module_init(init_module);
+module_exit(cleanup_module);