diff options
25 files changed, 1535 insertions, 977 deletions
@@ -251,6 +251,7 @@ 3ddb79be04dyXzyXqDbMRS_1funwXQ xen/drivers/block/blkpg.c 3ddb79beME_0abStePF6fU8XLuQnWw xen/drivers/block/elevator.c 3ddb79beNQVrdGyoI4njXhgAjD6a4A xen/drivers/block/genhd.c +3e677183FxihZVsJDCnvV2S0-FEZyA xen/drivers/block/grok.c 3ddb79beyWwLRP_BiM2t1JKgr_plEw xen/drivers/block/ll_rw_blk.c 3e4a8cb7RhubVgsPwO7cK0pgAN8WCQ xen/drivers/block/xen_block.c 3e5d129asHNyZOjBKTkqs-9AFzxemA xen/drivers/block/xen_segment.c @@ -477,6 +478,8 @@ 3e5a4e65iHEuC5sjFhj42XALYbLVRw xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/Makefile 3e5a4e65pP5spJErBW69pJxSSdK9RA xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c 3e5a4e65GtI9JZRAjuRdXaxt_4ohyQ xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block_test.c +3e677190SjkzJIvFifRVeYpIZOCtYA xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_ide.c +3e677193nOKKTLJzcAu4SYdbZaia8g xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_scsi.c 3e676eb5RXnHzSHgA1BvM0B1aIm4qg xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment.c 3e5d129aDldt6geU2-2SzBae34sQzg xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment_proc.c 3e5a4e65G3e2s0ghPMgiJ-gBTUJ0uQ xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/console/Makefile diff --git a/xen/Rules.mk b/xen/Rules.mk index 13a57ed550..d0feffd7f9 100644 --- a/xen/Rules.mk +++ b/xen/Rules.mk @@ -20,7 +20,7 @@ ALL_OBJS += $(BASEDIR)/drivers/pci/driver.o ALL_OBJS += $(BASEDIR)/drivers/net/driver.o ALL_OBJS += $(BASEDIR)/drivers/block/driver.o ALL_OBJS += $(BASEDIR)/drivers/ide/driver.o -#ALL_OBJS += $(BASEDIR)/drivers/scsi/driver.o +ALL_OBJS += $(BASEDIR)/drivers/scsi/driver.o ALL_OBJS += $(BASEDIR)/arch/$(ARCH)/arch.o HOSTCC = gcc diff --git a/xen/drivers/block/genhd.c b/xen/drivers/block/genhd.c index 427c2cb312..89d892ad47 100644 --- a/xen/drivers/block/genhd.c +++ b/xen/drivers/block/genhd.c @@ -193,6 +193,67 @@ out: } #endif +/* XXX SMH: stuff from fs/partitions dumped here temporarily */ + + +/* + * This function will re-read the partition tables for a given device, + * and set things back up again. There are some important caveats, + * however. You must ensure that no one is using the device, and no one + * can start using the device while this function is being executed. + * + * Much of the cleanup from the old partition tables should have already been + * done + */ +void register_disk(struct gendisk *gdev, kdev_t dev, unsigned minors, + struct block_device_operations *ops, long size) +{ + if (!gdev) + return; + grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size); +} + +void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size) +{ + int i; + int first_minor = drive << dev->minor_shift; + int end_minor = first_minor + dev->max_p; + + if(!dev->sizes) + blk_size[dev->major] = NULL; + + dev->part[first_minor].nr_sects = size; +#ifdef DEVFS_MUST_DIE + /* No such device or no minors to use for partitions */ + if ( !size && dev->flags && (dev->flags[drive] & GENHD_FL_REMOVABLE) ) + devfs_register_partitions (dev, first_minor, 0); +#endif + + if (!size || minors == 1) + return; + + if (dev->sizes) { + dev->sizes[first_minor] = size >> (BLOCK_SIZE_BITS - 9); + for (i = first_minor + 1; i < end_minor; i++) + dev->sizes[i] = 0; + } + blk_size[dev->major] = dev->sizes; +#if 0 + /* XXX SMH: don't actually check partition details yet */ + check_partition(dev, MKDEV(dev->major, first_minor), 1 + first_minor); +#endif + + /* + * We need to set the sizes array before we will be able to access + * any of the partitions on this device. + */ + if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */ + for (i = first_minor; i < end_minor; i++) + dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9); + } +} + + extern int blk_dev_init(void); extern int net_dev_init(void); diff --git a/xen/drivers/block/grok.c b/xen/drivers/block/grok.c new file mode 100644 index 0000000000..94f6df8869 --- /dev/null +++ b/xen/drivers/block/grok.c @@ -0,0 +1,39 @@ +void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size) +{ + int i; + int first_minor = drive << dev->minor_shift; + int end_minor = first_minor + dev->max_p; + + if(!dev->sizes) + blk_size[dev->major] = NULL; + + dev->part[first_minor].nr_sects = size; +#ifdef DEVFS_MUST_DIE + /* No such device or no minors to use for partitions */ + if ( !size && dev->flags && (dev->flags[drive] & GENHD_FL_REMOVABLE) ) + devfs_register_partitions (dev, first_minor, 0); +#endif + + if (!size || minors == 1) + return; + + if (dev->sizes) { + dev->sizes[first_minor] = size >> (BLOCK_SIZE_BITS - 9); + for (i = first_minor + 1; i < end_minor; i++) + dev->sizes[i] = 0; + } + blk_size[dev->major] = dev->sizes; +#if 0 + /* XXX SMH: don't actually check partition details yet */ + check_partition(dev, MKDEV(dev->major, first_minor), 1 + first_minor); +#endif + + /* + * We need to set the sizes array before we will be able to access + * any of the partitions on this device. + */ + if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */ + for (i = first_minor; i < end_minor; i++) + dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9); + } +} diff --git a/xen/drivers/block/xen_block.c b/xen/drivers/block/xen_block.c index 0e6a82ccc3..a0e3d51059 100644 --- a/xen/drivers/block/xen_block.c +++ b/xen/drivers/block/xen_block.c @@ -240,23 +240,23 @@ static void dispatch_debug_block_io(struct task_struct *p, int index) static void dispatch_create_segment(struct task_struct *p, int index) { - blk_ring_t *blk_ring = p->blk_ring_base; - xv_disk_t *xvd; - int result; - - if (p->domain != 0) - { - printk (KERN_ALERT "dispatch_create_segment called by dom%d\n", p->domain); - make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_SEG_CREATE, 1); - return; - } + blk_ring_t *blk_ring = p->blk_ring_base; + xv_disk_t *xvd; + int result; + + if (p->domain != 0) + { + DPRINTK("dispatch_create_segment called by dom%d\n", p->domain); + make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_SEG_CREATE, 1); + return; + } - xvd = phys_to_virt((unsigned long)blk_ring->ring[index].req.buffer); - result = xen_segment_create(xvd); + xvd = phys_to_virt((unsigned long)blk_ring->ring[index].req.buffer); + result = xen_segment_create(xvd); - make_response(p, blk_ring->ring[index].req.id, - XEN_BLOCK_SEG_CREATE, result); - return; + make_response(p, blk_ring->ring[index].req.id, + XEN_BLOCK_SEG_CREATE, result); + return; } static void dispatch_delete_segment(struct task_struct *p, int index) @@ -268,12 +268,16 @@ static void dispatch_probe_blk(struct task_struct *p, int index) { extern void ide_probe_devices(xen_disk_info_t *xdi, int *count, drive_t xdrives[]); + extern void scsi_probe_devices(xen_disk_info_t *xdi, int *count, + drive_t xdrives[]); + blk_ring_t *blk_ring = p->blk_ring_base; xen_disk_info_t *xdi; xdi = phys_to_virt((unsigned long)blk_ring->ring[index].req.buffer); + ide_probe_devices(xdi, &num_xdrives, xdrives); - /* scsi_probe_devices(xdi, &num_xdrives, xdrives); */ /* future */ + scsi_probe_devices(xdi, &num_xdrives, xdrives); make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_PROBE_BLK, 0); } @@ -371,39 +375,38 @@ static void dispatch_rw_block_io(struct task_struct *p, int index) xen_device = blk_ring->ring[index].req.device; if (IS_XHD_MAJOR(xen_device)) { - if (xen_device == XHDA_MAJOR) phys_device = MKDEV(IDE0_MAJOR, 0); - else if (xen_device == XHDB_MAJOR) phys_device = MKDEV(IDE1_MAJOR, 0); - else if (xen_device == XHDC_MAJOR) phys_device = MKDEV(IDE2_MAJOR, 0); - else if (xen_device == XHDD_MAJOR) phys_device = MKDEV(IDE3_MAJOR, 0); - else - { - printk (KERN_ALERT "dispatch_rw_block_io: unknown device %d\n", - xen_device); - BUG(); - } - - block_number = blk_ring->ring[index].req.block_number; - sector_number = blk_ring->ring[index].req.sector_number; + if (xen_device == XHDA_MAJOR) phys_device = MKDEV(IDE0_MAJOR, 0); + else if (xen_device == XHDB_MAJOR) phys_device = MKDEV(IDE1_MAJOR, 0); + else if (xen_device == XHDC_MAJOR) phys_device = MKDEV(IDE2_MAJOR, 0); + else if (xen_device == XHDD_MAJOR) phys_device = MKDEV(IDE3_MAJOR, 0); + else + { + printk(KERN_ALERT "dispatch_rw_block_io: unknown device %d\n", + xen_device); + BUG(); + } + + block_number = blk_ring->ring[index].req.block_number; + sector_number = blk_ring->ring[index].req.sector_number; } else if (IS_VHD_MAJOR(xen_device)) { - int s; - if (s = xen_segment_map_request(&phys_device, &block_number, - §or_number, - p, operation, xen_device, - blk_ring->ring[index].req.block_number, - blk_ring->ring[index].req.sector_number)) - { - printk ("dispatch_rw_block_io: xen_segment_map_request status: %d\n", - s); - goto bad_descriptor; - } + int s; + if (s = xen_segment_map_request(&phys_device, &block_number, + §or_number, + p, operation, xen_device, + blk_ring->ring[index].req.block_number, + blk_ring->ring[index].req.sector_number)) + { + DPRINTK("dispatch_rw_block_io: xen_seg_map_request status: %d\n", s); + goto bad_descriptor; + } } else { - printk (KERN_ALERT "dispatch_rw_block_io: unknown device %d\n", - xen_device); - BUG(); + printk (KERN_ALERT "dispatch_rw_block_io: unknown device %d\n", + xen_device); + BUG(); } bh->b_blocknr = block_number; @@ -433,9 +436,8 @@ static void dispatch_rw_block_io(struct task_struct *p, int index) return; bad_descriptor: - printk (KERN_ALERT "dispatch rw blockio bad descriptor\n"); + DPRINTK("dispatch rw blockio bad descriptor\n"); make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_READ, 1); - return; } @@ -468,23 +470,23 @@ static void make_response(struct task_struct *p, void *id, static void dump_blockq(u_char key, void *dev_id, struct pt_regs *regs) { - struct task_struct *p; - blk_ring_t *blk_ring ; + struct task_struct *p; + blk_ring_t *blk_ring ; - printk("Dumping block queue stats: nr_pending = %d\n", - atomic_read(&nr_pending)); + printk("Dumping block queue stats: nr_pending = %d\n", + atomic_read(&nr_pending)); - p = current->next_task; - do - { - printk (KERN_ALERT "Domain: %d\n", p->domain); - blk_ring = p->blk_ring_base; + p = current->next_task; + do + { + printk (KERN_ALERT "Domain: %d\n", p->domain); + blk_ring = p->blk_ring_base; - printk(" req_prod:%d, resp_prod:%d, req_cons:%d\n", - blk_ring->req_prod, blk_ring->resp_prod, p->blk_req_cons); + printk(" req_prod:%d, resp_prod:%d, req_cons:%d\n", + blk_ring->req_prod, blk_ring->resp_prod, p->blk_req_cons); - p = p->next_task; - } while (p != current); + p = p->next_task; + } while (p != current); } /* Start-of-day initialisation for a new domain. */ diff --git a/xen/drivers/ide/ide.c b/xen/drivers/ide/ide.c index 1db4e34834..84edfa28d6 100644 --- a/xen/drivers/ide/ide.c +++ b/xen/drivers/ide/ide.c @@ -183,12 +183,6 @@ int unregister_blkdev(unsigned int major, const char * name) { return 0; } int invalidate_device(kdev_t dev, int do_sync) { return 0; } /* fs/buffer.c... */ void invalidate_bdev(struct block_device *bdev, int destroy_dirty_buffers) { } -/* fs/partitions/check.c... */ -void grok_partitions(struct gendisk *dev, int drive, - unsigned minors, long size) { } -void register_disk(struct gendisk *dev, kdev_t first, - unsigned minors, struct block_device_operations *ops, - long size) { } /* fs/devices.c... */ const char * kdevname(kdev_t dev) { return NULL; } /* End of XXXXXX region */ diff --git a/xen/drivers/scsi/aacraid/aachba.c b/xen/drivers/scsi/aacraid/aachba.c index 21fc4259b8..198e37cace 100644 --- a/xen/drivers/scsi/aacraid/aachba.c +++ b/xen/drivers/scsi/aacraid/aachba.c @@ -253,7 +253,6 @@ int aac_get_containers(struct aac_dev *dev) dinfo->count = cpu_to_le32(index); dinfo->type = cpu_to_le32(FT_FILESYS); - printk("aac_get_container: getting info for container %d\n", index); status = fib_send(ContainerCommand, fibptr, sizeof (struct aac_query_mount), diff --git a/xen/drivers/scsi/aacraid/aacraid.h b/xen/drivers/scsi/aacraid/aacraid.h index 1f9838436d..ce6566bcc1 100644 --- a/xen/drivers/scsi/aacraid/aacraid.h +++ b/xen/drivers/scsi/aacraid/aacraid.h @@ -1410,7 +1410,7 @@ unsigned int aac_response_normal(struct aac_queue * q); unsigned int aac_command_normal(struct aac_queue * q); #ifdef TRY_TASKLET extern struct tasklet_struct aac_command_tasklet; -int aac_command_thread(unsigned long data); +void aac_command_thread(unsigned long data); #else int aac_command_thread(struct aac_dev * dev); #endif diff --git a/xen/drivers/scsi/aacraid/comminit.c b/xen/drivers/scsi/aacraid/comminit.c index 29a3dba28e..b4681a473b 100644 --- a/xen/drivers/scsi/aacraid/comminit.c +++ b/xen/drivers/scsi/aacraid/comminit.c @@ -325,10 +325,9 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) } memset(dev->queues, 0, sizeof(struct aac_queue_block)); - printk("aac_init_adapater, dev is %p\n", dev); if (aac_comm_init(dev)<0) return NULL; - printk("aac_init_adapater, dev->init is %p\n", dev->init); + /* * Initialize the list of fibs */ diff --git a/xen/drivers/scsi/aacraid/commsup.c b/xen/drivers/scsi/aacraid/commsup.c index 7d84ad241c..a1fabe7b19 100644 --- a/xen/drivers/scsi/aacraid/commsup.c +++ b/xen/drivers/scsi/aacraid/commsup.c @@ -535,12 +535,13 @@ int fib_send(u16 command, struct fib * fibptr, unsigned long size, int priority * do_softirq() after scheduling the tasklet, as long as we * are _sure_ we hold no locks here... */ - printk("about to softirq aac_command_thread...\n"); +// printk("about to softirq aac_command_thread...\n"); while (!fibptr->done) { tasklet_schedule(&aac_command_tasklet); - mdelay(100); + do_softirq(); /* force execution */ +// mdelay(100); } - printk("back from softirq cmd thread and fibptr->done!\n"); +// printk("back from softirq cmd thread and fibptr->done!\n"); #else printk("about to bail at aac_command_thread...\n"); while (!fibptr->done) { @@ -843,11 +844,12 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) */ #ifndef TRY_TASKLET -DECLARE_TASKLET_DISABLED(aac_command_tasklet, aac_command_thread, 0); int aac_command_thread(struct aac_dev * dev) { #else -int aac_command_thread(unsigned long data) +DECLARE_TASKLET_DISABLED(aac_command_tasklet, aac_command_thread, 0); +void aac_command_thread(unsigned long data) +#define return(_x) return { struct aac_dev *dev = (struct aac_dev *)data; #endif @@ -863,9 +865,8 @@ int aac_command_thread(unsigned long data) /* * We can only have one thread per adapter for AIF's. */ - printk("aac_command_'thread': entered.\n"); if (dev->aif_thread) - return -EINVAL; + return(-EINVAL); #if 0 /* @@ -888,9 +889,7 @@ int aac_command_thread(unsigned long data) // while(1) { - printk("aac_command_thread: in 'loop'\n"); spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags); - printk("flags = %x\n", flags); while(!list_empty(&(queues->queue[HostNormCmdQueue].cmdq))) { struct list_head *entry; struct aac_aifcmd * aifcmd; @@ -905,7 +904,6 @@ int aac_command_thread(unsigned long data) spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock,flags); fib = list_entry(entry, struct hw_fib, header.FibLinks); - printk("aac_command_thread: got fib \n"); /* * We will process the FIB here or pass it to a * worker thread that is TBD. We Really can't @@ -923,7 +921,6 @@ int aac_command_thread(unsigned long data) */ aifcmd = (struct aac_aifcmd *) fib->data; if (aifcmd->command == le16_to_cpu(AifCmdDriverNotify)) { - printk("aac_command_thread: handling aif... :-( \n"); aac_handle_aif(dev, &fibptr); } else { /* The u32 here is important and intended. We are using @@ -1024,5 +1021,5 @@ int aac_command_thread(unsigned long data) dev->aif_thread = 0; #endif - return 0; + return(0); } diff --git a/xen/drivers/scsi/aacraid/linit.c b/xen/drivers/scsi/aacraid/linit.c index b5026d9065..9c3cffda80 100644 --- a/xen/drivers/scsi/aacraid/linit.c +++ b/xen/drivers/scsi/aacraid/linit.c @@ -338,7 +338,6 @@ static int aac_detect(Scsi_Host_Template *template) #endif template->present = aac_count; /* # of cards of this type found */ - printk(KERN_DEBUG "aac_detect: returning %d\n", aac_count); return aac_count; } @@ -461,7 +460,7 @@ static int aac_biosparm(Scsi_Disk *disk, kdev_t dev, int *geom) struct buffer_head * buf; dprintk((KERN_DEBUG "aac_biosparm.\n")); - + /* * Assuming extended translation is enabled - #REVISIT# */ @@ -499,7 +498,6 @@ static int aac_biosparm(Scsi_Disk *disk, kdev_t dev, int *geom) * table entry whose end_head matches one of the standard geometry * translations ( 64/32, 128/32, 255/63 ). */ -#endif if(*(unsigned short *)(buf->b_data + 0x1fe) == cpu_to_le16(0xaa55)) @@ -560,7 +558,6 @@ static int aac_biosparm(Scsi_Disk *disk, kdev_t dev, int *geom) param->heads, param->sectors)); } } -#if 0 brelse(buf); #endif return 0; diff --git a/xen/drivers/scsi/aacraid/rx.c b/xen/drivers/scsi/aacraid/rx.c index e79ad49e74..8d4685ba0f 100644 --- a/xen/drivers/scsi/aacraid/rx.c +++ b/xen/drivers/scsi/aacraid/rx.c @@ -311,7 +311,7 @@ static void aac_rx_start_adapter(struct aac_dev *dev) struct aac_init *init; init = dev->init; - printk("aac_rx_start: dev is %p, init is %p\n", dev, init); + init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ); /* * Tell the adapter we are back and up and running so it will scan diff --git a/xen/drivers/scsi/scsi.c b/xen/drivers/scsi/scsi.c index 85a59f54ac..46ddcb77b1 100644 --- a/xen/drivers/scsi/scsi.c +++ b/xen/drivers/scsi/scsi.c @@ -55,6 +55,10 @@ /*#include <xeno/smp_lock.h>*/ /*#include <xeno/completion.h>*/ +/* for xeno scsi_probe() stuff... maybe punt somewhere else? */ +#include <hypervisor-ifs/block.h> +#include <xeno/blkdev.h> + #define __KERNEL_SYSCALLS__ /*#include <xeno/unistd.h>*/ @@ -240,7 +244,14 @@ static void scsi_wait_done(Scsi_Cmnd * SCpnt) if (req->waiting != NULL) { complete(req->waiting); } +#else + /* XXX SMH: just use a flag to signal completion; caller spins */ + if (*(int *)(req->waiting) != 0) { +// printk("scsi_wait_done: flipping wait status on req %p\n", req); + *(int *)(req->waiting) = 0; + } #endif + } /* @@ -317,15 +328,8 @@ void scsi_release_request(Scsi_Request * req) { if( req->sr_command != NULL ) { -#ifdef SMH_DEBUG - printk("scsi_release_request: req->sr_command = %p\n", - req->sr_command); -#endif scsi_release_command(req->sr_command); req->sr_command = NULL; -#ifdef SMHHACK - req->freeaddr = 0x1234; -#endif } kfree(req); @@ -361,225 +365,227 @@ void scsi_release_request(Scsi_Request * req) Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait, int interruptable) { - struct Scsi_Host *host; - Scsi_Cmnd *SCpnt = NULL; - Scsi_Device *SDpnt; - unsigned long flags; - - if (!device) - panic("No device passed to scsi_allocate_device().\n"); - - host = device->host; - - spin_lock_irqsave(&device_request_lock, flags); - - while (1 == 1) { - SCpnt = NULL; - if (!device->device_blocked) { - if (device->single_lun) { - /* - * FIXME(eric) - this is not at all optimal. Given that - * single lun devices are rare and usually slow - * (i.e. CD changers), this is good enough for now, but - * we may want to come back and optimize this later. - * - * Scan through all of the devices attached to this - * host, and see if any are active or not. If so, - * we need to defer this command. - * - * We really need a busy counter per device. This would - * allow us to more easily figure out whether we should - * do anything here or not. - */ - for (SDpnt = host->host_queue; - SDpnt; - SDpnt = SDpnt->next) { - /* - * Only look for other devices on the same bus - * with the same target ID. - */ - if (SDpnt->channel != device->channel - || SDpnt->id != device->id - || SDpnt == device) { - continue; - } - if( atomic_read(&SDpnt->device_active) != 0) - { - break; - } - } - if (SDpnt) { - /* - * Some other device in this cluster is busy. - * If asked to wait, we need to wait, otherwise - * return NULL. - */ - SCpnt = NULL; - goto busy; - } - } - /* - * Now we can check for a free command block for this device. - */ - for (SCpnt = device->device_queue; SCpnt; SCpnt = SCpnt->next) { - if (SCpnt->request.rq_status == RQ_INACTIVE) - break; - } - } - /* - * If we couldn't find a free command block, and we have been - * asked to wait, then do so. - */ - if (SCpnt) { - break; - } - busy: - /* - * If we have been asked to wait for a free block, then - * wait here. - */ - if (wait) { - printk("XXX smh: scsi cannot wait for free cmd block.\n"); - BUG(); + struct Scsi_Host *host; + Scsi_Cmnd *SCpnt = NULL; + Scsi_Device *SDpnt; + unsigned long flags; + + if (!device) + panic("No device passed to scsi_allocate_device().\n"); + + host = device->host; + + spin_lock_irqsave(&device_request_lock, flags); + + while (1 == 1) { + SCpnt = NULL; + if (!device->device_blocked) { + if (device->single_lun) { + /* + * FIXME(eric) - this is not at all optimal. Given that + * single lun devices are rare and usually slow + * (i.e. CD changers), this is good enough for now, but + * we may want to come back and optimize this later. + * + * Scan through all of the devices attached to this + * host, and see if any are active or not. If so, + * we need to defer this command. + * + * We really need a busy counter per device. This would + * allow us to more easily figure out whether we should + * do anything here or not. + */ + for (SDpnt = host->host_queue; + SDpnt; + SDpnt = SDpnt->next) { + /* + * Only look for other devices on the same bus + * with the same target ID. + */ + if (SDpnt->channel != device->channel + || SDpnt->id != device->id + || SDpnt == device) { + continue; + } + if( atomic_read(&SDpnt->device_active) != 0) + { + break; + } + } + if (SDpnt) { + /* + * Some other device in this cluster is busy. + * If asked to wait, we need to wait, otherwise + * return NULL. + */ + SCpnt = NULL; + goto busy; + } + } + /* + * Now we can check for a free command block for this device. + */ + for (SCpnt = device->device_queue; SCpnt; SCpnt = SCpnt->next) { + if (SCpnt->request.rq_status == RQ_INACTIVE) + break; + } + } + /* + * If we couldn't find a free command block, and we have been + * asked to wait, then do so. + */ + if (SCpnt) { + break; + } + busy: + /* + * If we have been asked to wait for a free block, then + * wait here. + */ + if (wait) { + printk("XXX smh: scsi cannot wait for free cmd block.\n"); + BUG(); #if 0 - DECLARE_WAITQUEUE(wait, current); - - /* - * We need to wait for a free commandblock. We need to - * insert ourselves into the list before we release the - * lock. This way if a block were released the same - * microsecond that we released the lock, the call - * to schedule() wouldn't block (well, it might switch, - * but the current task will still be schedulable. - */ - add_wait_queue(&device->scpnt_wait, &wait); - if( interruptable ) { - set_current_state(TASK_INTERRUPTIBLE); - } else { - set_current_state(TASK_UNINTERRUPTIBLE); - } - - spin_unlock_irqrestore(&device_request_lock, flags); - - /* - * This should block until a device command block - * becomes available. - */ - schedule(); - - spin_lock_irqsave(&device_request_lock, flags); - - remove_wait_queue(&device->scpnt_wait, &wait); - /* - * FIXME - Isn't this redundant?? Someone - * else will have forced the state back to running. - */ - set_current_state(TASK_RUNNING); - /* - * In the event that a signal has arrived that we need - * to consider, then simply return NULL. Everyone - * that calls us should be prepared for this - * possibility, and pass the appropriate code back - * to the user. - */ - if( interruptable ) { - if (signal_pending(current)) { - spin_unlock_irqrestore(&device_request_lock, flags); - return NULL; - } - } + DECLARE_WAITQUEUE(wait, current); + + /* + * We need to wait for a free commandblock. We need to + * insert ourselves into the list before we release the + * lock. This way if a block were released the same + * microsecond that we released the lock, the call + * to schedule() wouldn't block (well, it might switch, + * but the current task will still be schedulable. + */ + add_wait_queue(&device->scpnt_wait, &wait); + if( interruptable ) { + set_current_state(TASK_INTERRUPTIBLE); + } else { + set_current_state(TASK_UNINTERRUPTIBLE); + } + + spin_unlock_irqrestore(&device_request_lock, flags); + + /* + * This should block until a device command block + * becomes available. + */ + schedule(); + + spin_lock_irqsave(&device_request_lock, flags); + + remove_wait_queue(&device->scpnt_wait, &wait); + /* + * FIXME - Isn't this redundant?? Someone + * else will have forced the state back to running. + */ + set_current_state(TASK_RUNNING); + /* + * In the event that a signal has arrived that we need + * to consider, then simply return NULL. Everyone + * that calls us should be prepared for this + * possibility, and pass the appropriate code back + * to the user. + */ + if( interruptable ) { + if (signal_pending(current)) { + spin_unlock_irqrestore(&device_request_lock, flags); + return NULL; + } + } #endif - } else { - spin_unlock_irqrestore(&device_request_lock, flags); - return NULL; - } - } - - SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.waiting = NULL; /* And no one is waiting for this + } else { + spin_unlock_irqrestore(&device_request_lock, flags); + return NULL; + } + } + + SCpnt->request.rq_status = RQ_SCSI_BUSY; + SCpnt->request.waiting = NULL; /* And no one is waiting for this * to complete */ - atomic_inc(&SCpnt->host->host_active); - atomic_inc(&SCpnt->device->device_active); - - SCpnt->buffer = NULL; - SCpnt->bufflen = 0; - SCpnt->request_buffer = NULL; - SCpnt->request_bufflen = 0; - - SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ - SCpnt->old_use_sg = 0; - SCpnt->transfersize = 0; /* No default transfer size */ - SCpnt->cmd_len = 0; - - SCpnt->sc_data_direction = SCSI_DATA_UNKNOWN; - SCpnt->sc_request = NULL; - SCpnt->sc_magic = SCSI_CMND_MAGIC; - - SCpnt->result = 0; - SCpnt->underflow = 0; /* Do not flag underflow conditions */ - SCpnt->old_underflow = 0; - SCpnt->resid = 0; - SCpnt->state = SCSI_STATE_INITIALIZING; - SCpnt->owner = SCSI_OWNER_HIGHLEVEL; - - spin_unlock_irqrestore(&device_request_lock, flags); - - SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", - SCpnt->target, - atomic_read(&SCpnt->host->host_active))); - - return SCpnt; + atomic_inc(&SCpnt->host->host_active); + atomic_inc(&SCpnt->device->device_active); + + SCpnt->buffer = NULL; + SCpnt->bufflen = 0; + SCpnt->request_buffer = NULL; + SCpnt->request_bufflen = 0; + + SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ + SCpnt->old_use_sg = 0; + SCpnt->transfersize = 0; /* No default transfer size */ + SCpnt->cmd_len = 0; + + SCpnt->sc_data_direction = SCSI_DATA_UNKNOWN; + SCpnt->sc_request = NULL; + SCpnt->sc_magic = SCSI_CMND_MAGIC; + + SCpnt->result = 0; + SCpnt->underflow = 0; /* Do not flag underflow conditions */ + SCpnt->old_underflow = 0; + SCpnt->resid = 0; + SCpnt->state = SCSI_STATE_INITIALIZING; + SCpnt->owner = SCSI_OWNER_HIGHLEVEL; + + spin_unlock_irqrestore(&device_request_lock, flags); + + SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", + SCpnt->target, + atomic_read(&SCpnt->host->host_active))); + + return SCpnt; } inline void __scsi_release_command(Scsi_Cmnd * SCpnt) { - unsigned long flags; - Scsi_Device * SDpnt; - - spin_lock_irqsave(&device_request_lock, flags); - - SDpnt = SCpnt->device; - - SCpnt->request.rq_status = RQ_INACTIVE; - SCpnt->state = SCSI_STATE_UNUSED; - SCpnt->owner = SCSI_OWNER_NOBODY; - atomic_dec(&SCpnt->host->host_active); - atomic_dec(&SDpnt->device_active); - - SCSI_LOG_MLQUEUE(5, printk("Deactivating command for device %d (active=%d, failed=%d)\n", - SCpnt->target, - atomic_read(&SCpnt->host->host_active), - SCpnt->host->host_failed)); - if (SCpnt->host->host_failed != 0) { - SCSI_LOG_ERROR_RECOVERY(5, printk("Error handler thread %d %d\n", - SCpnt->host->in_recovery, - SCpnt->host->eh_active)); - } - /* - * If the host is having troubles, then look to see if this was the last - * command that might have failed. If so, wake up the error handler. - */ - if (SCpnt->host->in_recovery - && !SCpnt->host->eh_active - && SCpnt->host->host_busy == SCpnt->host->host_failed) { - SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n", - atomic_read(&SCpnt->host->eh_wait->count))); + unsigned long flags; + Scsi_Device * SDpnt; + + spin_lock_irqsave(&device_request_lock, flags); + + SDpnt = SCpnt->device; + + SCpnt->request.rq_status = RQ_INACTIVE; + SCpnt->state = SCSI_STATE_UNUSED; + SCpnt->owner = SCSI_OWNER_NOBODY; + atomic_dec(&SCpnt->host->host_active); + atomic_dec(&SDpnt->device_active); + + SCSI_LOG_MLQUEUE(5, printk( + "Deactivating command for device %d (active=%d, failed=%d)\n", + SCpnt->target, + atomic_read(&SCpnt->host->host_active), + SCpnt->host->host_failed)); + if (SCpnt->host->host_failed != 0) { + SCSI_LOG_ERROR_RECOVERY(5, printk("Error handler thread %d %d\n", + SCpnt->host->in_recovery, + SCpnt->host->eh_active)); + } + /* + * If the host is having troubles, then look to see if this was the last + * command that might have failed. If so, wake up the error handler. + */ + if (SCpnt->host->in_recovery + && !SCpnt->host->eh_active + && SCpnt->host->host_busy == SCpnt->host->host_failed) { #if 0 - up(SCpnt->host->eh_wait); + SCSI_LOG_ERROR_RECOVERY(5, printk( + "Waking error handler thread (%d)\n", + atomic_read(&SCpnt->host->eh_wait->count))); + up(SCpnt->host->eh_wait); #endif - } - - spin_unlock_irqrestore(&device_request_lock, flags); - + } + + spin_unlock_irqrestore(&device_request_lock, flags); + #if 0 - /* - * Wake up anyone waiting for this device. Do this after we - * have released the lock, as they will need it as soon as - * they wake up. - */ - wake_up(&SDpnt->scpnt_wait); + /* + * Wake up anyone waiting for this device. Do this after we + * have released the lock, as they will need it as soon as + * they wake up. + */ + wake_up(&SDpnt->scpnt_wait); #endif - + } /* @@ -611,21 +617,21 @@ inline void __scsi_release_command(Scsi_Cmnd * SCpnt) */ void scsi_release_command(Scsi_Cmnd * SCpnt) { - request_queue_t *q; - Scsi_Device * SDpnt; - - SDpnt = SCpnt->device; - - __scsi_release_command(SCpnt); - - /* - * Finally, hit the queue request function to make sure that - * the device is actually busy if there are requests present. - * This won't block - if the device cannot take any more, life - * will go on. - */ - q = &SDpnt->request_queue; - scsi_queue_next_request(q, NULL); + request_queue_t *q; + Scsi_Device * SDpnt; + + SDpnt = SCpnt->device; + + __scsi_release_command(SCpnt); + + /* + * Finally, hit the queue request function to make sure that + * the device is actually busy if there are requests present. + * This won't block - if the device cannot take any more, life + * will go on. + */ + q = &SDpnt->request_queue; + scsi_queue_next_request(q, NULL); } /* @@ -640,153 +646,158 @@ void scsi_release_command(Scsi_Cmnd * SCpnt) int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt) { #ifdef DEBUG_DELAY - unsigned long clock; + unsigned long clock; #endif - struct Scsi_Host *host; - int rtn = 0; - unsigned long flags = 0; - unsigned long timeout; - - ASSERT_LOCK(&io_request_lock, 0); - + struct Scsi_Host *host; + int rtn = 0; + unsigned long flags = 0; + unsigned long timeout; + + ASSERT_LOCK(&io_request_lock, 0); + #if DEBUG - unsigned long *ret = 0; + unsigned long *ret = 0; #ifdef __mips__ - __asm__ __volatile__("move\t%0,$31":"=r"(ret)); + __asm__ __volatile__("move\t%0,$31":"=r"(ret)); #else - ret = __builtin_return_address(0); + ret = __builtin_return_address(0); #endif #endif - - host = SCpnt->host; - - /* Assign a unique nonzero serial_number. */ - if (++serial_number == 0) - serial_number = 1; - SCpnt->serial_number = serial_number; - SCpnt->pid = scsi_pid++; - - /* - * We will wait MIN_RESET_DELAY clock ticks after the last reset so - * we can avoid the drive not being ready. - */ - timeout = host->last_reset + MIN_RESET_DELAY; - - if (host->resetting && time_before(jiffies, timeout)) { - int ticks_remaining = timeout - jiffies; - /* - * NOTE: This may be executed from within an interrupt - * handler! This is bad, but for now, it'll do. The irq - * level of the interrupt handler has been masked out by the - * platform dependent interrupt handling code already, so the - * sti() here will not cause another call to the SCSI host's - * interrupt handler (assuming there is one irq-level per - * host). - */ - while (--ticks_remaining >= 0) - mdelay(1 + 999 / HZ); - host->resetting = 0; - } - if (host->hostt->use_new_eh_code) { - scsi_add_timer(SCpnt, SCpnt->timeout_per_command, scsi_times_out); - } else { + + host = SCpnt->host; + + /* Assign a unique nonzero serial_number. */ + if (++serial_number == 0) + serial_number = 1; + SCpnt->serial_number = serial_number; + SCpnt->pid = scsi_pid++; + + /* + * We will wait MIN_RESET_DELAY clock ticks after the last reset so + * we can avoid the drive not being ready. + */ + timeout = host->last_reset + MIN_RESET_DELAY; + + if (host->resetting && time_before(jiffies, timeout)) { + int ticks_remaining = timeout - jiffies; + /* + * NOTE: This may be executed from within an interrupt + * handler! This is bad, but for now, it'll do. The irq + * level of the interrupt handler has been masked out by the + * platform dependent interrupt handling code already, so the + * sti() here will not cause another call to the SCSI host's + * interrupt handler (assuming there is one irq-level per + * host). + */ + while (--ticks_remaining >= 0) + mdelay(1 + 999 / HZ); + host->resetting = 0; + } + if (host->hostt->use_new_eh_code) { + scsi_add_timer(SCpnt, SCpnt->timeout_per_command, scsi_times_out); + } else { #if 0 - scsi_add_timer(SCpnt, SCpnt->timeout_per_command, - scsi_old_times_out); + scsi_add_timer(SCpnt, SCpnt->timeout_per_command, + scsi_old_times_out); #endif - } - - /* - * We will use a queued command if possible, otherwise we will emulate the - * queuing and calling of completion function ourselves. - */ - SCSI_LOG_MLQUEUE(3, printk("scsi_dispatch_cmnd (host = %d, channel = %d, target = %d, " - "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n", - SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd, - SCpnt->buffer, SCpnt->bufflen, SCpnt->done)); - - SCpnt->state = SCSI_STATE_QUEUED; - SCpnt->owner = SCSI_OWNER_LOWLEVEL; - if (host->can_queue) { - SCSI_LOG_MLQUEUE(3, printk("queuecommand : routine at %p\n", - host->hostt->queuecommand)); - /* - * Use the old error handling code if we haven't converted the driver - * to use the new one yet. Note - only the new queuecommand variant - * passes a meaningful return value. - */ - if (host->hostt->use_new_eh_code) { - /* - * Before we queue this command, check if the command - * length exceeds what the host adapter can handle. - */ - if (CDB_SIZE(SCpnt) <= SCpnt->host->max_cmd_len) { - spin_lock_irqsave(&io_request_lock, flags); - rtn = host->hostt->queuecommand(SCpnt, scsi_done); - spin_unlock_irqrestore(&io_request_lock, flags); - if (rtn != 0) { - scsi_delete_timer(SCpnt); - scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY); - SCSI_LOG_MLQUEUE(3, printk("queuecommand : request rejected\n")); - } - } else { - SCSI_LOG_MLQUEUE(3, printk("queuecommand : command too long.\n")); - SCpnt->result = (DID_ABORT << 16); - spin_lock_irqsave(&io_request_lock, flags); - scsi_done(SCpnt); - spin_unlock_irqrestore(&io_request_lock, flags); - rtn = 1; - } - } else { - /* - * Before we queue this command, check if the command - * length exceeds what the host adapter can handle. - */ + } + + /* + * We will use a queued command if possible, otherwise we will emulate the + * queuing and calling of completion function ourselves. + */ + SCSI_LOG_MLQUEUE(3, printk( + "scsi_dispatch_cmnd (host = %d, channel = %d, target = %d, " + "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n", + SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd, + SCpnt->buffer, SCpnt->bufflen, SCpnt->done)); + + SCpnt->state = SCSI_STATE_QUEUED; + SCpnt->owner = SCSI_OWNER_LOWLEVEL; + if (host->can_queue) { + SCSI_LOG_MLQUEUE(3, printk("queuecommand : routine at %p\n", + host->hostt->queuecommand)); + /* + * Use the old error handling code if we haven't converted the driver + * to use the new one yet. Note - only the new queuecommand variant + * passes a meaningful return value. + */ + if (host->hostt->use_new_eh_code) { + /* + * Before we queue this command, check if the command + * length exceeds what the host adapter can handle. + */ + if (CDB_SIZE(SCpnt) <= SCpnt->host->max_cmd_len) { + spin_lock_irqsave(&io_request_lock, flags); + rtn = host->hostt->queuecommand(SCpnt, scsi_done); + spin_unlock_irqrestore(&io_request_lock, flags); + if (rtn != 0) { + scsi_delete_timer(SCpnt); + scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY); + SCSI_LOG_MLQUEUE(3, printk( + "queuecommand : request rejected\n")); + } + } else { + SCSI_LOG_MLQUEUE(3, printk( + "queuecommand : command too long.\n")); + SCpnt->result = (DID_ABORT << 16); + spin_lock_irqsave(&io_request_lock, flags); + scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + rtn = 1; + } + } else { + /* + * Before we queue this command, check if the command + * length exceeds what the host adapter can handle. + */ #if 0 - if (CDB_SIZE(SCpnt) <= SCpnt->host->max_cmd_len) { - spin_lock_irqsave(&io_request_lock, flags); - host->hostt->queuecommand(SCpnt, scsi_old_done); - spin_unlock_irqrestore(&io_request_lock, flags); - } else { - SCSI_LOG_MLQUEUE(3, printk("queuecommand : command too long.\n")); - SCpnt->result = (DID_ABORT << 16); - spin_lock_irqsave(&io_request_lock, flags); - scsi_old_done(SCpnt); - spin_unlock_irqrestore(&io_request_lock, flags); - rtn = 1; - } -#endif - - } - } else { - int temp; - - SCSI_LOG_MLQUEUE(3, printk("command() : routine at %p\n", host->hostt->command)); + if (CDB_SIZE(SCpnt) <= SCpnt->host->max_cmd_len) { spin_lock_irqsave(&io_request_lock, flags); - temp = host->hostt->command(SCpnt); - SCpnt->result = temp; -#ifdef DEBUG_DELAY + host->hostt->queuecommand(SCpnt, scsi_old_done); spin_unlock_irqrestore(&io_request_lock, flags); - clock = jiffies + 4 * HZ; - while (time_before(jiffies, clock)) { - barrier(); - cpu_relax(); - } - printk("done(host = %d, result = %04x) : routine at %p\n", - host->host_no, temp, host->hostt->command); + } else { + SCSI_LOG_MLQUEUE(3, printk( + "queuecommand : command too long.\n")); + SCpnt->result = (DID_ABORT << 16); spin_lock_irqsave(&io_request_lock, flags); + scsi_old_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + rtn = 1; + } #endif - if (host->hostt->use_new_eh_code) { - scsi_done(SCpnt); - } else { + + } + } else { + int temp; + + SCSI_LOG_MLQUEUE(3, printk( + "command() : routine at %p\n", host->hostt->command)); + spin_lock_irqsave(&io_request_lock, flags); + temp = host->hostt->command(SCpnt); + SCpnt->result = temp; +#ifdef DEBUG_DELAY + spin_unlock_irqrestore(&io_request_lock, flags); + clock = jiffies + 4 * HZ; + while (time_before(jiffies, clock)) { + barrier(); + cpu_relax(); + } + printk("done(host = %d, result = %04x) : routine at %p\n", + host->host_no, temp, host->hostt->command); + spin_lock_irqsave(&io_request_lock, flags); +#endif + if (host->hostt->use_new_eh_code) { + scsi_done(SCpnt); + } else { #if 0 - scsi_old_done(SCpnt); + scsi_old_done(SCpnt); #endif - } - spin_unlock_irqrestore(&io_request_lock, flags); - } - SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n")); - return rtn; + } + spin_unlock_irqrestore(&io_request_lock, flags); + } + SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n")); + return rtn; } #ifdef DEVFS_MUST_DIE @@ -806,6 +817,8 @@ void scsi_wait_req (Scsi_Request * SRpnt, const void *cmnd , { #if 0 DECLARE_COMPLETION(wait); +#else + int wait = 1; #endif @@ -813,6 +826,8 @@ void scsi_wait_req (Scsi_Request * SRpnt, const void *cmnd , #if 0 SRpnt->sr_request.waiting = &wait; +#else + SRpnt->sr_request.waiting = (void *)&wait; #endif @@ -824,28 +839,31 @@ void scsi_wait_req (Scsi_Request * SRpnt, const void *cmnd , #if 0 wait_for_completion(&wait); -#endif + SRpnt->sr_request.waiting = NULL; +#else /* XXX SMH: in 'standard' driver we think everythings ok here since we've waited on &wait -- hence we deallocate the command structure if it hasn't been done already. This is not the correct behaviour in xen ... hmm .. how to fix? */ - mdelay(500); - + int usecs = 0; +// printk("scsi_wait_req: about to poll-wait, request is at %p\n", +// SRpnt->sr_request); + while(*(int *)(SRpnt->sr_request.waiting)) { + udelay(500); + usecs += 500; + if(usecs > 1000000) { + printk("scsi_wait_req: giving up after 1 seconds!\n"); + *(int *)(SRpnt->sr_request.waiting) = 0; + } + } +#endif - SRpnt->sr_request.waiting = NULL; if( SRpnt->sr_command != NULL ) { -#ifdef SMH_DEBUG - printk("scsi_wait_req: releasing SRpnt->sr_command = %p\n", - SRpnt->sr_command); -#endif scsi_release_command(SRpnt->sr_command); SRpnt->sr_command = NULL; -#ifdef SMHHACK - SRpnt->freeaddr = 0x99991234; -#endif } } @@ -880,87 +898,77 @@ void scsi_do_req(Scsi_Request * SRpnt, const void *cmnd, void *buffer, unsigned bufflen, void (*done) (Scsi_Cmnd *), int timeout, int retries) { - Scsi_Device * SDpnt = SRpnt->sr_device; - struct Scsi_Host *host = SDpnt->host; - - ASSERT_LOCK(&io_request_lock, 0); - - SCSI_LOG_MLQUEUE(4, - { - int i; - int target = SDpnt->id; - int size = COMMAND_SIZE(((const unsigned char *)cmnd)[0]); - printk("scsi_do_req (host = %d, channel = %d target = %d, " - "buffer =%p, bufflen = %d, done = %p, timeout = %d, " - "retries = %d)\n" - "command : ", host->host_no, SDpnt->channel, target, buffer, - bufflen, done, timeout, retries); - for (i = 0; i < size; ++i) - printk("%02x ", ((unsigned char *) cmnd)[i]); - printk("\n"); - }); - - if (!host) { - panic("Invalid or not present host.\n"); - } - - /* - * If the upper level driver is reusing these things, then - * we should release the low-level block now. Another one will - * be allocated later when this request is getting queued. - */ - if( SRpnt->sr_command != NULL ) - { -#ifdef SMH_DEBUG - printk("scsi_do_req: releasing SRpnt->sr_command = %p\n", - SRpnt->sr_command); -#endif - scsi_release_command(SRpnt->sr_command); - SRpnt->sr_command = NULL; -#ifdef SMHHACK - SRpnt->freeaddr = 0xabbadead; -#endif - } - - /* - * We must prevent reentrancy to the lowlevel host driver. - * This prevents it - we enter a loop until the host we want - * to talk to is not busy. Race conditions are prevented, as - * interrupts are disabled in between the time we check for - * the host being not busy, and the time we mark it busy - * ourselves. */ - - - /* - * Our own function scsi_done (which marks the host as not - * busy, disables the timeout counter, etc) will be called by - * us or by the scsi_hosts[host].queuecommand() function needs - * to also call the completion function for the high level - * driver. */ - - memcpy((void *) SRpnt->sr_cmnd, (const void *) cmnd, - sizeof(SRpnt->sr_cmnd)); -#ifdef SMHHACK - SRpnt->freeaddr = 0x1111; -#endif - - SRpnt->sr_bufflen = bufflen; - SRpnt->sr_buffer = buffer; - SRpnt->sr_allowed = retries; - SRpnt->sr_done = done; - SRpnt->sr_timeout_per_command = timeout; - - if (SRpnt->sr_cmd_len == 0) - SRpnt->sr_cmd_len = COMMAND_SIZE(SRpnt->sr_cmnd[0]); - - /* - * At this point, we merely set up the command, stick it in the normal - * request queue, and return. Eventually that request will come to the - * top of the list, and will be dispatched. - */ - scsi_insert_special_req(SRpnt, 0); - - SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_req()\n")); + Scsi_Device * SDpnt = SRpnt->sr_device; + struct Scsi_Host *host = SDpnt->host; + + ASSERT_LOCK(&io_request_lock, 0); + + SCSI_LOG_MLQUEUE(4, + { + int i; + int target = SDpnt->id; + int size = COMMAND_SIZE(((const unsigned char *)cmnd)[0]); + printk("scsi_do_req (host = %d, channel = %d target = %d, " + "buffer =%p, bufflen = %d, done = %p, timeout = %d, " + "retries = %d)\n" + "command : ", host->host_no, SDpnt->channel, target, buffer, + bufflen, done, timeout, retries); + for (i = 0; i < size; ++i) + printk("%02x ", ((unsigned char *) cmnd)[i]); + printk("\n"); + }); + + if (!host) { + panic("Invalid or not present host.\n"); + } + + /* + * If the upper level driver is reusing these things, then + * we should release the low-level block now. Another one will + * be allocated later when this request is getting queued. + */ + if( SRpnt->sr_command != NULL ) + { + scsi_release_command(SRpnt->sr_command); + SRpnt->sr_command = NULL; + } + + /* + * We must prevent reentrancy to the lowlevel host driver. + * This prevents it - we enter a loop until the host we want + * to talk to is not busy. Race conditions are prevented, as + * interrupts are disabled in between the time we check for + * the host being not busy, and the time we mark it busy + * ourselves. */ + + + /* + * Our own function scsi_done (which marks the host as not + * busy, disables the timeout counter, etc) will be called by + * us or by the scsi_hosts[host].queuecommand() function needs + * to also call the completion function for the high level + * driver. */ + + memcpy((void *) SRpnt->sr_cmnd, (const void *) cmnd, + sizeof(SRpnt->sr_cmnd)); + + SRpnt->sr_bufflen = bufflen; + SRpnt->sr_buffer = buffer; + SRpnt->sr_allowed = retries; + SRpnt->sr_done = done; + SRpnt->sr_timeout_per_command = timeout; + + if (SRpnt->sr_cmd_len == 0) + SRpnt->sr_cmd_len = COMMAND_SIZE(SRpnt->sr_cmnd[0]); + + /* + * At this point, we merely set up the command, stick it in the normal + * request queue, and return. Eventually that request will come to the + * top of the list, and will be dispatched. + */ + scsi_insert_special_req(SRpnt, 0); + + SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_req()\n")); } /* @@ -995,10 +1003,6 @@ void scsi_init_cmd_from_req(Scsi_Cmnd * SCpnt, Scsi_Request * SRpnt) SCpnt->owner = SCSI_OWNER_MIDLEVEL; SRpnt->sr_command = SCpnt; -#ifdef SMH_DEBUG - printk("scsi_init_cmd_from_req: SRpnt = %p, SRpnt->sr_command = %p\n", - SRpnt, SRpnt->sr_command); -#endif if (!host) { panic("Invalid or not present host.\n"); @@ -1381,10 +1385,10 @@ void scsi_bottom_half_handler(void) * see if this was the last command that might * have failed. If so, wake up the error handler. */ if (SCpnt->host->host_busy == SCpnt->host->host_failed) { +#if 0 SCSI_LOG_ERROR_RECOVERY(5, printk( "Waking error handler thread (%d)\n", atomic_read(&SCpnt->host->eh_wait->count))); -#if 0 up(SCpnt->host->eh_wait); #endif } @@ -2696,8 +2700,6 @@ int __init scsi_setup(char *str) __setup("scsihosts=", scsi_setup); #endif -static spinlock_t slock2 = SPIN_LOCK_UNLOCKED; - static int __init init_scsi(void) { #ifdef CONFIG_PROC_FS @@ -2706,14 +2708,6 @@ static int __init init_scsi(void) printk(KERN_INFO "SCSI subsystem driver " REVISION "\n"); - { - unsigned long flags; - - spin_lock_irqsave(&slock2, flags); - spin_unlock_irqrestore(&slock2, flags); - printk("SCSI start of day -- flags = %lx\n", flags); - } - if( scsi_init_minimal_dma_pool() != 0 ) { return 1; @@ -2749,18 +2743,11 @@ static int __init init_scsi(void) */ init_bh(SCSI_BH, scsi_bottom_half_handler); - { - unsigned long flags; - - spin_lock_irqsave(&slock2, flags); - spin_unlock_irqrestore(&slock2, flags); - printk("SCSI end of day -- flags = %lx\n", flags); - } - - return 0; } + + static void __exit exit_scsi(void) { Scsi_Host_Name *shn, *shn2 = NULL; @@ -2973,6 +2960,7 @@ scsi_reset_provider(Scsi_Device *dev, int flag) rtn = scsi_old_reset(SCpnt, flag); spin_unlock_irqrestore(&io_request_lock, flags); #endif + rtn= 0; } scsi_delete_timer(SCpnt); diff --git a/xen/drivers/scsi/scsi.h b/xen/drivers/scsi/scsi.h index 338bca8f7b..fc39615fc7 100644 --- a/xen/drivers/scsi/scsi.h +++ b/xen/drivers/scsi/scsi.h @@ -633,18 +633,18 @@ struct scsi_device { * with low level drivers that support multiple outstanding commands. */ typedef struct scsi_pointer { - char *ptr; /* data pointer */ - int this_residual; /* left in this buffer */ - struct scatterlist *buffer; /* which buffer */ - int buffers_residual; /* how many buffers left */ - - dma_addr_t dma_handle; - - volatile int Status; - volatile int Message; - volatile int have_data_in; - volatile int sent_command; - volatile int phase; + char *ptr; /* data pointer */ + int this_residual; /* left in this buffer */ + struct scatterlist *buffer; /* which buffer */ + int buffers_residual; /* how many buffers left */ + + dma_addr_t dma_handle; + + volatile int Status; + volatile int Message; + volatile int have_data_in; + volatile int sent_command; + volatile int phase; } Scsi_Pointer; /* @@ -685,146 +685,149 @@ struct scsi_request { }; /* - * FIXME(eric) - one of the great regrets that I have is that I failed to define - * these structure elements as something like sc_foo instead of foo. This would - * make it so much easier to grep through sources and so forth. I propose that - * all new elements that get added to these structures follow this convention. - * As time goes on and as people have the stomach for it, it should be possible to - * go back and retrofit at least some of the elements here with with the prefix. - */ + * FIXME(eric) - one of the great regrets that I have is that I failed + * to define these structure elements as something like sc_foo instead + * of foo. This would make it so much easier to grep through sources + * and so forth. I propose that all new elements that get added to + * these structures follow this convention. As time goes on and as + * people have the stomach for it, it should be possible to go back + * and retrofit at least some of the elements here with with the + * prefix. +*/ + struct scsi_cmnd { - int sc_magic; + int sc_magic; /* private: */ - /* - * This information is private to the scsi mid-layer. Wrapping it in a - * struct private is a way of marking it in a sort of C++ type of way. - */ - struct Scsi_Host *host; - unsigned short state; - unsigned short owner; - Scsi_Device *device; - Scsi_Request *sc_request; - struct scsi_cmnd *next; - struct scsi_cmnd *reset_chain; - - int eh_state; /* Used for state tracking in error handlr */ - void (*done) (struct scsi_cmnd *); /* Mid-level done function */ - /* - A SCSI Command is assigned a nonzero serial_number when internal_cmnd - passes it to the driver's queue command function. The serial_number - is cleared when scsi_done is entered indicating that the command has - been completed. If a timeout occurs, the serial number at the moment - of timeout is copied into serial_number_at_timeout. By subsequently - comparing the serial_number and serial_number_at_timeout fields - during abort or reset processing, we can detect whether the command - has already completed. This also detects cases where the command has - completed and the SCSI Command structure has already being reused - for another command, so that we can avoid incorrectly aborting or - resetting the new command. - */ - - unsigned long serial_number; - unsigned long serial_number_at_timeout; - - int retries; - int allowed; - int timeout_per_command; - int timeout_total; - int timeout; - - /* - * We handle the timeout differently if it happens when a reset, - * abort, etc are in process. - */ - unsigned volatile char internal_timeout; - struct scsi_cmnd *bh_next; /* To enumerate the commands waiting - to be processed. */ - + /* + * This information is private to the scsi mid-layer. Wrapping it in a + * struct private is a way of marking it in a sort of C++ type of way. + */ + struct Scsi_Host *host; + unsigned short state; + unsigned short owner; + Scsi_Device *device; + Scsi_Request *sc_request; + struct scsi_cmnd *next; + struct scsi_cmnd *reset_chain; + + int eh_state; /* Used for state tracking in error handlr */ + void (*done) (struct scsi_cmnd *); /* Mid-level done function */ + /* + A SCSI Command is assigned a nonzero serial_number when internal_cmnd + passes it to the driver's queue command function. The serial_number + is cleared when scsi_done is entered indicating that the command has + been completed. If a timeout occurs, the serial number at the moment + of timeout is copied into serial_number_at_timeout. By subsequently + comparing the serial_number and serial_number_at_timeout fields + during abort or reset processing, we can detect whether the command + has already completed. This also detects cases where the command has + completed and the SCSI Command structure has already being reused + for another command, so that we can avoid incorrectly aborting or + resetting the new command. + */ + + unsigned long serial_number; + unsigned long serial_number_at_timeout; + + int retries; + int allowed; + int timeout_per_command; + int timeout_total; + int timeout; + + /* + * We handle the timeout differently if it happens when a reset, + * abort, etc are in process. + */ + unsigned volatile char internal_timeout; + struct scsi_cmnd *bh_next; /* To enumerate the commands waiting + to be processed. */ + /* public: */ - - unsigned int target; - unsigned int lun; - unsigned int channel; - unsigned char cmd_len; - unsigned char old_cmd_len; - unsigned char sc_data_direction; - unsigned char sc_old_data_direction; - - /* These elements define the operation we are about to perform */ - unsigned char cmnd[MAX_COMMAND_SIZE]; - unsigned request_bufflen; /* Actual request size */ - - struct timer_list eh_timeout; /* Used to time out the command. */ - void *request_buffer; /* Actual requested buffer */ - void **bounce_buffers; /* Array of bounce buffers when using scatter-gather */ - - /* These elements define the operation we ultimately want to perform */ - unsigned char data_cmnd[MAX_COMMAND_SIZE]; - unsigned short old_use_sg; /* We save use_sg here when requesting - * sense info */ - unsigned short use_sg; /* Number of pieces of scatter-gather */ - unsigned short sglist_len; /* size of malloc'd scatter-gather list */ - unsigned short abort_reason; /* If the mid-level code requests an + + unsigned int target; + unsigned int lun; + unsigned int channel; + unsigned char cmd_len; + unsigned char old_cmd_len; + unsigned char sc_data_direction; + unsigned char sc_old_data_direction; + + /* These elements define the operation we are about to perform */ + unsigned char cmnd[MAX_COMMAND_SIZE]; + unsigned request_bufflen; /* Actual request size */ + + struct timer_list eh_timeout; /* Used to time out the command. */ + void *request_buffer; /* Actual requested buffer */ + void **bounce_buffers; /* Array of bounce buffers when + using scatter-gather */ + + /* These elements define the operation we ultimately want to perform */ + unsigned char data_cmnd[MAX_COMMAND_SIZE]; + unsigned short old_use_sg; /* We save use_sg here when requesting + * sense info */ + unsigned short use_sg; /* Number of pieces of scatter-gather */ + unsigned short sglist_len; /* size of malloc'd scatter-gather list */ + unsigned short abort_reason; /* If the mid-level code requests an * abort, this is the reason. */ - unsigned bufflen; /* Size of data buffer */ - void *buffer; /* Data buffer */ - - unsigned underflow; /* Return error if less than - this amount is transferred */ - unsigned old_underflow; /* save underflow here when reusing the + unsigned bufflen; /* Size of data buffer */ + void *buffer; /* Data buffer */ + + unsigned underflow; /* Return error if less than + this amount is transferred */ + unsigned old_underflow; /* save underflow here when reusing the * command for error handling */ - - unsigned transfersize; /* How much we are guaranteed to + + unsigned transfersize; /* How much we are guaranteed to transfer with each SCSI transfer (ie, between disconnect / reconnects. Probably == sector size */ - - int resid; /* Number of bytes requested to be - transferred less actual number - transferred (0 if not supported) */ - - struct request request; /* A copy of the command we are + + int resid; /* Number of bytes requested to be + transferred less actual number + transferred (0 if not supported) */ + + struct request request; /* A copy of the command we are working on */ + + unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; + /* obtained by REQUEST SENSE when CHECK CONDITION is + * received on original command (auto-sense) */ - unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE - * when CHECK CONDITION is - * received on original command - * (auto-sense) */ - - unsigned flags; - - /* - * Used to indicate that a command which has timed out also - * completed normally. Typically the completion function will - * do nothing but set this flag in this instance because the - * timeout handler is already running. - */ - unsigned done_late:1; - - /* Low-level done function - can be used by low-level driver to point - * to completion function. Not used by mid/upper level code. */ - void (*scsi_done) (struct scsi_cmnd *); - - /* - * The following fields can be written to by the host specific code. - * Everything else should be left alone. - */ - - Scsi_Pointer SCp; /* Scratchpad used by some host adapters */ - - unsigned char *host_scribble; /* The host adapter is allowed to - * call scsi_malloc and get some memory - * and hang it here. The host adapter - * is also expected to call scsi_free - * to release this memory. (The memory - * obtained by scsi_malloc is guaranteed - * to be at an address < 16Mb). */ + unsigned flags; + + /* + * Used to indicate that a command which has timed out also + * completed normally. Typically the completion function will + * do nothing but set this flag in this instance because the + * timeout handler is already running. + */ + unsigned done_late:1; + + /* Low-level done function - can be used by low-level driver to point + * to completion function. Not used by mid/upper level code. */ + void (*scsi_done) (struct scsi_cmnd *); + + /* + * The following fields can be written to by the host specific code. + * Everything else should be left alone. + */ + + Scsi_Pointer SCp; /* Scratchpad used by some host adapters */ + + unsigned char *host_scribble; - int result; /* Status code from lower level driver */ + /* The host adapter is allowed to call scsi_malloc and get some + * memory and hang it here. The host adapter is also expected to + * call scsi_free to release this memory. (The memory obtained + * by scsi_malloc is guaranteed to be at an address < 16Mb). */ - unsigned char tag; /* SCSI-II queued command tag */ - unsigned long pid; /* Process ID, starts at 0 */ + + int result; /* Status code from lower level driver */ + + unsigned char tag; /* SCSI-II queued command tag */ + unsigned long pid; /* Process ID, starts at 0 */ }; /* diff --git a/xen/drivers/scsi/scsi_error.c b/xen/drivers/scsi/scsi_error.c index 6c043937be..1287b9a99b 100644 --- a/xen/drivers/scsi/scsi_error.c +++ b/xen/drivers/scsi/scsi_error.c @@ -1914,9 +1914,9 @@ void scsi_error_handler(void *data) /* * Wake up the thread that created us. */ +#if 0 SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n", host->eh_notify->count.counter)); -#if 0 up(host->eh_notify); #endif diff --git a/xen/drivers/scsi/scsi_lib.c b/xen/drivers/scsi/scsi_lib.c index 8c32bf547f..57798389fc 100644 --- a/xen/drivers/scsi/scsi_lib.c +++ b/xen/drivers/scsi/scsi_lib.c @@ -73,7 +73,7 @@ static void __scsi_insert_special(request_queue_t *q, struct request *rq, unsigned long flags; ASSERT_LOCK(&io_request_lock, 0); - + rq->cmd = SPECIAL; rq->special = data; rq->q = NULL; @@ -362,92 +362,98 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt, int requeue, int frequeue) { - struct request *req; - struct buffer_head *bh; - Scsi_Device * SDpnt; - int nsect; - - ASSERT_LOCK(&io_request_lock, 0); - - req = &SCpnt->request; - req->errors = 0; - if (!uptodate) { - printk(" I/O error: dev %s, sector %lu\n", - kdevname(req->rq_dev), req->sector); - } - do { - if ((bh = req->bh) != NULL) { - nsect = bh->b_size >> 9; - blk_finished_io(nsect); - req->bh = bh->b_reqnext; - bh->b_reqnext = NULL; - sectors -= nsect; - bh->b_end_io(bh, uptodate); - if ((bh = req->bh) != NULL) { - req->hard_sector += nsect; - req->hard_nr_sectors -= nsect; - req->sector += nsect; - req->nr_sectors -= nsect; - - req->current_nr_sectors = bh->b_size >> 9; - if (req->nr_sectors < req->current_nr_sectors) { - req->nr_sectors = req->current_nr_sectors; - printk("scsi_end_request: buffer-list destroyed\n"); - } - } - } - } while (sectors && bh); - - /* - * If there are blocks left over at the end, set up the command - * to queue the remainder of them. - */ - if (req->bh) { - request_queue_t *q; - - if( !requeue ) - { - return SCpnt; + struct request *req; + struct buffer_head *bh; + Scsi_Device * SDpnt; + int nsect; + + ASSERT_LOCK(&io_request_lock, 0); + + req = &SCpnt->request; + req->errors = 0; + if (!uptodate) { + printk(" I/O error: dev %s, sector %lu\n", + kdevname(req->rq_dev), req->sector); + } + do { + if ((bh = req->bh) != NULL) { + nsect = bh->b_size >> 9; + blk_finished_io(nsect); + req->bh = bh->b_reqnext; + bh->b_reqnext = NULL; + sectors -= nsect; + bh->b_end_io(bh, uptodate); + if ((bh = req->bh) != NULL) { + req->hard_sector += nsect; + req->hard_nr_sectors -= nsect; + req->sector += nsect; + req->nr_sectors -= nsect; + + req->current_nr_sectors = bh->b_size >> 9; + if (req->nr_sectors < req->current_nr_sectors) { + req->nr_sectors = req->current_nr_sectors; + printk("scsi_end_request: buffer-list destroyed\n"); } - - q = &SCpnt->device->request_queue; - - req->buffer = bh->b_data; - /* - * Bleah. Leftovers again. Stick the leftovers in - * the front of the queue, and goose the queue again. - */ - scsi_queue_next_request(q, SCpnt); - return SCpnt; + } } -#if 0 - /* - * This request is done. If there is someone blocked waiting for this - * request, wake them up. Typically used to wake up processes trying - * to swap a page into memory. - */ - if (req->waiting != NULL) { - complete(req->waiting); + } while (sectors && bh); + + /* + * If there are blocks left over at the end, set up the command + * to queue the remainder of them. + */ + if (req->bh) { + request_queue_t *q; + + if( !requeue ) + { + return SCpnt; } -#endif - req_finished_io(req); - add_blkdev_randomness(MAJOR(req->rq_dev)); - - SDpnt = SCpnt->device; - + + q = &SCpnt->device->request_queue; + + req->buffer = bh->b_data; /* - * This will goose the queue request function at the end, so we don't - * need to worry about launching another command. + * Bleah. Leftovers again. Stick the leftovers in + * the front of the queue, and goose the queue again. */ - __scsi_release_command(SCpnt); - - if( frequeue ) { - request_queue_t *q; - - q = &SDpnt->request_queue; - scsi_queue_next_request(q, NULL); - } - return NULL; + scsi_queue_next_request(q, SCpnt); + return SCpnt; + } +#if 0 + /* + * This request is done. If there is someone blocked waiting for this + * request, wake them up. Typically used to wake up processes trying + * to swap a page into memory. + */ + if (req->waiting != NULL) { + complete(req->waiting); + } +#else + /* XXX SMH: we're done -- flip the flag for the spinner :-| */ + if(req->waiting && (*(int *)(req->waiting) != NULL)) { + printk("__scsi_end_request: flipping wait status on req %p\n", req); + *(int *)(req->waiting) = NULL; + } // else printk("__scsi_end_request: no-one to notify!!\n"); +#endif + req_finished_io(req); + add_blkdev_randomness(MAJOR(req->rq_dev)); + + SDpnt = SCpnt->device; + + /* + * This will goose the queue request function at the end, so we don't + * need to worry about launching another command. + */ + __scsi_release_command(SCpnt); + + if( frequeue ) { + request_queue_t *q; + + q = &SDpnt->request_queue; + scsi_queue_next_request(q, NULL); + } + return NULL; } /* @@ -554,6 +560,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, int this_count = SCpnt->bufflen >> 9; request_queue_t *q = &SCpnt->device->request_queue; + // printk("scsi_io_completion entered.\n"); /* * We must do one of several things here: * @@ -1053,6 +1060,7 @@ void scsi_request_fn(request_queue_t * q) * get those allocated here. */ if (!SDpnt->scsi_init_io_fn(SCpnt)) { + printk("scsi_request_fn: scsi_init_io_fn failed :-(\n"); SCpnt = __scsi_end_request(SCpnt, 0, SCpnt->request.nr_sectors, 0, 0); if( SCpnt != NULL ) @@ -1068,6 +1076,7 @@ void scsi_request_fn(request_queue_t * q) * Initialize the actual SCSI command for this request. */ if (!STpnt->init_command(SCpnt)) { + printk("scsi_request_fn: init_command failed :-(\n"); scsi_release_buffers(SCpnt); SCpnt = __scsi_end_request(SCpnt, 0, SCpnt->request.nr_sectors, 0, 0); diff --git a/xen/drivers/scsi/scsi_merge.c b/xen/drivers/scsi/scsi_merge.c index 92306b3ec0..4ea7f7e578 100644 --- a/xen/drivers/scsi/scsi_merge.c +++ b/xen/drivers/scsi/scsi_merge.c @@ -802,6 +802,7 @@ __inline static int __init_io(Scsi_Cmnd * SCpnt, int this_count; void ** bbpnt; + // printk("scsi_merge.c: __init_io entered\n"); /* * FIXME(eric) - don't inline this - it doesn't depend on the * integer flags. Come to think of it, I don't think this is even diff --git a/xen/drivers/scsi/sd.c b/xen/drivers/scsi/sd.c index dbb69d2447..4c64afd27e 100644 --- a/xen/drivers/scsi/sd.c +++ b/xen/drivers/scsi/sd.c @@ -61,6 +61,8 @@ #include <xeno/genhd.h> +#include <asm/domain_page.h> /* SMH: for [un_]map_domain_mem() */ + /* * static const char RCSid[] = "$Header:"; */ @@ -324,6 +326,7 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) !dpnt->device || !dpnt->device->online || block + SCpnt->request.nr_sectors > ppnt->nr_sects) { + SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors)); SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt)); @@ -1132,8 +1135,8 @@ static int sd_init() sd_registered++; } /* We do not support attaching loadable devices yet. */ - if (rscsi_disks) - return 0; + if (rscsi_disks) + return 0; rscsi_disks = kmalloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC); if (!rscsi_disks) @@ -1296,9 +1299,73 @@ static void sd_finish() } #endif +#if 0 + /* XXX SMH: turn on some logging */ + scsi_logging_level = ~0; + SCSI_SET_LOGGING(SCSI_LOG_HLQUEUE_SHIFT, SCSI_LOG_HLQUEUE_BITS, 1); +#endif + return; } + +/* +** XXX SMH: gross 'probe' function to allow xeno world to grope us; +** this should really not be in the disk-specific code as it should +** report tapes, CDs, etc. But for now this looks like the easiest +** place to hook it in :-( +*/ +void scsi_probe_devices(xen_disk_info_t *xdi) +{ + Scsi_Disk *sd; + int i, base, diskinfo[4]; + xen_disk_info_t *xen_xdi = + (xen_disk_info_t *)map_domain_mem(virt_to_phys(xdi)); + + /* We've already had IDE probe => we need to append our info */ + base = xen_xdi->count; + + for (sd = rscsi_disks, i = 0; i < sd_template.dev_max; i++, sd++) { + + if (sd->device !=NULL) { + + xen_xdi->disks[xen_xdi->count].type = XEN_DISK_SCSI; + xen_xdi->disks[xen_xdi->count].capacity = sd->capacity; + xen_xdi->count++; + + /* default bios params to most commonly used values */ + diskinfo[0] = 0x40; + diskinfo[1] = 0x20; + diskinfo[2] = (sd->capacity) >> 11; + + /* override with calculated, extended default, + or driver values */ + /* XXX SMH: gross in-line literal major number. XXX FIXME. */ + if(sd->device->host->hostt->bios_param != NULL) + sd->device->host->hostt->bios_param( + sd, MKDEV(SCSI_DISK0_MAJOR, 0), &diskinfo[0]); + else scsicam_bios_param(sd, MKDEV(SCSI_DISK0_MAJOR, 0), + &diskinfo[0]); + + + printk (KERN_ALERT "SCSI-XENO %d\n", xen_xdi->count - base); + printk (KERN_ALERT " capacity 0x%x\n", sd->capacity); + printk (KERN_ALERT " head 0x%x\n", diskinfo[0]); + printk (KERN_ALERT " sector 0x%x\n", diskinfo[1]); + printk (KERN_ALERT " cylinder 0x%x\n", diskinfo[2]); + + + } + } + + unmap_domain_mem(xen_xdi); + + return; +} + + + + static int sd_detect(Scsi_Device * SDp) { if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) @@ -1463,6 +1530,8 @@ static void sd_detach(Scsi_Device * SDp) static int __init init_sd(void) { + extern int scsi_register_module(int, void *); + sd_template.module = THIS_MODULE; return scsi_register_module(MODULE_SCSI_DEV, &sd_template); } diff --git a/xen/include/xeno/config.h b/xen/include/xeno/config.h index 7d7205b69a..08cc5cb0dd 100644 --- a/xen/include/xeno/config.h +++ b/xen/include/xeno/config.h @@ -32,6 +32,7 @@ #define CONFIG_BLK_DEV_PIIX 1 #define CONFIG_SCSI 1 +#define CONFIG_SCSI_LOGGING 1 #define CONFIG_BLK_DEV_SD 1 #define CONFIG_SD_EXTRA_DEVS 40 #define CONFIG_SCSI_MULTI_LUN 1 diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/Makefile b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/Makefile index 594aab25b8..fd6b63f51e 100644 --- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/Makefile +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/Makefile @@ -1,3 +1,4 @@ O_TARGET := blk.o -obj-y := xl_block.o xl_segment.o xl_segment_proc.o xl_block_test.o +obj-y := xl_block.o xl_ide.o xl_scsi.o xl_segment.o +obj-y += xl_segment_proc.o xl_block_test.o include $(TOPDIR)/Rules.make 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; } diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_ide.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_ide.c new file mode 100644 index 0000000000..50f80038ee --- /dev/null +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_ide.c @@ -0,0 +1,200 @@ +/****************************************************************************** + * xl_ide.c + * + * Xenolinux virtual IDE block-device driver. + * + */ + +#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> + +#define MAJOR_NR XLIDE_MAJOR /* force defns in blk.h, must precede include */ +static int xlide_major = XLIDE_MAJOR; +#include <linux/blk.h> + +void xlide_ide_register_disk(int, unsigned long); + +#define XLIDE_MAX 32 /* Maximum minor devices we support */ +#define XLIDE_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 xlide_blk_size[XLIDE_MAX]; +static int xlide_blksize_size[XLIDE_MAX]; +static int xlide_read_ahead; +static int xlide_hardsect_size[XLIDE_MAX]; +static int xlide_max_sectors[XLIDE_MAX]; + +extern xen_disk_info_t xen_disk_info; + + +extern int xenolinux_block_open(struct inode *inode, struct file *filep); +extern int xenolinux_block_release(struct inode *inode, struct file *filep); +extern int xenolinux_block_ioctl(struct inode *inode, struct file *filep, + unsigned command, unsigned long argument); +extern int xenolinux_block_check(kdev_t dev); +extern int xenolinux_block_revalidate(kdev_t dev); + + +extern void do_xlblk_request (request_queue_t *rq); + + +static struct block_device_operations xlide_block_fops = +{ + open: xenolinux_block_open, + release: xenolinux_block_release, + ioctl: xenolinux_block_ioctl, + check_media_change: xenolinux_block_check, + revalidate: xenolinux_block_revalidate, +}; + + +/* tiny inteface fn */ +int xlide_hwsect(int minor) +{ + return xlide_hardsect_size[minor]; +} + + +void xlide_register_disk(int xidx, int idx) +{ + 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 = xlide_major; /* XXX should be idx-specific */ + gd->major_name = XLIDE_MAJOR_NAME; /* XXX should be idx-specific */ + 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 = &xlide_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); + + xen_disk_info.disks[xidx].gendisk = gd; + + /* XXX major should be idx-specific */ + register_disk(gd, MKDEV(xlide_major, 0), 1<<IDE_PARTN_BITS, + &xlide_block_fops, xen_disk_info.disks[xidx].capacity); + + return; +} + + + +/* +** Initialize a XenoLinux IDE disk; the 'xidx' is the index into the +** xen_disk_info array so we can grab interesting values; the 'idx' is +** a count of the number of XLSCSI disks we've seen so far, starting at 0 +** XXX SMH: this is all so ugly because the xen_disk_info() structure and +** array doesn't really give us what we want. Ho hum. To be tidied someday. +*/ +int xlide_init(int xidx, int idx) +{ + int i, major, result; + + SET_MODULE_OWNER(&xlide_block_fops); + + major = xlide_major + idx; /* XXX assume we have a linear major space */ + + /* XXX SMH: name below should vary with major */ + result = register_blkdev(major, XLIDE_MAJOR_NAME, &xlide_block_fops); + if (result < 0) { + printk (KERN_ALERT "XL IDE: can't get major %d\n", + major); + return result; + } + + /* initialize global arrays in drivers/block/ll_rw_block.c */ + for (i = 0; i < XLIDE_MAX; i++) { + xlide_blk_size[i] = xen_disk_info.disks[0].capacity; + xlide_blksize_size[i] = 512; + xlide_hardsect_size[i] = 512; + xlide_max_sectors[i] = 128; + } + xlide_read_ahead = 8; + + blk_size[major] = xlide_blk_size; + blksize_size[major] = xlide_blksize_size; + hardsect_size[major] = xlide_hardsect_size; + read_ahead[major] = xlide_read_ahead; + max_sectors[major] = xlide_max_sectors; + + blk_init_queue(BLK_DEFAULT_QUEUE(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(major), 0); + + xlide_register_disk(xidx, idx); + + printk(KERN_ALERT + "XenoLinux Virtual IDE Device Driver installed [device: %d]\n", + major); + + return 0; +} + + +void xlide_cleanup(void) +{ + /* CHANGE FOR MULTIQUEUE */ + blk_cleanup_queue(BLK_DEFAULT_QUEUE(xlide_major)); + + /* clean up global arrays */ + read_ahead[xlide_major] = 0; + + if (blk_size[xlide_major]) + kfree(blk_size[xlide_major]); + blk_size[xlide_major] = NULL; + + if (blksize_size[xlide_major]) + kfree(blksize_size[xlide_major]); + blksize_size[xlide_major] = NULL; + + if (hardsect_size[xlide_major]) + kfree(hardsect_size[xlide_major]); + hardsect_size[xlide_major] = NULL; + + /* XXX: free each gendisk */ + if (unregister_blkdev(xlide_major, XLIDE_MAJOR_NAME)) + printk(KERN_ALERT + "XenoLinux Virtual IDE Device Driver uninstalled w/ errs\n"); + else + printk(KERN_ALERT + "XenoLinux Virtual IDE Device Driver uninstalled\n"); + + return; +} + diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_scsi.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_scsi.c new file mode 100644 index 0000000000..3ee86509f1 --- /dev/null +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_scsi.c @@ -0,0 +1,211 @@ +/****************************************************************************** + * xl_scsi.c + * + * Xenolinux virtual SCSI block-device driver. + * + */ + +#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> + +#define MAJOR_NR XLSCSI_MAJOR /* force defns in blk.h, must precede include */ +static int xlscsi_major = XLSCSI_MAJOR; +#include <linux/blk.h> + +/* Copied from linux/ide.h */ +typedef unsigned char byte; + +void xlscsi_ide_register_disk(int, unsigned long); + +#define SCSI_DISKS_PER_MAJOR 16 /* max number of devices per scsi major */ +#define XLSCSI_MAX 32 /* maximum minor devices we support */ +#define XLSCSI_MAJOR_NAME "xsd" + +static int xlscsi_blk_size[XLSCSI_MAX]; +static int xlscsi_blksize_size[XLSCSI_MAX]; +static int xlscsi_read_ahead; +static int xlscsi_hardsect_size[XLSCSI_MAX]; +static int xlscsi_max_sectors[XLSCSI_MAX]; + +#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 + +extern xen_disk_info_t xen_disk_info; + +extern int xenolinux_block_open(struct inode *inode, struct file *filep); +extern int xenolinux_block_release(struct inode *inode, struct file *filep); +extern int xenolinux_block_ioctl(struct inode *inode, struct file *filep, + unsigned command, unsigned long argument); +extern int xenolinux_block_check(kdev_t dev); +extern int xenolinux_block_revalidate(kdev_t dev); + + +extern void do_xlblk_request (request_queue_t *rq); + +static struct block_device_operations xlscsi_block_fops = +{ + open: xenolinux_block_open, + release: xenolinux_block_release, + ioctl: xenolinux_block_ioctl, + check_media_change: xenolinux_block_check, + revalidate: xenolinux_block_revalidate, +}; + + +/* tiny inteface fn */ +int xlscsi_hwsect(int minor) +{ + return xlscsi_hardsect_size[minor]; +} + + +void xlscsi_register_disk(int xidx, int idx) +{ + int minors; + struct gendisk *gd; + unsigned long capacity; + + minors = XLSCSI_MAX; + 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)); + + if(idx > 0) + printk("xlscsi_register_disk: need fix to handle " + "multiple SCSI majors!\n"); + + gd->major = xlscsi_major; /* XXX should be idx-specific */ + gd->major_name = XLSCSI_MAJOR_NAME; /* XXX should be idx-specific */ + gd->minor_shift = 4; + gd->max_p = 1<<4; + gd->nr_real = SCSI_DISKS_PER_MAJOR; + gd->real_devices = NULL; + gd->next = NULL; + gd->fops = &xlscsi_block_fops; + gd->de_arr = kmalloc (sizeof *gd->de_arr * SCSI_DISKS_PER_MAJOR, + GFP_KERNEL); + gd->flags = kmalloc (sizeof *gd->flags * SCSI_DISKS_PER_MAJOR, + GFP_KERNEL); + + if (gd->de_arr) + memset (gd->de_arr, 0, sizeof *gd->de_arr * SCSI_DISKS_PER_MAJOR); + + if (gd->flags) + memset (gd->flags, 0, sizeof *gd->flags * SCSI_DISKS_PER_MAJOR); + + add_gendisk(gd); + + xen_disk_info.disks[xidx].gendisk = gd; + + /* XXX major below should be idx-specific */ + register_disk(gd, MKDEV(xlscsi_major, 0), 1<<4, &xlscsi_block_fops, + xen_disk_info.disks[xidx].capacity); + + return; +} + + +/* +** Initialize a XenoLinux SCSI disk; the 'xidx' is the index into the +** xen_disk_info array so we can grab interesting values; the 'idx' is +** a count of the number of XLSCSI disks we've seen so far, starting at 0 +** XXX SMH: this is all so ugly because the xen_disk_info() structure and +** array doesn't really give us what we want. Ho hum. To be tidied someday. +*/ +int xlscsi_init(int xidx, int idx) +{ + int i, major, result; + + SET_MODULE_OWNER(&xlscsi_block_fops); + + major = xlscsi_major + idx; /* XXX asume we have linear major space */ + + /* XXX SMH: 'name' below should vary for different major values */ + result = register_blkdev(major, XLSCSI_MAJOR_NAME, &xlscsi_block_fops); + + if (result < 0) { + printk (KERN_ALERT "XL SCSI: can't get major %d\n", major); + return result; + } + + /* initialize global arrays in drivers/block/ll_rw_block.c */ + for (i = 0; i < XLSCSI_MAX; i++) { + xlscsi_blk_size[i] = xen_disk_info.disks[xidx].capacity; + xlscsi_blksize_size[i] = 512; + xlscsi_hardsect_size[i] = 512; + xlscsi_max_sectors[i] = 128; + } + xlscsi_read_ahead = 8; + + blk_size[major] = xlscsi_blk_size; + blksize_size[major] = xlscsi_blksize_size; + hardsect_size[major] = xlscsi_hardsect_size; + read_ahead[major] = xlscsi_read_ahead; + max_sectors[major] = xlscsi_max_sectors; + + blk_init_queue(BLK_DEFAULT_QUEUE(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(major), 0); + + xlscsi_register_disk(xidx, idx); + + printk(KERN_ALERT + "XenoLinux Virtual SCSI Device Driver installed [device: %d]\n", + major); + return 0; +} + + + +void xlscsi_cleanup(void) +{ + /* CHANGE FOR MULTIQUEUE */ + blk_cleanup_queue(BLK_DEFAULT_QUEUE(xlscsi_major)); + + /* clean up global arrays */ + read_ahead[xlscsi_major] = 0; + + if (blk_size[xlscsi_major]) + kfree(blk_size[xlscsi_major]); + blk_size[xlscsi_major] = NULL; + + if (blksize_size[xlscsi_major]) + kfree(blksize_size[xlscsi_major]); + blksize_size[xlscsi_major] = NULL; + + if (hardsect_size[xlscsi_major]) + kfree(hardsect_size[xlscsi_major]); + hardsect_size[xlscsi_major] = NULL; + + /* XXX: free each gendisk */ + if (unregister_blkdev(xlscsi_major, XLSCSI_MAJOR_NAME)) + printk(KERN_ALERT + "XenoLinux Virtual SCSI Device Driver uninstalled w/ errs\n"); + else + printk(KERN_ALERT + "XenoLinux Virtual SCSI Device Driver uninstalled\n"); + + return; +} + diff --git a/xenolinux-2.4.21-pre4-sparse/include/linux/major.h b/xenolinux-2.4.21-pre4-sparse/include/linux/major.h index 9cac1c2881..a838d477d1 100644 --- a/xenolinux-2.4.21-pre4-sparse/include/linux/major.h +++ b/xenolinux-2.4.21-pre4-sparse/include/linux/major.h @@ -145,8 +145,8 @@ #define UMEM_MAJOR 116 /* http://www.umem.com/ Battery Backed RAM */ -/* note: 123, 124, 125, 126 and 234, 235, 236, 237 are defined in xeno_major */ -#include <asm/hypervisor-ifs/xeno-major.h> +#define XLIDE_MAJOR 123 /* XenoLinux IDE Device */ +#define XLSCSI_MAJOR 133 /* XenoLinux SCSI Device */ #define RTF_MAJOR 150 #define RAW_MAJOR 162 diff --git a/xenolinux-2.4.21-pre4-sparse/init/do_mounts.c b/xenolinux-2.4.21-pre4-sparse/init/do_mounts.c index ddf2f96a39..68c1a4a002 100644 --- a/xenolinux-2.4.21-pre4-sparse/init/do_mounts.c +++ b/xenolinux-2.4.21-pre4-sparse/init/do_mounts.c @@ -232,13 +232,7 @@ static struct dev_name_struct { { "ataraid/d15p",0x72F0 }, #if defined(CONFIG_XENOLINUX_BLOCK) { "xhda", 0x7B00 }, - { "xhdb", 0x7C00 }, - { "xhdc", 0x7D00 }, - { "xhdd", 0x7E00 }, - { "vhda", 0xEA00 }, - { "vhdb", 0xEB00 }, - { "vhdc", 0xEC00 }, - { "vhdd", 0xED00 }, + { "xsda", 0x8500 }, #endif { "nftla", 0x5d00 }, { "nftlb", 0x5d10 }, |