Commit 7c11ccc5 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] I2O subsystem fixing and cleanup for 2.6 - i2o-64-bit-fix.patch

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

* provides i2o_context_list_*() functions, which maps 64-bit pointers to
  32-bit context id's in a dynamic list.  On 32-bit systems the functions are
  replaced with a static inline.

* i2o_scsi now uses the i2o_context_list_*() functions for transaction
  context, and therefore now work on 64-bit systems too.
parent 96005e5a
...@@ -213,6 +213,135 @@ static struct notifier_block i2o_reboot_notifier = ...@@ -213,6 +213,135 @@ static struct notifier_block i2o_reboot_notifier =
static int verbose; 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 * I2O Core reply handler
*/ */
...@@ -3551,6 +3680,10 @@ int __init i2o_pci_install(struct pci_dev *dev) ...@@ -3551,6 +3680,10 @@ int __init i2o_pci_install(struct pci_dev *dev)
c->short_req = 0; c->short_req = 0;
c->pdev = dev; c->pdev = dev;
#if BITS_PER_LONG == 64
c->context_list_lock = SPIN_LOCK_UNLOCKED;
#endif
c->irq_mask = mem+0x34; c->irq_mask = mem+0x34;
c->post_port = mem+0x40; c->post_port = mem+0x40;
c->reply_port = mem+0x44; c->reply_port = mem+0x44;
...@@ -3788,3 +3921,6 @@ EXPORT_SYMBOL(i2o_event_ack); ...@@ -3788,3 +3921,6 @@ EXPORT_SYMBOL(i2o_event_ack);
EXPORT_SYMBOL(i2o_report_status); EXPORT_SYMBOL(i2o_report_status);
EXPORT_SYMBOL(i2o_dump_message); EXPORT_SYMBOL(i2o_dump_message);
EXPORT_SYMBOL(i2o_get_class_name); EXPORT_SYMBOL(i2o_get_class_name);
EXPORT_SYMBOL(i2o_context_list_add);
EXPORT_SYMBOL(i2o_context_list_get);
EXPORT_SYMBOL(i2o_context_list_remove);
...@@ -62,9 +62,6 @@ ...@@ -62,9 +62,6 @@
#include "../../scsi/scsi.h" #include "../../scsi/scsi.h"
#include "../../scsi/hosts.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" #define VERSION_STRING "Version 0.1.2"
...@@ -233,7 +230,10 @@ static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, stru ...@@ -233,7 +230,10 @@ static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, stru
{ {
spin_unlock_irqrestore(&retry_lock, flags); spin_unlock_irqrestore(&retry_lock, flags);
/* Create a scsi error for this */ /* 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; lock = current_command->device->host->host_lock;
printk("Aborted %ld\n", current_command->serial_number); printk("Aborted %ld\n", current_command->serial_number);
...@@ -276,16 +276,15 @@ static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, stru ...@@ -276,16 +276,15 @@ static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, stru
printk(KERN_INFO "i2o_scsi: bus reset completed.\n"); printk(KERN_INFO "i2o_scsi: bus reset completed.\n");
return; 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 ? * Is this a control request coming back - eg an abort ?
*/ */
atomic_dec(&queue_depth);
if(current_command==NULL) if(current_command==NULL)
{ {
if(st) if(st)
...@@ -296,8 +295,6 @@ static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, stru ...@@ -296,8 +295,6 @@ static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, stru
dprintk(KERN_INFO "Completed %ld\n", current_command->serial_number); dprintk(KERN_INFO "Completed %ld\n", current_command->serial_number);
atomic_dec(&queue_depth);
if(st == 0x06) if(st == 0x06)
{ {
if(le32_to_cpu(m[5]) < current_command->underflow) if(le32_to_cpu(m[5]) < current_command->underflow)
...@@ -647,9 +644,7 @@ static int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) ...@@ -647,9 +644,7 @@ static int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
if(tid == -1) if(tid == -1)
{ {
SCpnt->result = DID_NO_CONNECT << 16; SCpnt->result = DID_NO_CONNECT << 16;
spin_lock_irqsave(host->host_lock, flags);
done(SCpnt); done(SCpnt);
spin_unlock_irqrestore(host->host_lock, flags);
return 0; return 0;
} }
...@@ -699,8 +694,7 @@ static int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) ...@@ -699,8 +694,7 @@ static int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
i2o_raw_writel(I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid, &msg[1]); 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 */ i2o_raw_writel(scsi_context, &msg[2]); /* So the I2O layer passes to us */
/* Sorry 64bit folks. FIXME */ i2o_raw_writel(i2o_context_list_add(SCpnt, c), &msg[3]); /* We want the SCSI control block back */
i2o_raw_writel((u32)SCpnt, &msg[3]); /* We want the SCSI control block back */
/* LSI_920_PCI_QUIRK /* LSI_920_PCI_QUIRK
* *
...@@ -883,7 +877,7 @@ static int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) ...@@ -883,7 +877,7 @@ static int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
* @SCpnt: command to abort * @SCpnt: command to abort
* *
* Ask the I2O controller to abort a command. This is an asynchrnous * 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. * with an aborted message if it succeeds.
* *
* Locks: no locks are held or needed * Locks: no locks are held or needed
...@@ -894,10 +888,9 @@ int i2o_scsi_abort(Scsi_Cmnd * SCpnt) ...@@ -894,10 +888,9 @@ int i2o_scsi_abort(Scsi_Cmnd * SCpnt)
struct i2o_controller *c; struct i2o_controller *c;
struct Scsi_Host *host; struct Scsi_Host *host;
struct i2o_scsi_host *hostdata; struct i2o_scsi_host *hostdata;
unsigned long msg; u32 msg[5];
u32 m;
int tid; int tid;
unsigned long timeout; int status = FAILED;
printk(KERN_WARNING "i2o_scsi: Aborting command block.\n"); printk(KERN_WARNING "i2o_scsi: Aborting command block.\n");
...@@ -907,37 +900,22 @@ int i2o_scsi_abort(Scsi_Cmnd * SCpnt) ...@@ -907,37 +900,22 @@ int i2o_scsi_abort(Scsi_Cmnd * SCpnt)
if(tid==-1) if(tid==-1)
{ {
printk(KERN_ERR "i2o_scsi: Impossible command to abort!\n"); printk(KERN_ERR "i2o_scsi: Impossible command to abort!\n");
return FAILED; return status;
} }
c = hostdata->controller; c = hostdata->controller;
spin_unlock_irq(host->host_lock); spin_unlock_irq(host->host_lock);
timeout = jiffies+2*HZ; msg[0] = FIVE_WORD_MSG_SIZE;
do msg[1] = I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid;
{ msg[2] = scsi_context;
m = le32_to_cpu(I2O_POST_READ32(c)); msg[3] = 0;
if(m != 0xFFFFFFFF) msg[4] = i2o_context_list_remove(SCpnt, c);
break; if(i2o_post_wait(c, msg, sizeof(msg), 240))
set_current_state(TASK_UNINTERRUPTIBLE); status = SUCCESS;
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();
spin_lock_irq(host->host_lock); spin_lock_irq(host->host_lock);
return SUCCESS; return status;
} }
/** /**
......
...@@ -75,6 +75,16 @@ struct i2o_device ...@@ -75,6 +75,16 @@ struct i2o_device
char dev_name[8]; /* linux /dev name if available */ char dev_name[8]; /* linux /dev name if available */
}; };
/*
* 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 * Each I2O controller has one of these objects
*/ */
...@@ -133,6 +143,11 @@ struct i2o_controller ...@@ -133,6 +143,11 @@ struct i2o_controller
void *page_frame; /* Message buffers */ void *page_frame; /* Message buffers */
dma_addr_t page_frame_map; /* Cache map */ 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(struct i2o_controller *); ...@@ -322,6 +337,27 @@ extern int i2o_activate_controller(struct i2o_controller *);
extern void i2o_run_queue(struct i2o_controller *); extern void i2o_run_queue(struct i2o_controller *);
extern int i2o_delete_controller(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 * Cache strategies
*/ */
...@@ -649,5 +685,9 @@ extern int i2o_delete_controller(struct i2o_controller *); ...@@ -649,5 +685,9 @@ extern int i2o_delete_controller(struct i2o_controller *);
#define I2O_POST_WAIT_OK 0 #define I2O_POST_WAIT_OK 0
#define I2O_POST_WAIT_TIMEOUT -ETIMEDOUT #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 /* __KERNEL__ */
#endif /* _I2O_H */ #endif /* _I2O_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment