aboutsummaryrefslogtreecommitdiffstats
path: root/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c
diff options
context:
space:
mode:
authorkaf24@labyrinth.cl.cam.ac.uk <kaf24@labyrinth.cl.cam.ac.uk>2003-03-07 01:38:49 +0000
committerkaf24@labyrinth.cl.cam.ac.uk <kaf24@labyrinth.cl.cam.ac.uk>2003-03-07 01:38:49 +0000
commitd0ec9023281a5d6ed0aee9341c7889320664e862 (patch)
treecfb9ba8056120e9c67a66a06a2785f7d4073a2d1 /xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c
parent796305db16ed924df9d4061b70ba110e5978b226 (diff)
downloadxen-d0ec9023281a5d6ed0aee9341c7889320664e862.tar.gz
xen-d0ec9023281a5d6ed0aee9341c7889320664e862.tar.bz2
xen-d0ec9023281a5d6ed0aee9341c7889320664e862.zip
bitkeeper revision 1.110 (3e67f829AwB4Vv_qPsJlN_yjkdepyg)
xl_block.h: new file Many files: Cleaned up new blkdev world. .del-blk.h~f91949f6390760d: Delete: xenolinux-2.4.21-pre4-sparse/include/linux/blk.h .del-xl_block_test.c~b3dce903a84011b8: Delete: xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block_test.c .del-xeno-major.h~d739160829760724: Delete: xen/include/hypervisor-ifs/xeno-major.h .del-grok.c~eca1f7a23736b451: Delete: xen/drivers/block/grok.c
Diffstat (limited to 'xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c')
-rw-r--r--xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c356
1 files changed, 134 insertions, 222 deletions
diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c
index af270f1aa1..985fda050f 100644
--- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c
+++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c
@@ -5,138 +5,83 @@
*
*/
-#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>
-#include <linux/blkdev.h>
-#include <linux/major.h>
-
-#include <asm/hypervisor-ifs/block.h>
-#include <asm/hypervisor-ifs/hypervisor-if.h>
-#include <asm/io.h>
-#include <asm/atomic.h>
-#include <asm/uaccess.h>
-
+#include "xl_block.h"
#include <linux/blk.h>
-/* Copied from linux/ide.h */
-typedef unsigned char byte;
-
-extern int xlide_init(int xidx, int idx);
-extern int xlide_hwsect(int minor);
-extern void xlide_cleanup(void);
-extern int xlscsi_init(int xidx, int idx);
-extern int xlscsi_hwsect(int minor);
-extern void xlscsi_cleanup(void);
-
-static int nide = 0; // number of IDE devices we have
-static int nscsi = 0; // number of SCSI devices we have
-
+typedef unsigned char byte; /* from linux/ide.h */
-#define XLBLK_MAX 32 /* XXX SMH: this the max of XLIDE_MAX and XLSCSI_MAX */
+#define XLBLK_MAX 32
#define XLBLK_RESPONSE_IRQ _EVENT_BLK_RESP
+#define DEBUG_IRQ _EVENT_DEBUG
-#define DEBUG_IRQ _EVENT_DEBUG
-
-#if 0
-#define DPRINTK(_f, _a...) printk ( KERN_ALERT _f , ## _a )
-#define DPRINTK_IOCTL(_f, _a...) printk ( KERN_ALERT _f , ## _a )
-#else
-#define DPRINTK(_f, _a...) ((void)0)
-#define DPRINTK_IOCTL(_f, _a...) ((void)0)
-#endif
+#define PARTN_SHIFT 4
static blk_ring_t *blk_ring;
static unsigned int resp_cons; /* Response consumer for comms ring. */
-
static xen_disk_info_t xlblk_disk_info;
-atomic_t xlblk_control_count;
-
-void xlblk_ide_register_disk(int, unsigned long);
-void do_xlseg_requestX (request_queue_t *rq);
-int hypervisor_request(void * id,
- int operation,
- char * buffer,
- unsigned long block_number,
- unsigned short block_size,
- kdev_t device,
- struct gendisk *gd);
-
-/* ------------------------------------------------------------------------
+static int xlblk_control_msg_pending;
+
+/*
+ * Request queues with outstanding work, but ring is currently full.
+ * We need no special lock here, as we always access this with the
+ * io_request_lock held. We only need a small maximum list.
*/
+#define MAX_PENDING 8
+static request_queue_t *pending_queues[MAX_PENDING];
+static int nr_pending;
-/* Convert from a XenoLinux (major,minor) to the Xen-level 'physical' device */
-static kdev_t xldev_to_physdev(kdev_t xldev)
+/* Convert from a XenoLinux major device to the Xen-level 'physical' device */
+static inline unsigned short xldev_to_physdev(kdev_t xldev)
{
- int xlmajor = MAJOR(xldev);
- int major, minor;
+ unsigned short physdev;
- switch(xlmajor) {
+ switch ( MAJOR(xldev) )
+ {
case XLIDE_MAJOR:
- major = IDE0_MAJOR;
- minor = 0; /* we do minor offsetting manually by addition */
+ physdev = XENDEV_IDE;
break;
case XLSCSI_MAJOR:
- major = SCSI_DISK0_MAJOR;
- minor = 0; /* we do minor offsetting manually by addition */
+ physdev = XENDEV_SCSI;
break;
+ case XLVIRT_MAJOR:
+ physdev = XENDEV_VIRTUAL;
+ break;
+
default:
- panic("xldev_to_physdev: unhandled major %d\n", xlmajor);
- break;
+ BUG();
}
- return MKDEV(major, minor);
+ physdev += (MINOR(xldev) >> PARTN_SHIFT);
+
+ return physdev;
}
-/*
-** Locate the gendisk structure associated with a particular xenolinux disk;
-** this requires a scan of the xen_disk_info[] array currently which kind of
-** sucks. However we can clean this whole area up later (i.e. post SOSP).
-*/
-struct gendisk *xldev_to_gendisk(kdev_t xldev, int *t)
+static inline struct gendisk *xldev_to_gendisk(kdev_t xldev)
{
- int i, j, posn, type;
+ struct gendisk *gd = NULL;
- switch(MAJOR(xldev)) {
-
+ switch ( MAJOR(xldev) )
+ {
case XLIDE_MAJOR:
- type = 1;
- posn = 1;
+ gd = xlide_gendisk;
break;
case XLSCSI_MAJOR:
- type = 2;
- posn = 1;
- break;
-
- default:
- panic("xldev_to_gendisk: unhandled major %d\n", MAJOR(xldev));
+ gd = xlscsi_gendisk;
break;
- }
-
- for ( i = j = 0; i < xen_disk_info.count; i++ ) {
- if(xen_disk_info.disks[i].type == type)
- if(++j == posn)
- break;
+ case XLVIRT_MAJOR:
+ gd = xlsegment_gendisk;
+ break;
}
- if(t)
- *t = type;
+ if ( gd == NULL ) BUG();
- return (xen_disk_info.disks[i].gendisk);
+ return gd;
}
int xenolinux_block_open(struct inode *inode, struct file *filep)
@@ -156,7 +101,6 @@ int xenolinux_block_release(struct inode *inode, struct file *filep)
int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
unsigned command, unsigned long argument)
{
- int minor_dev, type;
struct hd_geometry *geo = (struct hd_geometry *)argument;
struct gendisk *gd;
struct hd_struct *part;
@@ -167,16 +111,13 @@ int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
if (!capable(CAP_SYS_ADMIN)) return -EPERM;
if (!inode) return -EINVAL;
- minor_dev = MINOR(inode->i_rdev);
- if (minor_dev >= XLBLK_MAX) return -ENODEV;
-
- DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, minor: 0x%x\n",
- command, (long) argument, minor_dev);
+ DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n",
+ command, (long) argument, inode->i_rdev);
- gd = xldev_to_gendisk(inode->i_rdev, &type);
- part = &gd->part[minor_dev];
+ gd = xldev_to_gendisk(inode->i_rdev);
+ part = &gd->part[MINOR(inode->i_rdev)];
- switch (command)
+ switch ( command )
{
case BLKGETSIZE:
DPRINTK_IOCTL(" BLKGETSIZE: %x %lx\n", BLKGETSIZE, part->nr_sects);
@@ -187,24 +128,32 @@ int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
break;
case BLKSSZGET:
- switch(type) {
- case 1:
+ switch ( MAJOR(inode->i_rdev) )
+ {
+ case XLIDE_MAJOR:
DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET,
- xlide_hwsect(minor_dev));
- return xlide_hwsect(minor_dev);
- break;
- case 2:
+ xlide_hwsect(MINOR(inode->i_rdev)));
+ return xlide_hwsect(MINOR(inode->i_rdev));
+
+ case XLSCSI_MAJOR:
DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET,
- xlscsi_hwsect(minor_dev));
- return xlscsi_hwsect(minor_dev);
- break;
+ xlscsi_hwsect(MINOR(inode->i_rdev)));
+ return xlscsi_hwsect(MINOR(inode->i_rdev));
- default:
- printk("BLKSSZGET ioctl() on bogus type %d disk!\n", type);
- return 0;
+ case XLVIRT_MAJOR:
+ DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET,
+ xlsegment_hwsect(MINOR(inode->i_rdev)));
+ return xlsegment_hwsect(MINOR(inode->i_rdev));
+ default:
+ printk(KERN_ALERT "BLKSSZGET ioctl() on bogus disk!\n");
+ return 0;
}
+ case BLKBSZGET: /* get block size */
+ DPRINTK_IOCTL(" BLKBSZGET: %x\n", BLKBSZGET);
+ break;
+
case BLKBSZSET: /* set block size */
DPRINTK_IOCTL(" BLKBSZSET: %x\n", BLKBSZSET);
break;
@@ -217,11 +166,6 @@ int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
DPRINTK_IOCTL(" BLKRAFET: %x\n", BLKRAGET);
break;
- case BLKSSZGET: /* get sector size */
- DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET,
- xlblk_hardsect_size[minor_dev]);
- return xlblk_hardsect_size[minor_dev];
-
case HDIO_GETGEO:
/* note: these values are complete garbage */
DPRINTK_IOCTL(" HDIO_GETGEO: %x\n", HDIO_GETGEO);
@@ -273,21 +217,20 @@ int xenolinux_block_revalidate(kdev_t dev)
* virtual address in the guest os.
* block_number: block to read
* block_size: size of each block
- * device: xhd or vhd
- * gd: partition information if XEN_BLOCK_{READ,WRITE}
+ * device: xhd*, ksd*, xvd*, ...
*/
-int hypervisor_request(void * id,
- int operation,
- char * buffer,
- unsigned long block_number,
- unsigned short block_size,
- kdev_t device,
- struct gendisk *gd)
+static int hypervisor_request(void * id,
+ int operation,
+ char * buffer,
+ unsigned long block_number,
+ unsigned short block_size,
+ kdev_t device)
{
int position;
void *buffer_ma;
kdev_t phys_device = (kdev_t) 0;
unsigned long sector_number = 0;
+ struct gendisk *gd;
/*
* Bail if there's no room in the request communication ring. This may be
@@ -311,12 +254,10 @@ int hypervisor_request(void * id,
case XEN_BLOCK_READ:
case XEN_BLOCK_WRITE:
- phys_device = xldev_to_physdev(device);
- if (!IS_XHD_MAJOR(MAJOR(device)))
- phys_device = MAJOR(device);
+ phys_device = xldev_to_physdev(device);
/* Compute real buffer location on disk */
sector_number = block_number;
- gd = xldev_to_gendisk(device, NULL);
+ gd = xldev_to_gendisk(device);
sector_number += gd->part[MINOR(device)].start_sect;
break;
@@ -324,7 +265,7 @@ int hypervisor_request(void * id,
panic("unknown op %d\n", operation);
}
- /* Fill out a communications ring structure & trap to the hypervisor */
+ /* Fill out a communications ring structure. */
position = blk_ring->req_prod;
blk_ring->ring[position].req.id = id;
blk_ring->ring[position].req.operation = operation;
@@ -344,7 +285,7 @@ int hypervisor_request(void * id,
* do_xlblk_request
* read a block; request is in a request queue
*/
-void do_xlblk_request (request_queue_t *rq)
+void do_xlblk_request(request_queue_t *rq)
{
struct request *req;
struct buffer_head *bh;
@@ -373,10 +314,14 @@ void do_xlblk_request (request_queue_t *rq)
{
full = hypervisor_request(
bh, (rw == READ) ? XEN_BLOCK_READ : XEN_BLOCK_WRITE,
- bh->b_data, bh->b_rsector, bh->b_size, bh->b_dev,
- (struct gendisk *)xlblk_disk_info.disks[0].gendisk);
+ bh->b_data, bh->b_rsector, bh->b_size, bh->b_dev);
- if ( full ) goto out;
+ if ( full )
+ {
+ pending_queues[nr_pending++] = rq;
+ if ( nr_pending >= MAX_PENDING ) BUG();
+ goto out;
+ }
queued++;
@@ -411,15 +356,6 @@ void do_xlblk_request (request_queue_t *rq)
}
-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_response_int(int irq, void *dev_id, struct pt_regs *ptregs)
{
int i;
@@ -435,46 +371,56 @@ static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs)
blk_ring_resp_entry_t *bret = &blk_ring->ring[i].resp;
switch (bret->operation)
{
- case XEN_BLOCK_READ :
- case XEN_BLOCK_WRITE :
+ case XEN_BLOCK_READ:
+ case XEN_BLOCK_WRITE:
if ( (bh = bret->id) != NULL ) bh->b_end_io(bh, 1);
break;
- case XEN_BLOCK_SEG_CREATE :
- case XEN_BLOCK_SEG_DELETE :
- case XEN_BLOCK_PROBE_SEG :
- atomic_dec(&xlblk_control_count);
- break;
+ case XEN_BLOCK_SEG_CREATE:
+ case XEN_BLOCK_SEG_DELETE:
+ case XEN_BLOCK_PROBE_SEG:
+ case XEN_BLOCK_PROBE_BLK:
+ xlblk_control_msg_pending = 0;
+ break;
- default:
- break;
+ default:
+ BUG();
}
}
resp_cons = i;
- /* KAF: We can push work down at this point. We have the lock. */
- for (i = 0; i < xen_disk_info.count; i++) {
- /*
- ** XXX SMH: this is pretty broken ...
- ** a) should really only kick devs w/ outstanding work
- ** b) should cover /all/ devs, not just first IDE & SCSI
- ** KAF will fix this I'm sure.
- */
- do_xlblk_request(BLK_DEFAULT_QUEUE(IDE0_MAJOR));
- do_xlblk_request(BLK_DEFAULT_QUEUE(SCSI_DISK0_MAJOR));
- do_xlseg_requestX(BLK_DEFAULT_QUEUE(XLSEG_MAJOR));
+ /* We kick pending request queues if the ring is reasonably empty. */
+ if ( (nr_pending != 0) &&
+ (((blk_ring->req_prod - resp_cons) & (BLK_RING_SIZE - 1)) <
+ (BLK_RING_SIZE >> 1)) )
+ {
+ do { do_xlblk_request(pending_queues[--nr_pending]); }
+ while ( nr_pending != 0 );
}
spin_unlock_irqrestore(&io_request_lock, flags);
}
+/* Send a synchronous message to Xen. */
+int xenolinux_control_msg(int operation, char *buffer)
+{
+ xlblk_control_msg_pending = 1; barrier();
+ if ( hypervisor_request(NULL, operation, buffer, 0, 0, 0) )
+ return -EAGAIN;
+ HYPERVISOR_block_io_op();
+ while ( xlblk_control_msg_pending ) barrier();
+ return 0;
+}
+
+
int __init xlblk_init(void)
{
- int i, error, result;
+ int error;
- atomic_set(&xlblk_control_count, 0);
+ xlblk_control_msg_pending = 0;
+ nr_pending = 0;
/* This mapping was created early at boot time. */
blk_ring = (blk_ring_t *)fix_to_virt(FIX_BLKRING_BASE);
@@ -482,45 +428,27 @@ int __init xlblk_init(void)
error = request_irq(XLBLK_RESPONSE_IRQ, xlblk_response_int, 0,
"xlblk-response", NULL);
- if (error) {
+ if ( error )
+ {
printk(KERN_ALERT "Could not allocate receive interrupt\n");
goto fail;
}
- /* probe for disk information */
- memset (&xlblk_disk_info, 0, sizeof(xlblk_disk_info));
- xlblk_disk_info.count = 0;
-
- if ( hypervisor_request(NULL, XEN_BLOCK_PROBE_BLK,
- (char *) &xlblk_disk_info,
- 0, 0, (kdev_t) 0,
- (struct gendisk *) NULL))
- BUG();
- HYPERVISOR_block_io_op();
- while ( blk_ring->resp_prod != 1 ) barrier();
- for ( i = 0; i < xlblk_disk_info.count; i++ )
- {
- /*
- ** SMH: initialize all the disks we found; this is complicated a
- ** bit by the fact that we have both IDE and SCSI disks underneath
- */
- printk (KERN_ALERT " %2d: type: %d, capacity: %ld\n",
- i, xlblk_disk_info.disks[i].type,
- xlblk_disk_info.disks[i].capacity);
-
- switch(xen_disk_info.disks[i].type) {
- case 1:
- xlide_init(i, nide++);
- break;
- case 2:
- xlscsi_init(i, nscsi++);
- break;
- default:
- printk("Unknown Xen disk type %d\n", xen_disk_info.disks[i].type);
- break;
- }
+ /* Probe for disk information. */
+ memset(&xlblk_disk_info, 0, sizeof(xlblk_disk_info));
+ error = xenolinux_control_msg(XEN_BLOCK_PROBE_BLK,
+ (char *)&xlblk_disk_info);
+ if ( error )
+ {
+ printk(KERN_ALERT "Could not probe disks (%d)\n", error);
+ free_irq(XLBLK_RESPONSE_IRQ, NULL);
+ goto fail;
}
+ /* Pass the information to our fake IDE and SCSI susbystems. */
+ xlide_init(&xlblk_disk_info);
+ xlscsi_init(&xlblk_disk_info);
+
return 0;
fail:
@@ -529,25 +457,9 @@ int __init xlblk_init(void)
static void __exit xlblk_cleanup(void)
{
- int i;
-
- for ( i = 0; i < xen_disk_info.count; i++ )
- {
- switch(xen_disk_info.disks[i].type) {
- case 1:
- xlide_cleanup();
- break;
- case 2:
- xlscsi_cleanup();
- break;
- default:
- printk("Unknown Xen disk type %d\n", xen_disk_info.disks[i].type);
- break;
- }
-
- }
-
- return;
+ xlide_cleanup();
+ xlscsi_cleanup();
+ free_irq(XLBLK_RESPONSE_IRQ, NULL);
}