diff options
author | kaf24@labyrinth.cl.cam.ac.uk <kaf24@labyrinth.cl.cam.ac.uk> | 2003-03-07 01:38:49 +0000 |
---|---|---|
committer | kaf24@labyrinth.cl.cam.ac.uk <kaf24@labyrinth.cl.cam.ac.uk> | 2003-03-07 01:38:49 +0000 |
commit | d0ec9023281a5d6ed0aee9341c7889320664e862 (patch) | |
tree | cfb9ba8056120e9c67a66a06a2785f7d4073a2d1 /xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c | |
parent | 796305db16ed924df9d4061b70ba110e5978b226 (diff) | |
download | xen-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.c | 356 |
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); } |