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




---

 25-akpm/drivers/message/i2o/i2o_core.c |  136 +++++++++++++++++++++++++++++++++
 25-akpm/drivers/message/i2o/i2o_scsi.c |   64 +++++----------
 25-akpm/include/linux/i2o.h            |   40 +++++++++
 3 files changed, 197 insertions(+), 43 deletions(-)

diff -puN drivers/message/i2o/i2o_core.c~i2o-subsystem-fixing-and-cleanup-for-26-i2o-64-bit-fixpatch drivers/message/i2o/i2o_core.c
--- 25/drivers/message/i2o/i2o_core.c~i2o-subsystem-fixing-and-cleanup-for-26-i2o-64-bit-fixpatch	2004-04-30 03:27:28.437255328 -0700
+++ 25-akpm/drivers/message/i2o/i2o_core.c	2004-04-30 03:27:28.457252288 -0700
@@ -213,6 +213,135 @@ static struct notifier_block i2o_reboot_
 
 static int verbose;
 
+#if BITS_PER_LONG == 64
+/**
+ *      i2o_context_list_add -	append an ptr to the context list and return a
+ *				matching context id.
+ *	@ptr: pointer to add to the context list
+ *	@c: controller to which the context list belong
+ *	returns context id, which could be used in the transaction context
+ *	field.
+ *
+ *	Because the context field in I2O is only 32-bit large, on 64-bit the
+ *	pointer is to large to fit in the context field. The i2o_context_list
+ *	functiones map pointers to context fields.
+ */
+u32 i2o_context_list_add(void *ptr, struct i2o_controller *c) {
+	u32 context = 1;
+	struct i2o_context_list_element **entry = &c->context_list;
+	struct i2o_context_list_element *element;
+	unsigned long flags;
+
+	spin_lock_irqsave(&c->context_list_lock, flags);
+	while(*entry && ((*entry)->flags & I2O_CONTEXT_LIST_USED)) {
+		if((*entry)->context >= context)
+			context = (*entry)->context + 1;
+		entry = &((*entry)->next);
+	}
+
+	if(!*entry) {
+		if(unlikely(!context)) {
+			spin_unlock_irqrestore(&c->context_list_lock, flags);
+			printk(KERN_EMERG "i2o_core: context list overflow\n");
+			return 0;
+		}
+
+		element = kmalloc(sizeof(struct i2o_context_list_element), GFP_KERNEL);
+		if(!element) {
+			printk(KERN_EMERG "i2o_core: could not allocate memory for context list element\n");
+			return 0;
+		}
+		element->context = context;
+		element->next = NULL;
+		*entry = element;
+	} else
+		element = *entry;
+
+	element->ptr = ptr;
+	element->flags = I2O_CONTEXT_LIST_USED;
+
+	spin_unlock_irqrestore(&c->context_list_lock, flags);
+	dprintk(KERN_DEBUG "i2o_core: add context to list %p -> %d\n", ptr, context);
+	return context;
+}
+
+/**
+ *      i2o_context_list_remove - remove a ptr from the context list and return
+ *				  the matching context id.
+ *	@ptr: pointer to be removed from the context list
+ *	@c: controller to which the context list belong
+ *	returns context id, which could be used in the transaction context
+ *	field.
+ */
+u32 i2o_context_list_remove(void *ptr, struct i2o_controller *c) {
+	struct i2o_context_list_element **entry = &c->context_list;
+	struct i2o_context_list_element *element;
+	u32 context;
+	unsigned long flags;
+
+	spin_lock_irqsave(&c->context_list_lock, flags);
+	while(*entry && ((*entry)->ptr != ptr))
+		entry = &((*entry)->next);
+
+	if(unlikely(!*entry)) {
+		spin_unlock_irqrestore(&c->context_list_lock, flags);
+		printk(KERN_WARNING "i2o_core: could not remove nonexistent ptr %p\n", ptr);
+		return 0;
+	}
+
+	element = *entry;
+
+	context = element->context;
+	element->ptr = NULL;
+	element->flags |= I2O_CONTEXT_LIST_DELETED;
+
+	spin_unlock_irqrestore(&c->context_list_lock, flags);
+	dprintk(KERN_DEBUG "i2o_core: markt as deleted in context list %p -> %d\n", ptr, context);
+	return context;
+}
+
+/**
+ *      i2o_context_list_get -	get a ptr from the context list and remove it
+ *				from the list.
+ *	@context: context id to which the pointer belong
+ *	@c: controller to which the context list belong
+ *	returns pointer to the matching context id
+ */
+void *i2o_context_list_get(u32 context, struct i2o_controller *c) {
+	struct i2o_context_list_element **entry = &c->context_list;
+	struct i2o_context_list_element *element;
+	void *ptr;
+	int count = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&c->context_list_lock, flags);
+	while(*entry && ((*entry)->context != context)) {
+		entry = &((*entry)->next);
+		count ++;
+	}
+
+	if(unlikely(!*entry)) {
+		spin_unlock_irqrestore(&c->context_list_lock, flags);
+		printk(KERN_WARNING "i2o_core: context id %d not found\n", context);
+		return NULL;
+	}
+
+	element = *entry;
+	ptr = element->ptr;
+	if(count >= I2O_CONTEXT_LIST_MIN_LENGTH) {
+		*entry = (*entry)->next;
+		kfree(element);
+	} else {
+		element->ptr = NULL;
+		element->flags &= !I2O_CONTEXT_LIST_USED;
+	}
+
+	spin_unlock_irqrestore(&c->context_list_lock, flags);
+	dprintk(KERN_DEBUG "i2o_core: get ptr from context list %d -> %p\n", context, ptr);
+	return ptr;
+}
+#endif
+
 /*
  * I2O Core reply handler
  */
@@ -3551,6 +3680,10 @@ int __init i2o_pci_install(struct pci_de
 	c->short_req = 0;
 	c->pdev = dev;
 
+#if BITS_PER_LONG == 64
+	c->context_list_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
 	c->irq_mask = mem+0x34;
 	c->post_port = mem+0x40;
 	c->reply_port = mem+0x44;
@@ -3788,3 +3921,6 @@ EXPORT_SYMBOL(i2o_event_ack);
 EXPORT_SYMBOL(i2o_report_status);
 EXPORT_SYMBOL(i2o_dump_message);
 EXPORT_SYMBOL(i2o_get_class_name);
+EXPORT_SYMBOL(i2o_context_list_add);
+EXPORT_SYMBOL(i2o_context_list_get);
+EXPORT_SYMBOL(i2o_context_list_remove);
diff -puN drivers/message/i2o/i2o_scsi.c~i2o-subsystem-fixing-and-cleanup-for-26-i2o-64-bit-fixpatch drivers/message/i2o/i2o_scsi.c
--- 25/drivers/message/i2o/i2o_scsi.c~i2o-subsystem-fixing-and-cleanup-for-26-i2o-64-bit-fixpatch	2004-04-30 03:27:28.438255176 -0700
+++ 25-akpm/drivers/message/i2o/i2o_scsi.c	2004-04-30 03:27:28.459251984 -0700
@@ -62,9 +62,6 @@
 #include "../../scsi/scsi.h"
 #include "../../scsi/hosts.h"
 
-#if BITS_PER_LONG == 64
-#error FIXME: driver does not support 64-bit platforms
-#endif
 
 
 #define VERSION_STRING        "Version 0.1.2"
@@ -233,7 +230,10 @@ static void i2o_scsi_reply(struct i2o_ha
 		{
 			spin_unlock_irqrestore(&retry_lock, flags);
 			/* Create a scsi error for this */
-			current_command = (Scsi_Cmnd *)m[3];
+			current_command = (Scsi_Cmnd *)i2o_context_list_get(m[3], c);
+			if(!current_command)
+				return;
+
 			lock = current_command->device->host->host_lock;
 			printk("Aborted %ld\n", current_command->serial_number);
 
@@ -276,16 +276,15 @@ static void i2o_scsi_reply(struct i2o_ha
 		printk(KERN_INFO "i2o_scsi: bus reset completed.\n");
 		return;
 	}
-	/*
- 	 *	FIXME: 64bit breakage
-	 */
 
-	current_command = (Scsi_Cmnd *)m[3];
+	current_command = (Scsi_Cmnd *)i2o_context_list_get(m[3], c);
 	
 	/*
 	 *	Is this a control request coming back - eg an abort ?
 	 */
 	 
+	atomic_dec(&queue_depth);
+
 	if(current_command==NULL)
 	{
 		if(st)
@@ -296,8 +295,6 @@ static void i2o_scsi_reply(struct i2o_ha
 	
 	dprintk(KERN_INFO "Completed %ld\n", current_command->serial_number);
 	
-	atomic_dec(&queue_depth);
-	
 	if(st == 0x06)
 	{
 		if(le32_to_cpu(m[5]) < current_command->underflow)
@@ -647,9 +644,7 @@ static int i2o_scsi_queuecommand(Scsi_Cm
 	if(tid == -1)
 	{
 		SCpnt->result = DID_NO_CONNECT << 16;
-		spin_lock_irqsave(host->host_lock, flags);
 		done(SCpnt);
-		spin_unlock_irqrestore(host->host_lock, flags);
 		return 0;
 	}
 	
@@ -699,8 +694,7 @@ static int i2o_scsi_queuecommand(Scsi_Cm
 	
 	i2o_raw_writel(I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid, &msg[1]);
 	i2o_raw_writel(scsi_context, &msg[2]);	/* So the I2O layer passes to us */
-	/* Sorry 64bit folks. FIXME */
-	i2o_raw_writel((u32)SCpnt, &msg[3]);	/* We want the SCSI control block back */
+	i2o_raw_writel(i2o_context_list_add(SCpnt, c), &msg[3]);	/* We want the SCSI control block back */
 
 	/* LSI_920_PCI_QUIRK
 	 *
@@ -883,7 +877,7 @@ static int i2o_scsi_queuecommand(Scsi_Cm
  *	@SCpnt: command to abort
  *
  *	Ask the I2O controller to abort a command. This is an asynchrnous
- *	process and oru callback handler will see the command complete
+ *	process and our callback handler will see the command complete
  *	with an aborted message if it succeeds. 
  *
  *	Locks: no locks are held or needed
@@ -894,10 +888,9 @@ int i2o_scsi_abort(Scsi_Cmnd * SCpnt)
 	struct i2o_controller *c;
 	struct Scsi_Host *host;
 	struct i2o_scsi_host *hostdata;
-	unsigned long msg;
-	u32 m;
+	u32 msg[5];
 	int tid;
-	unsigned long timeout;
+	int status = FAILED;
 	
 	printk(KERN_WARNING "i2o_scsi: Aborting command block.\n");
 	
@@ -907,37 +900,22 @@ int i2o_scsi_abort(Scsi_Cmnd * SCpnt)
 	if(tid==-1)
 	{
 		printk(KERN_ERR "i2o_scsi: Impossible command to abort!\n");
-		return FAILED;
+		return status;
 	}
 	c = hostdata->controller;
 
 	spin_unlock_irq(host->host_lock);
 		
-	timeout = jiffies+2*HZ;
-	do
-	{
-		m = le32_to_cpu(I2O_POST_READ32(c));
-		if(m != 0xFFFFFFFF)
-			break;
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(1);
-		mb();
-	}
-	while(time_before(jiffies, timeout));
-	
-	msg = c->mem_offset + m;
-	
-	i2o_raw_writel(FIVE_WORD_MSG_SIZE, msg);
-	i2o_raw_writel(I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid, msg+4);
-	i2o_raw_writel(scsi_context, msg+8);
-	i2o_raw_writel(0, msg+12);	/* Not needed for an abort */
-	i2o_raw_writel((u32)SCpnt, msg+16);	
-	wmb();
-	i2o_post_message(c,m);
-	wmb();
-	
+	msg[0] = FIVE_WORD_MSG_SIZE;
+	msg[1] = I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid;
+	msg[2] = scsi_context;
+	msg[3] = 0;
+	msg[4] = i2o_context_list_remove(SCpnt, c);
+	if(i2o_post_wait(c, msg, sizeof(msg), 240))
+		status = SUCCESS;
+
 	spin_lock_irq(host->host_lock);
-	return SUCCESS;
+	return status;
 }
 
 /**
diff -puN include/linux/i2o.h~i2o-subsystem-fixing-and-cleanup-for-26-i2o-64-bit-fixpatch include/linux/i2o.h
--- 25/include/linux/i2o.h~i2o-subsystem-fixing-and-cleanup-for-26-i2o-64-bit-fixpatch	2004-04-30 03:27:28.440254872 -0700
+++ 25-akpm/include/linux/i2o.h	2004-04-30 03:27:28.460251832 -0700
@@ -76,6 +76,16 @@ struct i2o_device
 };
 
 /*
+ * context queue entry, used for 32-bit context on 64-bit systems
+ */
+struct i2o_context_list_element {
+	struct i2o_context_list_element *next;
+	u32 context;
+	void *ptr;
+	unsigned int flags;
+};
+
+/*
  * Each I2O controller has one of these objects
  */
 struct i2o_controller
@@ -133,6 +143,11 @@ struct i2o_controller
 
 	void *page_frame;			/* Message buffers */
 	dma_addr_t page_frame_map;		/* Cache map */
+#if BITS_PER_LONG == 64
+	spinlock_t context_list_lock;		/* lock for context_list */
+	struct i2o_context_list_element *context_list; /* list of context id's
+						    and pointers */
+#endif
 };
 
 /*
@@ -322,6 +337,27 @@ extern int i2o_activate_controller(struc
 extern void i2o_run_queue(struct i2o_controller *);
 extern int i2o_delete_controller(struct i2o_controller *);
 
+#if BITS_PER_LONG == 64
+extern u32 i2o_context_list_add(void *, struct i2o_controller *);
+extern void *i2o_context_list_get(u32, struct i2o_controller *);
+extern u32 i2o_context_list_remove(void *, struct i2o_controller *);
+#else
+static inline u32 i2o_context_list_add(void *ptr, struct i2o_controller *c)
+{
+	return (u32)ptr;
+}
+
+static inline void *i2o_context_list_get(u32 context, struct i2o_controller *c)
+{
+	return (void *)context;
+}
+
+static inline u32 i2o_context_list_remove(void *ptr, struct i2o_controller *c)
+{
+	return (u32)ptr;
+}
+#endif
+
 /*
  *	Cache strategies
  */
@@ -649,5 +685,9 @@ extern int i2o_delete_controller(struct 
 #define I2O_POST_WAIT_OK	0
 #define I2O_POST_WAIT_TIMEOUT	-ETIMEDOUT
 
+#define I2O_CONTEXT_LIST_MIN_LENGTH	15
+#define I2O_CONTEXT_LIST_USED		0x01
+#define I2O_CONTEXT_LIST_DELETED	0x02
+
 #endif /* __KERNEL__ */
 #endif /* _I2O_H */

_