diff options
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 | 348 |
1 files changed, 169 insertions, 179 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 bc87e7eb7b..af270f1aa1 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 @@ -1,7 +1,7 @@ /****************************************************************************** * xl_block.c * - * Xenolinux virtual block-device driver (xhd). + * Xenolinux virtual block-device driver. * */ @@ -25,22 +25,23 @@ #include <asm/atomic.h> #include <asm/uaccess.h> -#define MAJOR_NR XLBLK_MAJOR /* force defns in blk.h, must precede include */ -static int xlblk_major = XLBLK_MAJOR; #include <linux/blk.h> /* Copied from linux/ide.h */ typedef unsigned char byte; -#define XLBLK_MAX 32 /* Maximum minor devices we support */ -#define XLBLK_MAJOR_NAME "xhd" -#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_read_ahead; -static int xlblk_hardsect_size[XLBLK_MAX]; -static int xlblk_max_sectors[XLBLK_MAX]; +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 + + +#define XLBLK_MAX 32 /* XXX SMH: this the max of XLIDE_MAX and XLSCSI_MAX */ #define XLBLK_RESPONSE_IRQ _EVENT_BLK_RESP @@ -56,6 +57,7 @@ static int xlblk_max_sectors[XLBLK_MAX]; 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; @@ -69,54 +71,139 @@ int hypervisor_request(void * id, kdev_t device, struct gendisk *gd); - /* ------------------------------------------------------------------------ */ -static int xenolinux_block_open(struct inode *inode, struct file *filep) +/* Convert from a XenoLinux (major,minor) to the Xen-level 'physical' device */ +static kdev_t xldev_to_physdev(kdev_t xldev) +{ + int xlmajor = MAJOR(xldev); + int major, minor; + + switch(xlmajor) { + case XLIDE_MAJOR: + major = IDE0_MAJOR; + minor = 0; /* we do minor offsetting manually by addition */ + break; + + case XLSCSI_MAJOR: + major = SCSI_DISK0_MAJOR; + minor = 0; /* we do minor offsetting manually by addition */ + break; + + default: + panic("xldev_to_physdev: unhandled major %d\n", xlmajor); + break; + } + + return MKDEV(major, minor); +} + + +/* +** 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) +{ + int i, j, posn, type; + + switch(MAJOR(xldev)) { + + case XLIDE_MAJOR: + type = 1; + posn = 1; + break; + + case XLSCSI_MAJOR: + type = 2; + posn = 1; + break; + + default: + panic("xldev_to_gendisk: unhandled major %d\n", MAJOR(xldev)); + break; + } + + + for ( i = j = 0; i < xen_disk_info.count; i++ ) { + if(xen_disk_info.disks[i].type == type) + if(++j == posn) + break; + } + + if(t) + *t = type; + + return (xen_disk_info.disks[i].gendisk); +} + +int xenolinux_block_open(struct inode *inode, struct file *filep) { DPRINTK("xenolinux_block_open\n"); return 0; } -static int xenolinux_block_release(struct inode *inode, struct file *filep) +int xenolinux_block_release(struct inode *inode, struct file *filep) { DPRINTK("xenolinux_block_release\n"); return 0; } -static int xenolinux_block_ioctl(struct inode *inode, struct file *filep, + + +int xenolinux_block_ioctl(struct inode *inode, struct file *filep, unsigned command, unsigned long argument) { - int minor_dev; + int minor_dev, type; struct hd_geometry *geo = (struct hd_geometry *)argument; - + struct gendisk *gd; + struct hd_struct *part; + DPRINTK("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; DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, minor: 0x%x\n", command, (long) argument, minor_dev); + gd = xldev_to_gendisk(inode->i_rdev, &type); + part = &gd->part[minor_dev]; + switch (command) { - case BLKGETSIZE: /* get size */ - DPRINTK_IOCTL(" BLKGETSIZE: %x %lx\n", BLKGETSIZE, - (long) xlblk_disk_info.disks[0].capacity); - return put_user(xlblk_disk_info.disks[0].capacity, - (unsigned long *) argument); + case BLKGETSIZE: + DPRINTK_IOCTL(" BLKGETSIZE: %x %lx\n", BLKGETSIZE, part->nr_sects); + return put_user(part->nr_sects, (unsigned long *) argument); case BLKRRPART: /* re-read partition table */ DPRINTK_IOCTL(" BLKRRPART: %x\n", BLKRRPART); break; - case BLKBSZGET: /* get block size */ - DPRINTK_IOCTL(" BLKBSZGET: %x\n", BLKBSZGET); - break; + case BLKSSZGET: + switch(type) { + case 1: + DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET, + xlide_hwsect(minor_dev)); + return xlide_hwsect(minor_dev); + break; + case 2: + DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET, + xlscsi_hwsect(minor_dev)); + return xlscsi_hwsect(minor_dev); + break; + + default: + printk("BLKSSZGET ioctl() on bogus type %d disk!\n", type); + return 0; + + } case BLKBSZSET: /* set block size */ DPRINTK_IOCTL(" BLKBSZSET: %x\n", BLKBSZSET); @@ -163,13 +250,13 @@ static int xenolinux_block_ioctl(struct inode *inode, struct file *filep, return 0; } -static int xenolinux_block_check(kdev_t dev) +int xenolinux_block_check(kdev_t dev) { DPRINTK("xenolinux_block_check\n"); return 0; } -static int xenolinux_block_revalidate(kdev_t dev) +int xenolinux_block_revalidate(kdev_t dev) { DPRINTK("xenolinux_block_revalidate\n"); return 0; @@ -224,30 +311,13 @@ int hypervisor_request(void * id, case XEN_BLOCK_READ: case XEN_BLOCK_WRITE: - /* only accept requests for xhd and vhd devices */ - if (!IS_XHD_MAJOR(MAJOR(device)) && !IS_VHD_MAJOR(MAJOR(device))) - panic("error: xl_block::hypervisor_request: " - "unknown device [0x%x]\n", device); - phys_device = MAJOR(device); - - /* Compute real buffer location on disk. - * note: gd will be null when we read the partition table. - */ + phys_device = xldev_to_physdev(device); + if (!IS_XHD_MAJOR(MAJOR(device))) + phys_device = MAJOR(device); + /* Compute real buffer location on disk */ sector_number = block_number; - if ( gd != NULL ) - { - sector_number += gd->part[MINOR(device)&IDE_PARTN_MASK].start_sect; - } - - /* - if (IS_VHD_MAJOR(MAJOR(device))) - { - printk (KERN_ALERT "%lx + %lx = %lx (%x)\n", - block_number, - gd->part[MINOR(device)&IDE_PARTN_MASK].start_sect, - sector_number, device); - } - */ + gd = xldev_to_gendisk(device, NULL); + sector_number += gd->part[MINOR(device)].start_sect; break; default: @@ -274,7 +344,7 @@ int hypervisor_request(void * id, * do_xlblk_request * read a block; request is in a request queue */ -static void do_xlblk_request (request_queue_t *rq) +void do_xlblk_request (request_queue_t *rq) { struct request *req; struct buffer_head *bh; @@ -282,9 +352,10 @@ static void do_xlblk_request (request_queue_t *rq) DPRINTK("xlblk.c::do_xlblk_request for '%s'\n", DEVICE_NAME); - while ( !rq->plugged && !QUEUE_EMPTY ) + while ( !rq->plugged && !list_empty(&rq->queue_head)) { - if ( (req = CURRENT) == NULL ) goto out; + if ( (req = blkdev_entry_next_request(&rq->queue_head)) == NULL ) + goto out; DPRINTK("do_xlblk_request %p: cmd %i, sec %lx, (%li/%li) bh:%p\n", req, req->cmd, req->sector, @@ -351,7 +422,7 @@ static struct block_device_operations xenolinux_block_fops = static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs) { - int i; + int i; unsigned long flags; struct buffer_head *bh; @@ -383,10 +454,18 @@ static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs) resp_cons = i; /* KAF: We can push work down at this point. We have the lock. */ - /* aho: okay, so this is a bit of a hack. we'll kick every queue... */ - do_xlblk_request(BLK_DEFAULT_QUEUE(XLBLK_MAJOR)); - do_xlseg_requestX(BLK_DEFAULT_QUEUE(XLSEG_MAJOR)); - + 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)); + } + spin_unlock_irqrestore(&io_request_lock, flags); } @@ -419,143 +498,54 @@ int __init xlblk_init(void) BUG(); HYPERVISOR_block_io_op(); while ( blk_ring->resp_prod != 1 ) barrier(); - printk (KERN_ALERT "xhd block device probe:\n"); 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; + } } - - 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 */ - for (i = 0; i < XLBLK_MAX; i++) { - xlblk_blk_size[i] = xlblk_disk_info.disks[0].capacity; - xlblk_blksize_size[i] = 512; - xlblk_hardsect_size[i] = 512; - xlblk_max_sectors[i] = 128; - } - xlblk_read_ahead = 8; - - 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; - - blk_init_queue(BLK_DEFAULT_QUEUE(xlblk_major), do_xlblk_request); - - /* - * Turn off barking 'headactive' mode. We dequeue buffer heads as - * soon as we pass them down to Xen. - */ - blk_queue_headactive(BLK_DEFAULT_QUEUE(xlblk_major), 0); - xlblk_ide_register_disk(0, xlblk_disk_info.disks[0].capacity); - - printk(KERN_ALERT - "XenoLinux Virtual Block Device Driver installed [device: %d]\n", - xlblk_major); return 0; fail: 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; - gd->major_name = XLBLK_MAJOR_NAME; - gd->minor_shift = IDE_PARTN_BITS; - gd->max_p = 1<<IDE_PARTN_BITS; - gd->nr_real = units; - gd->real_devices = NULL; - gd->next = NULL; - gd->fops = &xenolinux_block_fops; - 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); - - xlblk_disk_info.disks[idx].gendisk = gd; - - register_disk(gd, MKDEV(xlblk_major, 0), 1<<IDE_PARTN_BITS, - &xenolinux_block_fops, capacity); - - { - int loop = 0; - printk (KERN_ALERT "Partition Table: (capacity: %lx)\n", capacity); - for (loop = 0; loop < minors; loop++) - { - if (gd->part[loop].start_sect && gd->part[loop].nr_sects) - { - printk (KERN_ALERT - " %2d: 0x%6lx %8ld 0x%6lx %7ld\n", loop, - gd->part[loop].start_sect, gd->part[loop].start_sect, - gd->part[loop].nr_sects, gd->part[loop].nr_sects); - } - } - } - - 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; + int i; - if (blksize_size[xlblk_major]) - kfree(blksize_size[xlblk_major]); - blksize_size[xlblk_major] = NULL; + 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; + } - if (hardsect_size[xlblk_major]) - kfree(hardsect_size[xlblk_major]); - hardsect_size[xlblk_major] = NULL; - - /* XXX: free each gendisk */ - if (unregister_blkdev(xlblk_major, "block")) - printk(KERN_ALERT - "XenoLinux Virtual Block Device Driver uninstalled w/ errs\n"); - else - printk(KERN_ALERT - "XenoLinux Virtual Block Device Driver uninstalled\n"); + } return; } |