From: Markus Lidel <Markus.Lidel@shadowconnect.com>




---

 25-akpm/drivers/message/i2o/i2o_block.c |  382 +++++++++++++-------------------
 1 files changed, 165 insertions(+), 217 deletions(-)

diff -puN drivers/message/i2o/i2o_block.c~i2o-subsystem-fixing-and-cleanup-for-26-i2o_block-cleanuppatch drivers/message/i2o/i2o_block.c
--- 25/drivers/message/i2o/i2o_block.c~i2o-subsystem-fixing-and-cleanup-for-26-i2o_block-cleanuppatch	2004-04-30 03:27:26.520546712 -0700
+++ 25-akpm/drivers/message/i2o/i2o_block.c	2004-04-30 03:27:26.527545648 -0700
@@ -83,7 +83,6 @@
 #include <asm/semaphore.h>
 #include <linux/completion.h>
 #include <asm/io.h>
-#include <asm/atomic.h>
 #include <linux/smp_lock.h>
 #include <linux/wait.h>
 
@@ -111,16 +110,12 @@
 				 I2O_EVT_IND_BSA_SCSI_SMART )
 
 
-#define I2O_LOCK(unit)	(i2ob_dev[(unit)].req_queue->queue_lock)
-
 /*
  *	Some of these can be made smaller later
  */
 
-static int i2ob_media_change_flag[MAX_I2OB];
-static u32 i2ob_max_sectors[MAX_I2OB<<4];
-
 static int i2ob_context;
+static struct block_device_operations i2ob_fops;
 
 /*
  * I2O Block device descriptor 
@@ -143,6 +138,9 @@ struct i2ob_device
 	int wcache;
 	int power;
 	int index;
+	int media_change_flag;
+	u32 max_sectors;
+	struct gendisk *gd;
 };
 
 /*
@@ -162,16 +160,16 @@ struct i2ob_request
 };
 
 /*
- * Per IOP requst queue information
+ * Per IOP request queue information
  *
- * We have a separate requeust_queue_t per IOP so that a heavilly
+ * We have a separate request_queue_t per IOP so that a heavilly
  * loaded I2O block device on an IOP does not starve block devices
  * across all I2O controllers.
  * 
  */
 struct i2ob_iop_queue
 {
-	atomic_t queue_depth;
+	unsigned int queue_depth;
 	struct i2ob_request request_queue[MAX_I2OB_DEPTH];
 	struct i2ob_request *i2ob_qhead;
 	request_queue_t *req_queue;
@@ -183,9 +181,8 @@ static struct i2ob_iop_queue *i2ob_queue
  *	Each I2O disk is one of these.
  */
 
-static struct i2ob_device i2ob_dev[MAX_I2OB<<4];
+static struct i2ob_device i2ob_dev[MAX_I2OB];
 static int i2ob_dev_count = 0;
-static struct gendisk *i2ob_disk[MAX_I2OB];
 
 /*
  * Mutex and spin lock for event handling synchronization
@@ -312,7 +309,6 @@ static int i2ob_send(u32 m, struct i2ob_
 	/* 
 	 * Mask out partitions from now on
 	 */
-	unit &= 0xF0;
 		
 	/* This can be optimised later - just want to be sure its right for
 	   starters */
@@ -402,7 +398,7 @@ static int i2ob_send(u32 m, struct i2ob_
 	}
 
 	i2o_post_message(c,m);
-	atomic_inc(&i2ob_queues[c->unit]->queue_depth);
+	i2ob_queues[c->unit]->queue_depth ++;
 
 	return 0;
 }
@@ -453,8 +449,8 @@ static void i2o_block_reply(struct i2o_h
 	struct i2ob_request *ireq = NULL;
 	u8 st;
 	u32 *m = (u32 *)msg;
-	u8 unit = (m[2]>>8)&0xF0;	/* low 4 bits are partition */
-	struct i2ob_device *dev = &i2ob_dev[(unit&0xF0)];
+	u8 unit = m[2]>>8;
+	struct i2ob_device *dev = &i2ob_dev[unit];
 
 	/*
 	 * FAILed message
@@ -475,10 +471,10 @@ static void i2o_block_reply(struct i2o_h
 		ireq=&i2ob_queues[c->unit]->request_queue[m[3]];
 		ireq->req->errors++;
 
-		spin_lock_irqsave(I2O_LOCK(c->unit), flags);
+		spin_lock_irqsave(dev->req_queue->queue_lock, flags);
 		i2ob_unhook_request(ireq, c->unit);
 		i2ob_end_request(ireq->req);
-		spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
+		spin_unlock_irqrestore(dev->req_queue->queue_lock, flags);
 	
 		/* Now flush the message by making it a NOP */
 		m[0]&=0x00FFFFFF;
@@ -509,10 +505,10 @@ static void i2o_block_reply(struct i2o_h
 		ireq=&i2ob_queues[c->unit]->request_queue[m[3]];
 		ireq->req->errors++;
 		printk(KERN_WARNING "I2O Block: Data transfer to deleted device!\n");
-		spin_lock_irqsave(I2O_LOCK(c->unit), flags);
+		spin_lock_irqsave(dev->req_queue->queue_lock, flags);
 		i2ob_unhook_request(ireq, c->unit);
 		i2ob_end_request(ireq->req);
-		spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
+		spin_unlock_irqrestore(dev->req_queue->queue_lock, flags);
 		return;
 	}	
 
@@ -576,17 +572,17 @@ static void i2o_block_reply(struct i2o_h
 	 */
 	
 	i2ob_free_sglist(dev, ireq);
-	spin_lock_irqsave(I2O_LOCK(c->unit), flags);
+	spin_lock_irqsave(dev->req_queue->queue_lock, flags);
 	i2ob_unhook_request(ireq, c->unit);
 	i2ob_end_request(ireq->req);
-	atomic_dec(&i2ob_queues[c->unit]->queue_depth);
+	i2ob_queues[c->unit]->queue_depth --;
 	
 	/*
 	 *	We may be able to do more I/O
 	 */
 	 
-	i2ob_request(dev->req_queue);
-	spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
+	i2ob_request(dev->gd->queue);
+	spin_unlock_irqrestore(dev->req_queue->queue_lock, flags);
 }
 
 /* 
@@ -598,8 +594,8 @@ static int i2ob_evt(void *dummy)
 {
 	unsigned int evt;
 	unsigned long flags;
+	struct i2ob_device *dev;
 	int unit;
-	int i;
 	//The only event that has data is the SCSI_SMART event.
 	struct i2o_reply {
 		u32 header[4];
@@ -638,6 +634,7 @@ static int i2ob_evt(void *dummy)
 		unit = le32_to_cpu(evt_local->header[3]);
 		evt = le32_to_cpu(evt_local->evt_indicator);
 
+		dev = &i2ob_dev[unit];
 		switch(evt)
 		{
 			/*
@@ -648,10 +645,9 @@ static int i2ob_evt(void *dummy)
 			 */
 			case I2O_EVT_IND_BSA_VOLUME_LOAD:
 			{
-				struct gendisk *p = i2ob_disk[unit>>4];
-				i2ob_install_device(i2ob_dev[unit].i2odev->controller, 
-					i2ob_dev[unit].i2odev, unit);
-				add_disk(p);
+				i2ob_install_device(dev->i2odev->controller,
+					dev->i2odev, unit);
+				add_disk(dev->gd);
 				break;
 			}
 
@@ -663,17 +659,18 @@ static int i2ob_evt(void *dummy)
 			 */
 			case I2O_EVT_IND_BSA_VOLUME_UNLOAD:
 			{
-				struct gendisk *p = i2ob_disk[unit>>4];
+				struct gendisk *p = dev->gd;
+				blk_queue_max_sectors(dev->gd->queue, 0);
 				del_gendisk(p);
-				for(i = unit; i <= unit+15; i++)
-					blk_queue_max_sectors(i2ob_dev[i].req_queue, 0);
-				i2ob_media_change_flag[unit] = 1;
+				put_disk(p);
+				dev->gd = NULL;
+				dev->media_change_flag = 1;
 				break;
 			}
 
 			case I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ:
 				printk(KERN_WARNING "%s: Attempt to eject locked media\n", 
-					i2ob_dev[unit].i2odev->dev_name);
+					dev->i2odev->dev_name);
 				break;
 
 			/*
@@ -691,12 +688,12 @@ static int i2ob_evt(void *dummy)
 			{
 				u64 size;
 
-	  			if(i2ob_query_device(&i2ob_dev[unit], 0x0004, 0, &size, 8) !=0 )
-					i2ob_query_device(&i2ob_dev[unit], 0x0000, 4, &size, 8);
+	  			if(i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 )
+					i2ob_query_device(dev, 0x0000, 4, &size, 8);
 
-				spin_lock_irqsave(I2O_LOCK(unit), flags);	
-				set_capacity(i2ob_disk[unit>>4], size>>9);
-				spin_unlock_irqrestore(I2O_LOCK(unit), flags);	
+				spin_lock_irqsave(dev->req_queue->queue_lock, flags);
+				set_capacity(dev->gd, size>>9);
+				spin_unlock_irqrestore(dev->req_queue->queue_lock, flags);
 				break;
 			}
 
@@ -708,7 +705,7 @@ static int i2ob_evt(void *dummy)
 			case I2O_EVT_IND_BSA_SCSI_SMART:
 			{
 				char buf[16];
-				printk(KERN_INFO "I2O Block: %s received a SCSI SMART Event\n",i2ob_dev[unit].i2odev->dev_name);
+				printk(KERN_INFO "I2O Block: %s received a SCSI SMART Event\n",dev->i2odev->dev_name);
 				evt_local->data[16]='\0';
 				sprintf(buf,"%s",&evt_local->data[0]);
 				printk(KERN_INFO "      Disk Serial#:%s\n",buf);
@@ -735,12 +732,12 @@ static int i2ob_evt(void *dummy)
 				 * hit the fan big time. The card seems to recover but loses
 				 * the pending writes. Deeply ungood except for testing fsck
 				 */
-				if(i2ob_dev[unit].i2odev->controller->promise)
+				if(dev->i2odev->controller->promise)
 					panic("I2O controller firmware failed. Reboot and force a filesystem check.\n");
 			default:
 				printk(KERN_INFO "%s: Received event 0x%X we didn't register for\n"
 					KERN_INFO "   Blame the I2O card manufacturer 8)\n", 
-					i2ob_dev[unit].i2odev->dev_name, evt);
+					dev->i2odev->dev_name, evt);
 				break;
 		}
 	};
@@ -765,14 +762,6 @@ static void i2ob_request(request_queue_t
 	u32 m;
 	
 	while ((req = elv_next_request(q)) != NULL) {
-		/*
-		 *	On an IRQ completion if there is an inactive
-		 *	request on the queue head it means it isnt yet
-		 *	ready to dispatch.
-		 */
-		if(req->rq_status == RQ_INACTIVE)
-			return;
-
 		dev = req->rq_disk->private_data;
 
 		/* 
@@ -780,7 +769,7 @@ static void i2ob_request(request_queue_t
 		 *	generic IOP commit control. Certainly it's not right 
 		 *	its global!  
 		 */
-		if(atomic_read(&i2ob_queues[dev->unit]->queue_depth) >= dev->depth)
+		if(i2ob_queues[dev->unit]->queue_depth >= dev->depth)
 			break;
 		
 		/* Get a message */
@@ -788,7 +777,7 @@ static void i2ob_request(request_queue_t
 
 		if(m==0xFFFFFFFF)
 		{
-			if(atomic_read(&i2ob_queues[dev->unit]->queue_depth) == 0)
+			if(i2ob_queues[dev->unit]->queue_depth == 0)
 				printk(KERN_ERR "i2o_block: message queue and request queue empty!!\n");
 			break;
 		}
@@ -797,13 +786,12 @@ static void i2ob_request(request_queue_t
 		 */
 		req->errors = 0;
 		blkdev_dequeue_request(req);	
-		req->waiting = NULL;
 		
 		ireq = i2ob_queues[dev->unit]->i2ob_qhead;
 		i2ob_queues[dev->unit]->i2ob_qhead = ireq->next;
 		ireq->req = req;
 
-		i2ob_send(m, dev, ireq, (dev->unit&0xF0));
+		i2ob_send(m, dev, ireq, dev->index);
 	}
 }
 
@@ -1065,7 +1053,10 @@ static int i2ob_install_device(struct i2
 	u16 power;
 	u32 flags, status;
 	struct i2ob_device *dev=&i2ob_dev[unit];
-	int i;
+	struct gendisk *disk;
+	request_queue_t *q;
+	int segments;
+
 
 	/*
 	 * For logging purposes...
@@ -1079,21 +1070,35 @@ static int i2ob_install_device(struct i2
 	 * before any I/O can be performed. If it fails, this
 	 * device is useless.
 	 */
-	if(!i2ob_queues[unit]) {
-		if(i2ob_init_iop(unit))
+	if(!i2ob_queues[c->unit]) {
+		if(i2ob_init_iop(c->unit))
 			return 1;
 	}
 
+	q = i2ob_queues[c->unit]->req_queue;
+
 	/*
 	 * This will save one level of lookup/indirection in critical
 	 * code so that we can directly get the queue ptr from the
 	 * device instead of having to go the IOP data structure.
 	 */
-	dev->req_queue = i2ob_queues[unit]->req_queue;
+	dev->req_queue = q;
 
+	/*
+	 * Allocate a gendisk structure and initialize it
+	 */
+	disk = alloc_disk(16);
+	if (!disk)
+		return 1;
+
+	dev->gd = disk;
 	/* initialize gendik structure */
-	i2ob_disk[unit>>4]->private_data = dev;
-	i2ob_disk[unit>>4]->queue = dev->req_queue;
+	disk->major = MAJOR_NR;
+	disk->first_minor = unit<<4;
+	disk->queue = q;
+	disk->fops = &i2ob_fops;
+	sprintf(disk->disk_name, "i2o/hd%c", 'a' + unit);
+	disk->private_data = dev;
 
 	/*
 	 *	Ask for the current media data. If that isn't supported
@@ -1110,53 +1115,49 @@ static int i2ob_install_device(struct i2
 		power = 0;
 	i2ob_query_device(dev, 0x0000, 5, &flags, 4);
 	i2ob_query_device(dev, 0x0000, 6, &status, 4);
-	set_capacity(i2ob_disk[unit>>4], size>>9);
+	set_capacity(disk, size>>9);
 
 	/*
 	 * Max number of Scatter-Gather Elements
 	 */	
 
-	i2ob_dev[unit].power = power;	/* Save power state in device proper */
-	i2ob_dev[unit].flags = flags;
+	dev->power = power;	/* Save power state in device proper */
+	dev->flags = flags;
 
-	for(i=unit;i<=unit+15;i++)
-	{
-		request_queue_t *q = i2ob_dev[unit].req_queue;
-		int segments = (d->controller->status_block->inbound_frame_size - 7) / 2;
+	segments = (d->controller->status_block->inbound_frame_size - 7) / 2;
+
+	if(segments > 16)
+		segments = 16;
 
-		if(segments > 16)
-			segments = 16;
-					
-		i2ob_dev[i].power = power;	/* Save power state */
-		i2ob_dev[unit].flags = flags;	/* Keep the type info */
+	dev->power = power;	/* Save power state */
+	dev->flags = flags;	/* Keep the type info */
 		
-		blk_queue_max_sectors(q, 96);	/* 256 might be nicer but many controllers 
+	blk_queue_max_sectors(q, 96);	/* 256 might be nicer but many controllers
 						   explode on 65536 or higher */
-		blk_queue_max_phys_segments(q, segments);
-		blk_queue_max_hw_segments(q, segments);
+	blk_queue_max_phys_segments(q, segments);
+	blk_queue_max_hw_segments(q, segments);
 		
-		i2ob_dev[i].rcache = CACHE_SMARTFETCH;
-		i2ob_dev[i].wcache = CACHE_WRITETHROUGH;
+	dev->rcache = CACHE_SMARTFETCH;
+	dev->wcache = CACHE_WRITETHROUGH;
 		
-		if(d->controller->battery == 0)
-			i2ob_dev[i].wcache = CACHE_WRITETHROUGH;
+	if(d->controller->battery == 0)
+		dev->wcache = CACHE_WRITETHROUGH;
 
-		if(d->controller->promise)
-			i2ob_dev[i].wcache = CACHE_WRITETHROUGH;
+	if(d->controller->promise)
+		dev->wcache = CACHE_WRITETHROUGH;
 
-		if(d->controller->short_req)
-		{
-			blk_queue_max_sectors(q, 8);
-			blk_queue_max_phys_segments(q, 8);
-			blk_queue_max_hw_segments(q, 8);
-		}
+	if(d->controller->short_req)
+	{
+		blk_queue_max_sectors(q, 8);
+		blk_queue_max_phys_segments(q, 8);
+		blk_queue_max_hw_segments(q, 8);
 	}
 
-	strcpy(d->dev_name, i2ob_disk[unit>>4]->disk_name);
-	strcpy(i2ob_disk[unit>>4]->devfs_name, i2ob_disk[unit>>4]->disk_name);
+	strcpy(d->dev_name, disk->disk_name);
+	strcpy(disk->devfs_name, disk->disk_name);
 
 	printk(KERN_INFO "%s: Max segments %d, queue depth %d, byte limit %d.\n",
-		 d->dev_name, i2ob_dev[unit].max_segments, i2ob_dev[unit].depth, i2ob_max_sectors[unit]<<9);
+		 d->dev_name, dev->max_segments, dev->depth, dev->max_sectors<<9);
 
 	i2ob_query_device(dev, 0x0000, 0, &type, 1);
 
@@ -1197,7 +1198,7 @@ static int i2ob_install_device(struct i2
 	}
 	printk(".\n");
 	printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", 
-		d->dev_name, i2ob_max_sectors[unit]);
+		d->dev_name, dev->max_sectors);
 
 	/*
 	 * Register for the events we're interested in and that the
@@ -1233,7 +1234,7 @@ static int i2ob_init_iop(unsigned int un
 	/* Queue is MAX_I2OB + 1... */
 	i2ob_queues[unit]->request_queue[i].next = NULL;
 	i2ob_queues[unit]->i2ob_qhead = &i2ob_queues[unit]->request_queue[0];
-	atomic_set(&i2ob_queues[unit]->queue_depth, 0);
+	i2ob_queues[unit]->queue_depth = 0;
 
 	i2ob_queues[unit]->lock = SPIN_LOCK_UNLOCKED;
 	i2ob_queues[unit]->req_queue = blk_init_queue(i2ob_request, &i2ob_queues[unit]->lock);
@@ -1257,7 +1258,6 @@ static void i2ob_scan(int bios)
 
 	struct i2o_device *d, *b=NULL;
 	struct i2o_controller *c;
-	struct i2ob_device *dev;
 		
 	for(i=0; i< MAX_I2O_CONTROLLERS; i++)
 	{
@@ -1313,44 +1313,12 @@ static void i2ob_scan(int bios)
 					continue; /*Already claimed on pass 1 */
 			}
 
-			if(i2o_claim_device(d, &i2o_block_handler))
-			{
-				printk(KERN_WARNING "i2o_block: Controller %d, TID %d\n", c->unit,
-					d->lct_data.tid);
-				printk(KERN_WARNING "\t%sevice refused claim! Skipping installation\n", bios?"Boot d":"D");
-				continue;
-			}
-
-			i2o_release_device(d, &i2o_block_handler);
-
-			if(scan_unit<MAX_I2OB<<4)
-			{
- 				/*
-				 * Get the device and fill in the
-				 * Tid and controller.
-				 */
-				dev=&i2ob_dev[scan_unit];
-				dev->i2odev = d; 
-				dev->controller = c;
-				dev->unit = c->unit;
-				dev->tid = d->lct_data.tid;
-
-				if(i2ob_install_device(c,d,scan_unit))
-					printk(KERN_WARNING "Could not install I2O block device\n");
-				else
-				{
-					add_disk(i2ob_disk[scan_unit>>4]);
-					scan_unit+=16;
-					i2ob_dev_count++;
-
-					/* We want to know when device goes away */
-					i2o_device_notify_on(d, &i2o_block_handler);
-				}
-			}
+			if(scan_unit<MAX_I2OB)
+				i2ob_new_device(c, d);
 			else
 			{
 				if(!warned++)
-					printk(KERN_WARNING "i2o_block: too many device, registering only %d.\n", scan_unit>>4);
+					printk(KERN_WARNING "i2o_block: too many device, registering only %d.\n", scan_unit);
 			}
 		}
 		i2o_unlock_controller(c);
@@ -1399,12 +1367,12 @@ void i2ob_new_device(struct i2o_controll
 	printk(KERN_INFO "   Controller %d Tid %d\n",c->unit, d->lct_data.tid);
 
 	/* Check for available space */
-	if(i2ob_dev_count>=MAX_I2OB<<4)
+	if(i2ob_dev_count>=MAX_I2OB)
 	{
 		printk(KERN_ERR "i2o_block: No more devices allowed!\n");
 		return;
 	}
-	for(unit = 0; unit < (MAX_I2OB<<4); unit += 16)
+	for(unit = 0; unit < MAX_I2OB; unit ++)
 	{
 		if(!i2ob_dev[unit].i2odev)
 			break;
@@ -1420,18 +1388,20 @@ void i2ob_new_device(struct i2o_controll
 	dev->i2odev = d; 
 	dev->controller = c;
 	dev->tid = d->lct_data.tid;
+	dev->unit = c->unit;
 
-	if(i2ob_install_device(c,d,unit))
+	if(i2ob_install_device(c,d,unit)) {
+		i2o_release_device(d, &i2o_block_handler);
 		printk(KERN_ERR "i2o_block: Could not install new device\n");
+	}
 	else	
 	{
-		add_disk(i2ob_disk[unit>>4]);
+		i2o_release_device(d, &i2o_block_handler);
+		add_disk(dev->gd);
 		i2ob_dev_count++;
 		i2o_device_notify_on(d, &i2o_block_handler);
 	}
 
-	i2o_release_device(d, &i2o_block_handler);
- 
 	return;
 }
 
@@ -1443,64 +1413,58 @@ void i2ob_new_device(struct i2o_controll
 void i2ob_del_device(struct i2o_controller *c, struct i2o_device *d)
 {	
 	int unit = 0;
-	int i = 0;
 	unsigned long flags;
+	struct i2ob_device *dev;
 
-	spin_lock_irqsave(I2O_LOCK(c->unit), flags);
-
-	/*
-	 * Need to do this...we somtimes get two events from the IRTOS
-	 * in a row and that causes lots of problems.
-	 */
-	i2o_device_notify_off(d, &i2o_block_handler);
-
-	printk(KERN_INFO "I2O Block Device Deleted\n");
-
-	for(unit = 0; unit < MAX_I2OB<<4; unit += 16)
+	for(unit = 0; unit < MAX_I2OB; unit ++)
 	{
-		if(i2ob_dev[unit].i2odev == d)
+		dev = &i2ob_dev[unit];
+		if(dev->i2odev == d)
 		{
 			printk(KERN_INFO "  /dev/%s: Controller %d Tid %d\n", 
 				d->dev_name, c->unit, d->lct_data.tid);
 			break;
 		}
 	}
-	if(unit >= MAX_I2OB<<4)
+
+	printk(KERN_INFO "I2O Block Device Deleted\n");
+
+	if(unit >= MAX_I2OB)
 	{
 		printk(KERN_ERR "i2ob_del_device called, but not in dev table!\n");
-		spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
 		return;
 	}
 
+	spin_lock_irqsave(dev->req_queue->queue_lock, flags);
+
+	/*
+	 * Need to do this...we somtimes get two events from the IRTOS
+	 * in a row and that causes lots of problems.
+	 */
+	i2o_device_notify_off(d, &i2o_block_handler);
+
 	/* 
 	 * This will force errors when i2ob_get_queue() is called
 	 * by the kenrel.
 	 */
-	del_gendisk(i2ob_disk[unit>>4]);
-	i2ob_dev[unit].req_queue = NULL;
-	for(i = unit; i <= unit+15; i++)
-	{
-		i2ob_dev[i].i2odev = NULL;
-		blk_queue_max_sectors(i2ob_dev[i].req_queue, 0);
-	}
-	spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
-
-	/*
-	 * Decrease usage count for module
-	 */	
-
-	while(i2ob_dev[unit].refcnt--)
-		MOD_DEC_USE_COUNT;
-
-	i2ob_dev[unit].refcnt = 0;
-	
-	i2ob_dev[i].tid = 0;
+	if(dev->gd) {
+		struct gendisk *gd = dev->gd;
+		gd->queue = NULL;
+		del_gendisk(gd);
+		put_disk(gd);
+		dev->gd = NULL;
+	}
+	spin_unlock_irqrestore(dev->req_queue->queue_lock, flags);
+	dev->req_queue = NULL;
+	dev->i2odev = NULL;
+	dev->refcnt = 0;
+	dev->tid = 0;
 
 	/* 
 	 * Do we need this?
 	 * The media didn't really change...the device is just gone
 	 */
-	i2ob_media_change_flag[unit] = 1;
+	dev->media_change_flag = 1;
 
 	i2ob_dev_count--;	
 }
@@ -1511,10 +1475,9 @@ void i2ob_del_device(struct i2o_controll
 static int i2ob_media_change(struct gendisk *disk)
 {
 	struct i2ob_device *p = disk->private_data;
-	int i = p->index;
-	if(i2ob_media_change_flag[i])
+	if(p->media_change_flag)
 	{
-		i2ob_media_change_flag[i]=0;
+		p->media_change_flag=0;
 		return 1;
 	}
 	return 0;
@@ -1523,7 +1486,7 @@ static int i2ob_media_change(struct gend
 static int i2ob_revalidate(struct gendisk *disk)
 {
 	struct i2ob_device *p = disk->private_data;
-	return i2ob_install_device(p->controller, p->i2odev, p->index<<4);
+	return i2ob_install_device(p->controller, p->i2odev, p->index);
 }
 
 /*
@@ -1536,7 +1499,7 @@ static void i2ob_reboot_event(void)
 	
 	for(i=0;i<MAX_I2OB;i++)
 	{
-		struct i2ob_device *dev=&i2ob_dev[(i<<4)];
+		struct i2ob_device *dev=&i2ob_dev[i];
 		
 		if(dev->refcnt!=0)
 		{
@@ -1598,51 +1561,36 @@ static int i2o_block_init(void)
 	if (register_blkdev(MAJOR_NR, "i2o_block"))
 		return -EIO;
 
-	for (i = 0; i < MAX_I2OB; i++) {
-		struct gendisk *disk = alloc_disk(16);
-		if (!disk)
-			goto oom;
-		i2ob_dev[i<<4].index = i;
-		disk->queue = i2ob_dev[i<<4].req_queue;
-		i2ob_disk[i] = disk;
-	}
 #ifdef MODULE
 	printk(KERN_INFO "i2o_block: registered device at major %d\n", MAJOR_NR);
 #endif
 
 	/*
+	 *	Set up the queue
+	 */
+	for(i = 0; i < MAX_I2O_CONTROLLERS; i++)
+		i2ob_queues[i] = NULL;
+
+	/*
 	 *	Now fill in the boiler plate
 	 */
 	 
-	for (i = 0; i < MAX_I2OB << 4; i++) {
-		i2ob_dev[i].refcnt = 0;
-		i2ob_dev[i].flags = 0;
-		i2ob_dev[i].controller = NULL;
-		i2ob_dev[i].i2odev = NULL;
-		i2ob_dev[i].tid = 0;
-		i2ob_dev[i].head = NULL;
-		i2ob_dev[i].tail = NULL;
-		i2ob_dev[i].depth = MAX_I2OB_DEPTH;
-		i2ob_max_sectors[i] = 2;
-	}
-	
 	for (i = 0; i < MAX_I2OB; i++) {
-		struct gendisk *disk = i2ob_disk[i];
-		disk->major = MAJOR_NR;
-		disk->first_minor = i<<4;
-		disk->fops = &i2ob_fops;
-		sprintf(disk->disk_name, "i2o/hd%c", 'a' + i);
+		struct i2ob_device *dev = &i2ob_dev[i];
+		dev->index = i;
+		dev->refcnt = 0;
+		dev->flags = 0;
+		dev->controller = NULL;
+		dev->i2odev = NULL;
+		dev->tid = 0;
+		dev->head = NULL;
+		dev->tail = NULL;
+		dev->depth = MAX_I2OB_DEPTH;
+		dev->max_sectors = 2;
+		dev->gd = NULL;
 	}
 	
 	/*
-	 *	Set up the queue
-	 */
-	for(i = 0; i < MAX_I2O_CONTROLLERS; i++)
-	{
-		i2ob_queues[i] = NULL;
-	}
-
-	/*
 	 *	Register the OSM handler as we will need this to probe for
 	 *	drives, geometry and other goodies.
 	 */
@@ -1671,9 +1619,6 @@ static int i2o_block_init(void)
 
 	return 0;
 
-oom:
-	while (i--)
-		put_disk(i2ob_disk[i]);
 	unregister_blkdev(MAJOR_NR, "i2o_block");
 	return -ENOMEM;
 }
@@ -1701,11 +1646,8 @@ static void i2o_block_exit(void)
 	if(i2ob_dev_count) {
 		struct i2o_device *d;
 		for(i = 0; i < MAX_I2OB; i++)
-		if((d=i2ob_dev[i<<4].i2odev)) {
-			i2o_device_notify_off(d, &i2o_block_handler);
-			i2o_event_register(d->controller, d->lct_data.tid, 
-				i2ob_context, i<<4, 0);
-		}
+			if((d = i2ob_dev[i].i2odev))
+				i2ob_del_device(d->controller, d);
 	}
 	
 	/*
@@ -1725,15 +1667,21 @@ static void i2o_block_exit(void)
 	 */
 
 	i2o_remove_handler(&i2o_block_handler);
-		 
-	for (i = 0; i < MAX_I2OB; i++)
-		put_disk(i2ob_disk[i]);
 
 	/*
 	 *	Return the block device
 	 */
 	if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0)
 		printk("i2o_block: cleanup_module failed\n");
+
+	/*
+	 *	release request queue
+	 */
+	for (i = 0; i < MAX_I2O_CONTROLLERS; i ++)
+		if(i2ob_queues[i]) {
+			blk_cleanup_queue(i2ob_queues[i]->req_queue);
+			kfree(i2ob_queues[i]);
+		}
 }
 
 MODULE_AUTHOR("Red Hat");

_