From: Markus Lidel --- 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 */ _