patch-2.3.24 linux/drivers/i2o/i2o_core.c
Next file: linux/drivers/i2o/i2o_lan.c
Previous file: linux/drivers/i2o/i2o_config.c
Back to the patch index
Back to the overall index
- Lines: 2028
- Date:
Mon Oct 25 20:49:42 1999
- Orig file:
v2.3.23/linux/drivers/i2o/i2o_core.c
- Orig date:
Mon Oct 4 15:49:29 1999
diff -u --recursive --new-file v2.3.23/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c
@@ -1,22 +1,24 @@
-/*
- * Core I2O structure managment
- *
- * (C) Copyright 1999 Red Hat Software
+/*
+ * Core I2O structure managment
+ *
+ * (C) Copyright 1999 Red Hat Software
*
- * Written by Alan Cox, Building Number Three Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
+ * Written by Alan Cox, Building Number Three Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * A lot of the I2O message side code from this is taken from the
+ * Red Creek RCPCI45 adapter driver by Red Creek Communications
*
- * A lot of the I2O message side code from this is taken from the
- * Red Creek RCPCI45 adapter driver by Red Creek Communications
- *
- * Fixes by Philipp Rumpf
- * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
- * Deepak Saxena <deepak@plexity.net>
+ * Fixes by:
+ * Philipp Rumpf
+ * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ * Deepak Saxena <deepak@plexity.net>
+ *
*/
#include <linux/config.h>
@@ -31,11 +33,16 @@
#include <linux/malloc.h>
#include <linux/spinlock.h>
+#include <linux/bitops.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+
#include <asm/io.h>
#include "i2o_lan.h"
#define DRIVERDEBUG
+// #define DEBUG_IRQ
/*
* Size of the I2O module table
@@ -48,12 +55,36 @@
static int reply_flag = 0;
extern int i2o_online_controller(struct i2o_controller *c);
+static int i2o_init_outbound_q(struct i2o_controller *c);
static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *,
struct i2o_message *);
static int i2o_add_management_user(struct i2o_device *, struct i2o_handler *);
static int i2o_remove_management_user(struct i2o_device *, struct i2o_handler *);
+static int i2o_quiesce_system(void);
+static int i2o_enable_system(void);
static void i2o_dump_message(u32 *);
+static int i2o_lct_get(struct i2o_controller *);
+static int i2o_hrt_get(struct i2o_controller *);
+
+static void i2o_sys_init(void);
+static void i2o_sys_shutdown(void);
+
+static int i2o_build_sys_table(void);
+static int i2o_systab_send(struct i2o_controller *c);
+
+/*
+ * I2O System Table. Contains information about
+ * all the IOPs in the system. Used to inform IOPs
+ * about each other's existence.
+ *
+ * sys_tbl_ver is the CurrentChangeIndicator that is
+ * used by IOPs to track changes.
+ */
+static struct i2o_sys_tbl *sys_tbl = NULL;
+static int sys_tbl_ind = 0;
+static int sys_tbl_len = 0;
+
#ifdef MODULE
/*
* Function table to send to bus specific layers
@@ -76,6 +107,21 @@
#endif /* MODULE */
+/*
+ * Structures and definitions for synchronous message posting.
+ * See i2o_post_wait() for description.
+ */
+struct i2o_post_wait_data
+{
+ int status;
+ u32 id;
+ wait_queue_head_t *wq;
+ struct i2o_post_wait_data *next;
+};
+static struct i2o_post_wait_data *post_wait_queue = NULL;
+static u32 post_wait_id = 0; // Unique ID for each post_wait
+static spinlock_t post_wait_lock = SPIN_LOCK_UNLOCKED;
+static void i2o_post_wait_complete(u32, int);
/* Message handler */
static struct i2o_handler i2o_core_handler =
@@ -85,6 +131,7 @@
0
};
+
/*
* I2O configuration spinlock. This isnt a big deal for contention
* so we have one only
@@ -92,11 +139,17 @@
static spinlock_t i2o_configuration_lock = SPIN_LOCK_UNLOCKED;
+/*
+ * I2O Core reply handler
+ *
+ * Only messages this should see are i2o_post_wait() replies
+ */
void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c,
struct i2o_message *m)
{
u32 *msg=(u32 *)m;
- u32 *flag = (u32 *)msg[3];
+ u32 status;
+ u32 context = msg[3];
#if 0
i2o_report_status(KERN_INFO, "i2o_core", msg);
@@ -117,13 +170,18 @@
return;
}
- if (msg[4] >> 24)
+ if(msg[2]&0x80000000) // Post wait message
{
- i2o_report_status(KERN_WARNING, "i2o_core", msg);
- *flag = -(msg[4] & 0xFFFF);
+ if (msg[4] >> 24)
+ {
+ i2o_report_status(KERN_WARNING, "i2o_core: post_wait reply", msg);
+ status = -(msg[4] & 0xFFFF);
+ }
+ else
+ status = I2O_POST_WAIT_OK;
+
+ i2o_post_wait_complete(context, status);
}
- else
- *flag = I2O_POST_WAIT_OK;
}
/*
@@ -245,6 +303,12 @@
c->next=i2o_controller_chain;
i2o_controller_chain=c;
c->unit = i;
+ c->page_frame = NULL;
+ c->hrt = NULL;
+ c->lct = NULL;
+ c->status_block = NULL;
+ printk(KERN_INFO "lct @ %p hrt @ %p status @ %p",
+ c->lct, c->hrt, c->status_block);
sprintf(c->name, "i2o/iop%d", i);
i2o_num_controllers++;
spin_unlock(&i2o_configuration_lock);
@@ -261,10 +325,14 @@
struct i2o_controller **p;
int users;
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "Deleting controller iop%d\n", c->unit);
+#endif
+
spin_lock(&i2o_configuration_lock);
if((users=atomic_read(&c->users)))
{
- printk("I2O: %d users for controller iop%d\n", users, c->unit);
+ printk(KERN_INFO "I2O: %d users for controller iop%d\n", users, c->unit);
spin_unlock(&i2o_configuration_lock);
return -EBUSY;
}
@@ -280,21 +348,6 @@
p=&i2o_controller_chain;
- /* Send first SysQuiesce to other IOPs */
- while(*p)
- {
- if(*p!=c)
- {
- printk("Quiescing controller %p != %p\n", c, *p);
- if(i2o_quiesce_controller(*p)<0)
- printk(KERN_INFO "Unable to quiesce iop%d\n",
- (*p)->unit);
- }
- p=&((*p)->next);
- }
-
- p=&i2o_controller_chain;
-
while(*p)
{
if(*p==c)
@@ -308,15 +361,26 @@
*p=c->next;
spin_unlock(&i2o_configuration_lock);
+
+ printk(KERN_INFO "hrt %p lct %p page_frame %p status_block %p\n",
+ c->hrt, c->lct, c->page_frame, c->status_block);
if(c->page_frame)
kfree(c->page_frame);
if(c->hrt)
kfree(c->hrt);
if(c->lct)
kfree(c->lct);
- i2o_controllers[c->unit]=NULL;
+ if(c->status_block)
+ kfree(c->status_block);
+
kfree(c);
+
+ i2o_controllers[c->unit]=NULL;
+
i2o_num_controllers--;
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "iop deleted\n");
+#endif
return 0;
}
p=&((*p)->next);
@@ -360,7 +424,7 @@
return -EBUSY;
}
- if(i2o_issue_claim(d->controller,d->id, h->context, 1, &reply_flag, type) < 0)
+ if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 1, &reply_flag, type))
{
return -EBUSY;
}
@@ -395,8 +459,8 @@
err = -ENOENT;
else
{
- if(i2o_issue_claim(d->controller, d->id, h->context, 0,
- &reply_flag, type) < 0)
+ if(i2o_issue_claim(d->controller, d->lct_data->tid, h->context, 0,
+ &reply_flag, type))
{
err = -ENXIO;
}
@@ -418,8 +482,8 @@
{
atomic_dec(&d->controller->users);
- if(i2o_issue_claim(d->controller,d->id, h->context, 0,
- &reply_flag, type) < 0)
+ if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 0,
+ &reply_flag, type))
err = -ENXIO;
}
@@ -468,7 +532,11 @@
{
struct i2o_message *m;
u32 mv;
-
+
+#ifdef DEBUG_IRQ
+ printk(KERN_INFO "iop%d interrupt\n", c->unit);
+#endif
+
while((mv=I2O_REPLY_READ32(c))!=0xFFFFFFFF)
{
struct i2o_handler *i;
@@ -478,7 +546,11 @@
*/
if(((m->function_addr>>24)&0xFF)==0x15)
printk("UTFR!\n");
-// printk("dispatching.\n");
+
+#ifdef DEBUG_IRQ
+ i2o_dump_message((u32*)m);
+#endif
+
i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)];
if(i)
i->reply(i,c,m);
@@ -572,8 +644,10 @@
{
if((jiffies-time)>=5*HZ)
{
+#ifdef DRIVERDEBUG
printk(KERN_ERR "%s: Timeout waiting for message frame to send %s.\n",
c->name, why);
+#endif
return 0xFFFFFFFF;
}
schedule();
@@ -596,8 +670,10 @@
{
if(jiffies-time >= timeout*HZ )
{
+#ifdef DRIVERDEBUG
printk(KERN_ERR "%s: timeout waiting for %s reply.\n",
c->name, why);
+#endif
return 0xFFFFFFFF;
}
schedule();
@@ -686,8 +762,10 @@
/* Do we have an error block ? */
if(p[1]&0xFF000000)
{
+#ifdef DRIVERDEBUG
printk(KERN_ERR "%s: error in field read.\n",
c->name);
+#endif
kfree(rbuf);
return -EBADR;
}
@@ -711,25 +789,27 @@
void i2o_report_controller_unit(struct i2o_controller *c, int unit)
{
char buf[64];
+ return;
- if(i2o_query_scalar_polled(c, unit, buf, 16, 0xF100, 3)>=0)
+ if(i2o_query_scalar(c, unit, 0xF100, 3, buf, 16))
{
buf[16]=0;
printk(KERN_INFO " Vendor: %s\n", buf);
}
- if(i2o_query_scalar_polled(c, unit, buf, 16, 0xF100, 4)>=0)
+ if(i2o_query_scalar(c, unit, 0xF100, 4, buf, 16))
{
+
buf[16]=0;
printk(KERN_INFO " Device: %s\n", buf);
}
#if 0
- if(i2o_query_scalar_polled(c, unit, buf, 16, 0xF100, 5)>=0)
+ if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16))
{
buf[16]=0;
printk(KERN_INFO "Description: %s\n", buf);
}
#endif
- if(i2o_query_scalar_polled(c, unit, buf, 8, 0xF100, 6)>=0)
+ if(i2o_query_scalar(c, unit, 0xF100, 6, buf, 8))
{
buf[8]=0;
printk(KERN_INFO " Rev: %s\n", buf);
@@ -749,6 +829,7 @@
static int i2o_parse_hrt(struct i2o_controller *c)
{
+#ifdef DRIVERDEBUG
u32 *rows=c->hrt;
u8 *p=(u8 *)c->hrt;
u8 *d;
@@ -766,8 +847,8 @@
count=p[0]|(p[1]<<8);
length = p[2];
- printk(KERN_INFO "HRT has %d entries of %d bytes each.\n",
- count, length<<2);
+ printk(KERN_INFO "iop%d: HRT has %d entries of %d bytes each.\n",
+ c->unit, count, length<<2);
rows+=2;
@@ -829,6 +910,7 @@
printk("\n");
rows+=length;
}
+#endif
return 0;
}
@@ -845,12 +927,12 @@
u32 *p;
struct i2o_device *d;
char str[22];
- u32 *lct=(u32 *)c->lct;
+ pi2o_lct lct = c->lct;
- max=lct[0]&0xFFFF;
+ max = lct->table_size;
- max-=3;
- max/=9;
+ max -= 3;
+ max /= 9;
if(max==0)
{
@@ -866,28 +948,25 @@
max=128;
}
- if(lct[1]&(1<<0))
- printk(KERN_WARNING "Configuration dialog desired.\n");
+ if(lct->iop_flags&(1<<0))
+ printk(KERN_WARNING "I2O: Configuration dialog desired by iop%d.\n", c->unit);
- p=lct+3;
-
for(i=0;i<max;i++)
{
d = (struct i2o_device *)kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
if(d==NULL)
{
- printk("i2o_core: Out of memory for LCT data.\n");
+ printk("i2o_core: Out of memory for I2O device data.\n");
return -ENOMEM;
}
d->controller = c;
d->next = NULL;
-
- d->id = tid = (p[0]>>16)&0xFFF;
- d->class = p[3]&0xFFF;
- d->subclass = p[4]&0xFFF;
- d->parent = (p[5]>>12)&0xFFF;
+
+ d->lct_data = &lct->lct_entry[i];
+
d->flags = 0;
+ tid = d->lct_data->tid;
printk(KERN_INFO "TID %d.\n", tid);
@@ -897,19 +976,19 @@
printk(KERN_INFO " Class: ");
- sprintf(str, "%-21s", i2o_get_class_name(d->class));
+ sprintf(str, "%-21s", i2o_get_class_name(d->lct_data->class_id));
printk("%s", str);
printk(" Subclass: 0x%03X Flags: ",
- d->subclass);
+ d->lct_data->sub_class);
- if(p[2]&(1<<0))
+ if(d->lct_data->device_flags&(1<<0))
printk("C"); // ConfigDialog requested
- if(p[2]&(1<<1))
+ if(d->lct_data->device_flags&(1<<1))
printk("M"); // Multi-user capable
- if(!(p[2]&(1<<4)))
+ if(!(d->lct_data->device_flags&(1<<4)))
printk("P"); // Peer service enabled!
- if(!(p[2]&(1<<5)))
+ if(!(d->lct_data->device_flags&(1<<5)))
printk("m"); // Mgmt service enabled!
printk("\n");
p+=9;
@@ -917,30 +996,120 @@
return 0;
}
+
/* Quiesce IOP */
int i2o_quiesce_controller(struct i2o_controller *c)
{
u32 msg[4];
+ if(c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL)
+ return -EINVAL;
+
msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
- msg[2]=core_context;
+ msg[2]=(u32)core_context;
msg[3]=(u32)&reply_flag;
/* Long timeout needed for quiesce if lots of devices */
- return i2o_post_wait(c, ADAPTER_TID, msg, sizeof(msg), &reply_flag, 120);
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "Posting quiesce message to iop%d\n", c->unit);
+#endif
+ if(i2o_post_wait(c, msg, sizeof(msg), 120))
+ return -1;
+ else
+ return 0;
+}
+
+/* Enable IOP */
+int i2o_enable_controller(struct i2o_controller *c)
+{
+ u32 msg[4];
+
+ msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+ msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID;
+ msg[2]=core_context;
+ msg[3]=(u32)&reply_flag;
+
+ /* How long of a timeout do we need? */
+ return i2o_post_wait(c, msg, sizeof(msg), 240);
+}
+
+/*
+ * Quiesce _all_ IOPs in OP state.
+ * Used during init/shutdown time.
+ */
+int i2o_quiesce_system(void)
+{
+ struct i2o_controller *iop;
+ int ret = 0;
+
+ for(iop=i2o_controller_chain; iop != NULL; iop=iop->next)
+ {
+ /*
+ * Quiesce only needed on operational IOPs
+ */
+ i2o_status_get(iop);
+
+ if(iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL)
+ {
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "Attempting to quiesce iop%d\n", iop->unit);
+#endif
+ if(i2o_quiesce_controller(iop))
+ {
+ printk(KERN_INFO "Unable to quiesce iop%d\n", iop->unit);
+ ret = -ENXIO;
+ }
+#ifdef DRIVERDEBUG
+ else
+ printk(KERN_INFO "%s quiesced\n", iop->name);
+#endif
+
+ i2o_status_get(iop); // Update IOP state information
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * (re)Enable _all_ IOPs in READY state.
+ */
+int i2o_enable_system(void)
+{
+ struct i2o_controller *iop;
+ int ret = 0;
+
+ for(iop=i2o_controller_chain; iop != NULL; iop=iop->next)
+ {
+ /*
+ * Enable only valid for IOPs in READY state
+ */
+ i2o_status_get(iop);
+
+ if(iop->status_block->iop_state == ADAPTER_STATE_READY)
+ {
+ if(i2o_enable_controller(iop)<0)
+ printk(KERN_INFO "Unable to (re)enable iop%d\n",
+ iop->unit);
+
+ i2o_status_get(iop); // Update IOP state information
+ }
+ }
+
+ return ret;
}
+/* Reset an IOP, but keep message queues alive */
int i2o_clear_controller(struct i2o_controller *c)
{
u32 msg[4];
+ int ret;
- /* First stop external operations for this IOP */
- if(i2o_quiesce_controller(c)<0)
- printk(KERN_INFO "Unable to quiesce iop%d\n", c->unit);
- else
- printk(KERN_INFO "Iop%d quiesced\n", c->unit);
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "Clearing iop%d\n", c->unit);
+#endif
/* Then clear the IOP */
msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
@@ -948,7 +1117,14 @@
msg[2]=core_context;
msg[3]=(u32)&reply_flag;
- return i2o_post_wait(c, ADAPTER_TID, msg, sizeof(msg), &reply_flag, 10);
+ if((ret=i2o_post_wait(c, msg, sizeof(msg), 30)))
+ printk(KERN_INFO "ExecIopClear failed: %#10x\n", ret);
+#ifdef DRIVERDEBUG
+ else
+ printk(KERN_INFO "ExecIopClear success!\n");
+#endif
+
+ return ret;
}
@@ -959,27 +1135,15 @@
u8 *work8;
u32 *msg;
long time;
- struct i2o_controller *iop;
- /* First stop external operations */
- for(iop=i2o_controller_chain; iop != NULL; iop=iop->next)
- {
- /* Quiesce is rejected on hold state */
- if(iop->status != ADAPTER_STATE_HOLD)
- {
- if(i2o_quiesce_controller(iop)<0)
- printk(KERN_INFO "Unable to quiesce iop%d\n",
- iop->unit);
- else
- printk(KERN_DEBUG "%s quiesced\n", iop->name);
- }
- }
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "Reseting iop%d\n", c->unit);
+#endif
- /* Then reset the IOP */
+ /* Get a message */
m=i2o_wait_message(c, "AdapterReset");
- if(m==0xFFFFFFFF)
+ if(m==0xFFFFFFFF)
return -ETIMEDOUT;
-
msg=(u32 *)(c->mem_offset+m);
work8=(void *)kmalloc(4, GFP_KERNEL);
@@ -999,12 +1163,16 @@
msg[6]=virt_to_phys(work8);
msg[7]=0; /* 64bit host FIXME */
+ /* Then reset the IOP */
i2o_post_message(c,m);
/* Wait for a reply */
time=jiffies;
- while(work8[0]==0x01)
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "Reset posted, waiting...\n");
+#endif
+ while(work8[0]==0)
{
if((jiffies-time)>=5*HZ)
{
@@ -1016,8 +1184,41 @@
barrier();
}
- if (work8[0]==0x02)
- printk(KERN_WARNING "IOP Reset rejected\n");
+ if (work8[0]==0x02)
+ {
+ printk(KERN_WARNING "IOP Reset rejected\n");
+ }
+ else
+ {
+ /*
+ * Once the reset is sent, the IOP goes into the INIT state
+ * which is inditerminate. We need to wait until the IOP
+ * has rebooted before we can let the system talk to
+ * it. We read the inbound Free_List until a message is
+ * available. If we can't read one in the given ammount of
+ * time, we assume the IOP could not reboot properly.
+ */
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "Reset succeeded...waiting for reboot\n");
+#endif
+ time = jiffies;
+ m = I2O_POST_READ32(c);
+ while(m == 0XFFFFFFFF)
+ {
+ if((jiffies-time) >= 30*HZ)
+ {
+ printk(KERN_ERR "i2o/iop%d: Timeout waiting for IOP reset.\n",
+ c->unit);
+ return -ETIMEDOUT;
+ }
+ schedule();
+ barrier();
+ m = I2O_POST_READ32(c);
+ }
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "Reboot completed\n");
+#endif
+ }
return 0;
}
@@ -1030,13 +1231,24 @@
u32 *msg;
u8 *status_block;
- status_block=(void *)kmalloc(88, GFP_KERNEL);
- if(status_block==NULL)
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "Getting status block for iop%d\n", c->unit);
+#endif
+ if(c->status_block)
+ kfree(c->status_block);
+
+ c->status_block =
+ (pi2o_status_block)kmalloc(sizeof(i2o_status_block),GFP_KERNEL);
+ if(c->status_block == NULL)
{
- printk(KERN_ERR "StatusGet failed - no free memory.\n");
+#ifdef DRIVERDEBUG
+ printk(KERN_ERR "No memory in status get!\n");
+#endif
return -ENOMEM;
}
+ status_block = (u8*)c->status_block;
+
m=i2o_wait_message(c, "StatusGet");
if(m==0xFFFFFFFF)
return -ETIMEDOUT;
@@ -1049,7 +1261,7 @@
msg[3]=0;
msg[4]=0;
msg[5]=0;
- msg[6]=virt_to_phys(status_block);
+ msg[6]=virt_to_phys(c->status_block);
msg[7]=0; /* 64bit host FIXME */
msg[8]=88;
@@ -1062,7 +1274,9 @@
{
if((jiffies-time)>=5*HZ)
{
+#ifdef DRIVERDEBUG
printk(KERN_ERR "IOP get status timeout.\n");
+#endif
return -ETIMEDOUT;
}
schedule();
@@ -1070,8 +1284,6 @@
}
/* Ok the reply has arrived. Fill in the important stuff */
- c->status = status_block[10];
- c->i2oversion = (status_block[9]>>4)&0xFF;
c->inbound_size = (status_block[12]|(status_block[13]<<8))*4;
return 0;
@@ -1080,8 +1292,10 @@
int i2o_hrt_get(struct i2o_controller *c)
{
- u32 m;
- u32 *msg;
+ u32 msg[6];
+
+ if(c->hrt)
+ kfree(c->hrt);
c->hrt=kmalloc(2048, GFP_KERNEL);
if(c->hrt==NULL)
@@ -1090,12 +1304,6 @@
return -ENOMEM;
}
- m=i2o_wait_message(c, "HRTGet");
- if(m==0xFFFFFFFF)
- return -ETIMEDOUT;
-
- msg=(u32 *)(c->mem_offset+m);
-
msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
msg[2]= core_context;
@@ -1103,134 +1311,271 @@
msg[4]= (0xD0000000 | 2048); /* Simple transaction , 2K */
msg[5]= virt_to_phys(c->hrt); /* Dump it here */
- i2o_post_message(c,m);
-
- barrier();
-
- /* Now wait for a reply */
- m=i2o_wait_reply(c, "HRTGet", 5);
+ return i2o_post_wait(c, msg, sizeof(msg), 20);
+}
- if(m==0xFFFFFFFF)
- return -ETIMEDOUT;
+static int i2o_systab_send(struct i2o_controller* iop)
+{
+ u32 msg[10];
+ u32 privmem[2];
+ u32 privio[2];
+ int ret;
- msg=(u32 *)bus_to_virt(m);
+ privmem[0]=iop->priv_mem; /* Private memory space base address */
+ privmem[1]=iop->priv_mem_size;
+ privio[0]=iop->priv_io; /* Private I/O address */
+ privio[1]=iop->priv_io_size;
- if(msg[4]>>24)
- i2o_report_status(KERN_WARNING, "i2o_core", msg);
+ msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_6;
+ msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
+ msg[2] = 0; /* Context not needed */
+ msg[3] = 0;
+ msg[4] = (0<<16)|((iop->unit+2)<<12); /* Host 0 IOP ID (unit + 2) */
+ msg[5] = 0; /* Segment 0 */
+
+ /*
+ * Scatter Gather List
+ */
+ msg[6] = 0x54000000|sys_tbl_len;
+ msg[7] = virt_to_phys(sys_tbl);
+ msg[8] = 0xD4000000|48; /* One table for now */
+ msg[9] = virt_to_phys(privmem);
+/* msg[10] = virt_to_phys(privio); */
- I2O_REPLY_WRITE32(c,m);
+ ret=i2o_post_wait(iop, msg, sizeof(msg), 120);
+ if(ret)
+ return ret;
return 0;
}
-
/*
- * Bring an I2O controller into HOLD state. See the 1.5
- * spec. Basically we go
- *
- * Wait for the message queue to initialise.
- * If it didnt -> controller is dead
- *
- * Send a get status using the message queue
- * Poll for a reply block 88 bytes long
- *
- * Send an initialise outbound queue
- * Poll for a reply
- *
- * Post our blank messages to the queue FIFO
- *
- * Send GetHRT, Parse it
+ * Initialize I2O subsystem.
*/
-
-int i2o_activate_controller(struct i2o_controller *c)
+static void __init i2o_sys_init()
{
- long time;
- u32 m;
- u8 *workspace;
- u32 *msg;
- int i;
+ struct i2o_controller *iop;
int ret;
+ u32 m;
- printk(KERN_INFO "Configuring I2O controller at 0x%08X.\n",
- (u32)c->mem_phys);
-
- if((ret=i2o_status_get(c)))
- return ret;
+ printk(KERN_INFO "Activating I2O controllers\n");
+ printk(KERN_INFO "This may take a few minutes if there are many devices\n");
- if(c->status == ADAPTER_STATE_FAULTED) /* not likely to be seen */
+ /* Get the status for each IOP */
+ for(iop = i2o_controller_chain; iop; iop = iop->next)
{
- printk(KERN_CRIT "i2o: iop%d has hardware fault\n",
- c->unit);
- return -1;
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "Getting initial status for iop%d\n", iop->unit);
+#endif
+ i2o_status_get(iop);
+
+ if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED)
+ {
+ printk(KERN_CRIT "i2o: iop%d has hardware fault\n",
+ iop->unit);
+ i2o_delete_controller(iop);
+ }
+
+ if(iop->status_block->iop_state == ADAPTER_STATE_HOLD ||
+ iop->status_block->iop_state == ADAPTER_STATE_READY ||
+ iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL ||
+ iop->status_block->iop_state == ADAPTER_STATE_FAILED)
+ {
+ int msg[256];
+
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "iop%d already running...trying to reboot",
+ iop->unit);
+#endif
+ i2o_init_outbound_q(iop);
+ I2O_REPLY_WRITE32(iop,virt_to_phys(msg));
+ i2o_quiesce_controller(iop);
+ i2o_reset_controller(iop);
+ i2o_status_get(iop);
+ }
}
/*
- * If the board is running, reset it - we have no idea
- * what kind of a mess the previous owner left it in.
+ * Now init the outbound queue for each one.
*/
- if(c->status == ADAPTER_STATE_HOLD ||
- c->status == ADAPTER_STATE_READY ||
- c->status == ADAPTER_STATE_OPERATIONAL ||
- c->status == ADAPTER_STATE_FAILED)
+ for(iop = i2o_controller_chain; iop; iop = iop->next)
{
- if((ret=i2o_reset_controller(c)))
- return ret;
+ int i;
- if((ret=i2o_status_get(c)))
- return ret;
- }
+ if((ret=i2o_init_outbound_q(iop)))
+ {
+ printk(KERN_ERR
+ "IOP%d initialization failed: Could not initialize outbound q\n",
+ iop->unit);
+ i2o_delete_controller(iop);
+ }
+ iop->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
- workspace = (void *)kmalloc(88, GFP_KERNEL);
- if(workspace==NULL)
- {
- printk(KERN_ERR "IOP initialisation failed - no free memory.\n");
- return -ENOMEM;
+ if(iop->page_frame==NULL)
+ {
+ printk(KERN_ERR "IOP init failed: no memory for message page.\n");
+ i2o_delete_controller(iop);
+ continue;
+ }
+
+ m=virt_to_phys(iop->page_frame);
+
+ for(i=0; i< NMBR_MSG_FRAMES; i++)
+ {
+ I2O_REPLY_WRITE32(iop,m);
+ mb();
+ m+=MSG_FRAME_SIZE;
+ mb();
+ }
}
- memset(workspace, 0, 88);
-
- m=i2o_wait_message(c, "OutboundInit");
- if(m==0xFFFFFFFF)
- {
- kfree(workspace);
- return -ETIMEDOUT;
+ /*
+ * OK..parse the HRT
+ */
+ for(iop = i2o_controller_chain; iop; iop = iop->next)
+ {
+ if(i2o_hrt_get(iop))
+ {
+ i2o_delete_controller(iop);
+ break;
+ }
+ if(i2o_parse_hrt(iop))
+ i2o_delete_controller(iop);
}
- msg=(u32 *)(c->mem_offset+m);
-
- msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6;
- msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID;
- msg[2]= core_context;
- msg[3]= 0x0106; /* Transaction context */
- msg[4]= 4096; /* Host page frame size */
- msg[5]= MSG_FRAME_SIZE<<16|0x80; /* Outbound msg frame size and Initcode */
- msg[6]= 0xD0000004; /* Simple SG LE, EOB */
- msg[7]= virt_to_phys(workspace);
- *((u32 *)workspace)=0;
+ /*
+ * Build and send the system table
+ */
+ i2o_build_sys_table();
+ for(iop = i2o_controller_chain; iop; iop = iop->next)
+#ifdef DRIVERDEBUG
+ {
+ printk(KERN_INFO "Sending system table to iop%d\n", iop->unit);
+#endif
+ i2o_systab_send(iop);
+#ifdef DRIVERDEBUG
+ }
+#endif
/*
- * Post it
+ * Enable
*/
+ for(iop = i2o_controller_chain; iop; iop = iop->next)
+ {
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "Enableing iop%d\n", iop->unit);
+#endif
+ if(i2o_enable_controller(iop))
+ {
+ printk(KERN_ERR "Could not enable iop%d\n", iop->unit);
+ i2o_delete_controller(iop);
+ }
+ }
- i2o_post_message(c,m);
-
- barrier();
-
- time=jiffies;
-
- while(workspace[0]!=I2O_CMD_OUTBOUND_INIT_COMPLETE)
+ /*
+ * OK..one last thing and we're ready to go!
+ */
+ for(iop = i2o_controller_chain; iop; iop = iop->next)
{
- if((jiffies-time)>=5*HZ)
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "Getting LCT for iop%d\n", iop->unit);
+#endif
+ if(i2o_lct_get(iop))
{
- printk(KERN_ERR "IOP outbound initialise failed.\n");
- kfree(workspace);
- return -ETIMEDOUT;
+ printk(KERN_ERR "Could not get LCT from iop%d\n", iop->unit);
+ i2o_delete_controller(iop);
}
- schedule();
- barrier();
+ else
+ i2o_parse_lct(iop);
}
+}
+
+/*
+ * Shutdown I2O system
+ *
+ * 1. Quiesce all controllers
+ * 2. Delete all controllers
+ *
+ */
+static void i2o_sys_shutdown(void)
+{
+ struct i2o_controller *iop = NULL;
- kfree(workspace);
+ i2o_quiesce_system();
+ for(iop = i2o_controller_chain; iop; iop = iop->next)
+ i2o_delete_controller(iop);
+}
+
+/*
+ * Bring an I2O controller into HOLD state. See the 1.5
+ * spec. Basically we go
+ *
+ * Wait for the message queue to initialise.
+ * If it didnt -> controller is dead
+ *
+ * Send a get status using the message queue
+ * Poll for a reply block 88 bytes long
+ *
+ * Send an initialise outbound queue
+ * Poll for a reply
+ *
+ * Post our blank messages to the queue FIFO
+ *
+ * Send GetHRT, Parse it
+ */
+int i2o_activate_controller(struct i2o_controller *c)
+{
+ return 0;
+#ifdef I2O_HOTPLUG_SUPPORT
+ u32 m;
+ int i;
+ int ret;
+
+ printk(KERN_INFO "Configuring I2O controller at 0x%08X.\n",
+ (u32)c->mem_phys);
+
+ if((ret=i2o_status_get(c)))
+ return ret;
+
+ /* not likely to be seen */
+ if(c->status_block->iop_state == ADAPTER_STATE_FAULTED)
+ {
+ printk(KERN_CRIT "i2o: iop%d has hardware fault\n",
+ c->unit);
+ return -1;
+ }
+
+ /*
+ * If the board is running, reset it - we have no idea
+ * what kind of a mess the previous owner left it in.
+ * We need to feed the IOP a single outbound message
+ * so that it can reply back to the ExecSysQuiesce.
+ */
+ if(c->status_block->iop_state == ADAPTER_STATE_HOLD ||
+ c->status_block->iop_state == ADAPTER_STATE_READY ||
+ c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL ||
+ c->status_block->iop_state == ADAPTER_STATE_FAILED)
+ {
+ int msg[256];
+ printk(KERN_INFO "i2o/iop%d already running, reseting\n", c->unit);
+
+ if(i2o_init_outbound_q(c));
+ I2O_REPLY_WRITE32(c,virt_to_phys(msg));
+
+ if((ret=i2o_reset_controller(c)))
+ return ret;
+
+ if((ret=i2o_status_get(c)))
+ return ret;
+ }
+
+ if((ret=i2o_init_outbound_q(c)))
+ {
+ printk(KERN_ERR
+ "IOP%d initialization failed: Could not initialize outbound queue\n",
+ c->unit);
+ return ret;
+ }
/* TODO: v2.0: Set Executive class group 000Bh - OS Operating Info */
@@ -1248,46 +1593,101 @@
I2O_REPLY_WRITE32(c,m);
mb();
m+=MSG_FRAME_SIZE;
+ mb();
}
- /*
- * The outbound queue is initialised and loaded,
- *
- * Now we need the Hardware Resource Table. We must ask for
- * this next we can't issue random messages yet.
- */
- ret=i2o_hrt_get(c);
- if(ret)
- return ret;
+ /*
+ * The outbound queue is initialised and loaded,
+ *
+ * Now we need the Hardware Resource Table. We must ask for
+ * this next we can't issue random messages yet.
+ */
+ ret=i2o_hrt_get(c); if(ret) return ret;
ret=i2o_parse_hrt(c);
if(ret)
return ret;
return i2o_online_controller(c);
-// i2o_report_controller_unit(c, ADAPTER_TID);
+#endif
}
-
-int i2o_lct_get(struct i2o_controller *c)
+/*
+ * Clear and (re)initialize IOP's outbound queue
+ */
+int i2o_init_outbound_q(struct i2o_controller *c)
{
+ u8 workspace[88];
u32 m;
u32 *msg;
+ u32 time;
- m=i2o_wait_message(c, "LCTNotify");
+ memset(workspace, 0, 88);
+ printk(KERN_INFO "i2o/iop%d: Initializing Outbound Queue\n", c->unit);
+ m=i2o_wait_message(c, "OutboundInit");
if(m==0xFFFFFFFF)
+ {
+ kfree(workspace);
return -ETIMEDOUT;
+ }
msg=(u32 *)(c->mem_offset+m);
+ msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6;
+ msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID;
+ msg[2]= core_context;
+ msg[3]= 0x0106; /* Transaction context */
+ msg[4]= 4096; /* Host page frame size */
+ msg[5]= MSG_FRAME_SIZE<<16|0x80; /* Outbound msg frame size and Initcode */
+ msg[6]= 0xD0000004; /* Simple SG LE, EOB */
+ msg[7]= virt_to_phys(workspace);
+ *((u32 *)workspace)=0;
+
+ /*
+ * Post it
+ */
+ i2o_post_message(c,m);
+
+ barrier();
+
+ time=jiffies;
+
+ while(workspace[0]!=I2O_CMD_OUTBOUND_INIT_COMPLETE)
+ {
+ if((jiffies-time)>=5*HZ)
+ {
+ printk(KERN_ERR "i2o/iop%d: IOP outbound initialise failed.\n",
+ c->unit);
+ kfree(workspace);
+ return -ETIMEDOUT;
+ }
+ schedule();
+ barrier();
+ }
+
+ return 0;
+}
+
+/*
+ * Get the IOP's Logical Configuration Table
+ */
+int i2o_lct_get(struct i2o_controller *c)
+{
+ u32 msg[8];
+
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "Getting lct for iop%d\n", c->unit);
+#endif
+
+ if(c->lct)
+ kfree(c->lct);
+
c->lct = kmalloc(8192, GFP_KERNEL);
if(c->lct==NULL)
{
- msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
- msg[1]= HOST_TID<<12|ADAPTER_TID; /* NOP */
- i2o_post_message(c,m);
- printk(KERN_ERR "No free memory for i2o controller buffer.\n");
+ printk(KERN_ERR "i2o/iop%d: No free memory for i2o controller buffer.\n",
+ c->unit);
return -ENOMEM;
}
@@ -1302,25 +1702,8 @@
msg[6] = 0xD0000000|8192;
msg[7] = virt_to_bus(c->lct);
- i2o_post_message(c,m);
-
- barrier();
-
- /* Now wait for a reply */
- m=i2o_wait_reply(c, "LCTNotify", 5);
-
- if(m==0xFFFFFFFF)
- return -ETIMEDOUT;
-
- msg=(u32 *)bus_to_virt(m);
-
- /* TODO: Check TableSize for big LCTs and send new ExecLctNotify
- * with bigger workspace */
-
- if(msg[4]>>24)
- i2o_report_status(KERN_ERR, "i2o_core", msg);
-
- return 0;
+
+ return(i2o_post_wait(c, msg, sizeof(msg), 120));
}
@@ -1330,13 +1713,14 @@
int i2o_online_controller(struct i2o_controller *c)
{
- u32 m;
- u32 *msg;
- u32 systab[32];
+ return 0;
+#ifdef I2O_HOTPLUG_SUPPORT
+ u32 msg[10];
u32 privmem[2];
u32 privio[2];
+ u32 systab[32];
int ret;
-
+
systab[0]=1;
systab[1]=0;
systab[2]=0;
@@ -1350,103 +1734,45 @@
systab[10]=virt_to_phys(c->post_port);
systab[11]=0;
+ i2o_build_sys_table();
+
privmem[0]=c->priv_mem; /* Private memory space base address */
privmem[1]=c->priv_mem_size;
privio[0]=c->priv_io; /* Private I/O address */
privio[1]=c->priv_io_size;
-
- m=i2o_wait_message(c, "SysTabSet");
- if(m==0xFFFFFFFF)
- return -ETIMEDOUT;
-
- /* Now we build the systab */
- msg=(u32 *)(c->mem_offset+m);
-
+
msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_6;
msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
msg[2] = 0; /* Context not needed */
msg[3] = 0;
- msg[4] = (1<<16)|(2<<12); /* Host 1 I2O 2 */
- msg[5] = 1; /* Segment 1 */
+ msg[4] = (0<<16)|(2<<12); /* Host 1 I2O 2 */
+ msg[5] = 0; /* Segment 1 */
/*
* Scatter Gather List
*/
-
- msg[6] = 0x54000000|48; /* One table for now */
- msg[7] = virt_to_phys(systab);
+ msg[6] = 0x54000000|sys_tbl_len; /* One table for now */
+ msg[7] = virt_to_phys(sys_tbl);
msg[8] = 0xD4000000|48; /* One table for now */
msg[9] = virt_to_phys(privmem);
-/* msg[10] = virt_to_phys(privio); */
-
- i2o_post_message(c,m);
+/* msg[10] = virt_to_phys(privio); */
- barrier();
-
- /*
- * Now wait for a reply
- */
-
-
- m=i2o_wait_reply(c, "SysTabSet", 5);
-
- if(m==0xFFFFFFFF)
- return -ETIMEDOUT;
-
- msg=(u32 *)bus_to_virt(m);
-
- if(msg[4]>>24)
- {
- i2o_report_status(KERN_ERR, "i2o_core", msg);
- }
- I2O_REPLY_WRITE32(c,m);
+ return(i2o_post_wait(c, msg, sizeof(msg), 120));
/*
* Finally we go online
*/
-
- m=i2o_wait_message(c, "SysEnable");
-
- if(m==0xFFFFFFFF)
- return -ETIMEDOUT;
-
- msg=(u32 *)(c->mem_offset+m);
-
- msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
- msg[1] = I2O_CMD_SYS_ENABLE<<24 | HOST_TID<<12 | ADAPTER_TID;
- msg[2] = 0; /* Context not needed */
- msg[3] = 0;
-
- i2o_post_message(c,m);
-
- barrier();
-
- /*
- * Now wait for a reply
- */
-
-
- m=i2o_wait_reply(c, "SysEnable", 240);
-
- if(m==0xFFFFFFFF)
- return -ETIMEDOUT;
-
- msg=(u32 *)bus_to_virt(m);
-
- if(msg[4]>>24)
- {
- i2o_report_status(KERN_ERR, "i2o_core", msg);
- }
- I2O_REPLY_WRITE32(c,m);
+ ret = i2o_enable_controller(c);
+ if(ret)
+ return ret;
/*
* Grab the LCT, see what is attached
*/
-
ret=i2o_lct_get(c);
if(ret)
{
- /* Maybe we should do also sthg else */
+ /* Maybe we should do also do something else */
return ret;
}
@@ -1454,11 +1780,73 @@
if(ret)
return ret;
- I2O_REPLY_WRITE32(c,m);
-
+ return 0;
+#endif
+}
+
+static int i2o_build_sys_table(void)
+{
+ struct i2o_controller *iop = NULL;
+ int count = 0;
+#ifdef DRIVERDEBUG
+ u32 *table;
+#endif
+
+ sys_tbl_len = sizeof(struct i2o_sys_tbl) + // Header + IOPs
+ (i2o_num_controllers) *
+ sizeof(struct i2o_sys_tbl_entry);
+
+#ifdef DRIVERDEBUG
+ printk(KERN_INFO "Building system table len = %d\n", sys_tbl_len);
+#endif
+ if(sys_tbl)
+ kfree(sys_tbl);
+
+ sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL);
+ if(!sys_tbl)
+ return -ENOMEM;
+ memset((void*)sys_tbl, 0, sys_tbl_len);
+
+ sys_tbl->num_entries = i2o_num_controllers;
+ sys_tbl->version = I2OVERSION; /* TODO: Version 2.0 */
+ sys_tbl->change_ind = sys_tbl_ind++;
+
+ for(iop = i2o_controller_chain; iop; iop = iop->next)
+ {
+ // Get updated IOP state so we have the latest information
+ i2o_status_get(iop);
+
+ sys_tbl->iops[count].org_id = iop->status_block->org_id;
+ sys_tbl->iops[count].iop_id = iop->unit + 2;
+ sys_tbl->iops[count].seg_num = 0;
+ sys_tbl->iops[count].i2o_version =
+ iop->status_block->i2o_version;
+ sys_tbl->iops[count].iop_state =
+ iop->status_block->iop_state;
+ sys_tbl->iops[count].msg_type =
+ iop->status_block->msg_type;
+ sys_tbl->iops[count].frame_size =
+ iop->status_block->inbound_frame_size;
+ sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ??
+ sys_tbl->iops[count].iop_capabilities =
+ iop->status_block->iop_capabilities;
+ sys_tbl->iops[count].inbound_low =
+ (u32)virt_to_phys(iop->post_port);
+ sys_tbl->iops[count].inbound_high = 0; // TODO: 64-bit support
+
+ count++;
+ }
+
+#ifdef DRIVERDEBUG
+ table = (u32*)sys_tbl;
+ for(count = 0; count < (sys_tbl_len >>2); count++)
+ printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]);
+#endif
+
return 0;
}
+
/*
* Run time support routines
*/
@@ -1469,11 +1857,11 @@
* this is simply not worth optimising
*/
-int i2o_post_this(struct i2o_controller *c, int tid, u32 *data, int len)
+int i2o_post_this(struct i2o_controller *c, u32 *data, int len)
{
u32 m;
u32 *msg;
- unsigned long t=jiffies;
+ unsigned long t=jiffies;
do
{
@@ -1485,8 +1873,9 @@
if(m==0xFFFFFFFF)
{
- printk(KERN_ERR "i2o: controller not responding.\n");
- return -1;
+ printk(KERN_ERR "i2o/iop%d: Timeout waiting for message frame!\n",
+ c->unit);
+ return -ETIMEDOUT;
}
msg = bus_to_virt(c->mem_offset + m);
memcpy(msg, data, len);
@@ -1495,32 +1884,114 @@
}
/*
- * Post a message and wait for a response flag to be set. This API will
- * change to use wait_queue's one day
+ * Post a message and wait for a response flag to be set.
*/
-
-int i2o_post_wait(struct i2o_controller *c, int tid, u32 *data, int len, int *flag, int timeout)
+int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout)
{
- unsigned long t=jiffies;
+ DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post);
+ int status = 0;
+ int flags = 0;
+ int ret = 0;
+ struct i2o_post_wait_data *p1, *p2;
+ struct i2o_post_wait_data *wait_data =
+ kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL);
+
+ if(!wait_data)
+ return -ETIMEDOUT;
+
+ p1 = p2 = NULL;
- *flag = 0;
-
- if(i2o_post_this(c, tid, data, len))
- return I2O_POST_WAIT_TIMEOUT;
-
- while(!*flag && (jiffies-t)<timeout*HZ)
+ /*
+ * The spin locking is needed to keep anyone from playing
+ * with the queue pointers and id while we do the same
+ */
+ spin_lock_irqsave(&post_wait_lock, flags);
+ wait_data->next = post_wait_queue;
+ post_wait_queue = wait_data;
+ wait_data->id = ++post_wait_id;
+ spin_unlock_irqrestore(&post_wait_lock, flags);
+
+ wait_data->wq = &wq_i2o_post;
+ wait_data->status = -ETIMEDOUT;
+
+ msg[3] = (u32)wait_data->id;
+ msg[2] = 0x80000000|(u32)core_context;
+
+ if((ret=i2o_post_this(c, msg, len)))
+ return ret;
+ /*
+ * Go to sleep and wait for timeout or wake_up call
+ */
+ interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout);
+
+ /*
+ * Grab transaction status
+ */
+ status = wait_data->status;
+
+ /*
+ * Remove the entry from the queue.
+ * Since i2o_post_wait() may have been called again by
+ * a different thread while we were waiting for this
+ * instance to complete, we're not guaranteed that
+ * this entry is at the head of the queue anymore, so
+ * we need to search for it, find it, and delete it.
+ */
+ spin_lock_irqsave(&post_wait_lock, flags);
+ for(p1 = post_wait_queue; p1; )
{
- schedule();
- mb();
+ if(p1 == wait_data)
+ {
+ if(p2)
+ p2->next = p1->next;
+ else
+ post_wait_queue = p1->next;
+
+ break;
+ }
+ p1 = p1->next;
}
+ spin_unlock_irqrestore(&post_wait_lock, flags);
+
+ kfree(wait_data);
- if (*flag < 0)
- return *flag; /* DetailedStatus */
+ return status;
+}
- if (*flag == 0)
- return I2O_POST_WAIT_TIMEOUT;
-
- return I2O_POST_WAIT_OK;
+/*
+ * i2o_post_wait is completed and we want to wake up the
+ * sleeping proccess. Called by core's reply handler.
+ */
+static void i2o_post_wait_complete(u32 context, int status)
+{
+ struct i2o_post_wait_data *p1 = NULL;
+
+ /*
+ * We need to search through the post_wait
+ * queue to see if the given message is still
+ * outstanding. If not, it means that the IOP
+ * took longer to respond to the message than we
+ * had allowed and timer has already expired.
+ * Not much we can do about that except log
+ * it for debug purposes, increase timeout, and recompile
+ *
+ * Lock needed to keep anyone from moving queue pointers
+ * around while we're looking through them.
+ */
+ spin_lock(&post_wait_lock);
+ for(p1 = post_wait_queue; p1; p1 = p1->next)
+ {
+ if(p1->id == context)
+ {
+ p1->status = status;
+ wake_up_interruptible(p1->wq);
+ spin_unlock(&post_wait_lock);
+ return;
+ }
+ }
+ spin_unlock(&post_wait_lock);
+
+ printk(KERN_DEBUG "i2o_post_wait reply after timeout!");
}
/*
@@ -1543,7 +2014,7 @@
msg[3] = (u32)flag;
msg[4] = type;
- return i2o_post_wait(c, tid, msg, 20, flag,2);
+ return i2o_post_wait(c, msg, 20, 2);
}
/* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
@@ -1554,60 +2025,56 @@
* Note that the minimum sized resblk is 8 bytes and contains
* ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
*/
-int i2o_issue_params(int cmd,
- struct i2o_controller *iop, int tid, int context,
- void *opblk, int oplen, void *resblk, int reslen,
- int *flag)
+int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid,
+ void *opblk, int oplen, void *resblk, int reslen)
{
- u32 msg[9];
+u32 msg[9];
u8 *res = (u8 *)resblk;
int res_count;
int blk_size;
int bytes;
int wait_status;
- msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
- msg[1] = cmd << 24 | HOST_TID << 12 | tid;
- msg[2] = context | 0x80000000;
- msg[3] = (u32)flag;
- msg[4] = 0;
- msg[5] = 0x54000000 | oplen; /* OperationBlock */
- msg[6] = virt_to_bus(opblk);
- msg[7] = 0xD0000000 | reslen; /* ResultBlock */
- msg[8] = virt_to_bus(resblk);
-
- wait_status = i2o_post_wait(iop, tid, msg, sizeof(msg), flag, 10);
- if (wait_status < 0)
- return wait_status; /* -DetailedStatus */
-
- if (res[1]&0x00FF0000) /* BlockStatus != SUCCESS */
- {
- printk(KERN_WARNING "%s - Error:\n ErrorInfoSize = 0x%02x, "
- "BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
- (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET"
- : "PARAMS_GET",
- res[1]>>24, (res[1]>>16)&0xFF, res[1]&0xFFFF);
- return -((res[1] >> 16) & 0xFF); /* -BlockStatus */
- }
-
- res_count = res[0] & 0xFFFF; /* # of resultblocks */
- bytes = 4;
- res += 4;
- while (res_count--)
+ msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
+ msg[1] = cmd << 24 | HOST_TID << 12 | tid;
+ msg[4] = 0;
+ msg[5] = 0x54000000 | oplen; /* OperationBlock */
+ msg[6] = virt_to_bus(opblk);
+ msg[7] = 0xD0000000 | reslen; /* ResultBlock */
+ msg[8] = virt_to_bus(resblk);
+
+ wait_status = i2o_post_wait(iop, msg, sizeof(msg), 10);
+ if (wait_status)
+ return wait_status; /* -DetailedStatus */
+
+ if (res[1]&0x00FF0000) /* BlockStatus != SUCCESS */
+ {
+ printk(KERN_WARNING "%s - Error:\n ErrorInfoSize = 0x%02x, "
+ "BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
+ (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET"
+ : "PARAMS_GET",
+ res[1]>>24, (res[1]>>16)&0xFF, res[1]&0xFFFF);
+ return -((res[1] >> 16) & 0xFF); /* -BlockStatus */
+ }
+
+ res_count = res[0] & 0xFFFF; /* # of resultblocks */
+ bytes = 4;
+ res += 4;
+ while (res_count--)
{
blk_size = (res[0] & 0xFFFF) << 2;
bytes += blk_size;
res += blk_size;
}
-
- return bytes; /* total sizeof Result List in bytes */
+
+ return bytes; /* total sizeof Result List in bytes */
}
/*
* Query one scalar group value or a whole scalar group.
*/
-int i2o_query_scalar(struct i2o_controller *iop, int tid, int context,
- int group, int field, void *buf, int buflen, int *flag)
+int i2o_query_scalar(struct i2o_controller *iop, int tid,
+ int group, int field, void *buf, int buflen)
{
u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
u8 resblk[8+buflen]; /* 8 bytes for header */
@@ -1616,8 +2083,8 @@
if (field == -1) /* whole group */
opblk[4] = -1;
- size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, context,
- opblk, sizeof(opblk), resblk, sizeof(resblk), flag);
+ size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid,
+ opblk, sizeof(opblk), resblk, sizeof(resblk));
if (size < 0)
return size;
@@ -1629,38 +2096,38 @@
/*
* Set a scalar group value or a whole group.
*/
-int i2o_set_scalar(struct i2o_controller *iop, int tid, int context,
- int group, int field, void *buf, int buflen, int *flag)
+int i2o_set_scalar(struct i2o_controller *iop, int tid,
+ int group, int field, void *buf, int buflen)
{
u16 *opblk;
u8 resblk[8+buflen]; /* 8 bytes for header */
int size;
- opblk = kmalloc(buflen+64, GFP_KERNEL);
- if (opblk == NULL)
- {
- printk(KERN_ERR "i2o: no memory for operation buffer.\n");
- return -ENOMEM;
- }
+ opblk = kmalloc(buflen+64, GFP_KERNEL);
+ if (opblk == NULL)
+ {
+ printk(KERN_ERR "i2o: no memory for operation buffer.\n");
+ return -ENOMEM;
+ }
- opblk[0] = 1; /* operation count */
- opblk[1] = 0; /* pad */
- opblk[2] = I2O_PARAMS_FIELD_SET;
- opblk[3] = group;
-
- if(field == -1) { /* whole group */
- opblk[4] = -1;
- memcpy(opblk+5, buf, buflen);
- }
- else /* single field */
- {
- opblk[4] = 1;
- opblk[5] = field;
- memcpy(opblk+6, buf, buflen);
- }
+ opblk[0] = 1; /* operation count */
+ opblk[1] = 0; /* pad */
+ opblk[2] = I2O_PARAMS_FIELD_SET;
+ opblk[3] = group;
+
+ if(field == -1) { /* whole group */
+ opblk[4] = -1;
+ memcpy(opblk+5, buf, buflen);
+ }
+ else /* single field */
+ {
+ opblk[4] = 1;
+ opblk[5] = field;
+ memcpy(opblk+6, buf, buflen);
+ }
- size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context,
- opblk, 12+buflen, resblk, sizeof(resblk), flag);
+ size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid,
+ opblk, 12+buflen, resblk, sizeof(resblk));
kfree(opblk);
return size;
@@ -1687,10 +2154,9 @@
*
* You could also use directly function i2o_issue_params().
*/
-int i2o_query_table(int oper,
- struct i2o_controller *iop, int tid, int context, int group,
+int i2o_query_table(int oper, struct i2o_controller *iop, int tid, int group,
int fieldcount, void *ibuf, int ibuflen,
- void *resblk, int reslen, int *flag)
+ void *resblk, int reslen)
{
u16 *opblk;
int size;
@@ -1709,8 +2175,8 @@
opblk[4] = fieldcount;
memcpy(opblk+5, ibuf, ibuflen); /* other params */
- size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET,iop, tid, context,
- opblk, 10+ibuflen, resblk, reslen, flag);
+ size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET,iop, tid,
+ opblk, 10+ibuflen, resblk, reslen);
kfree(opblk);
return size;
@@ -1720,14 +2186,13 @@
* Clear table group, i.e. delete all rows.
*/
-int i2o_clear_table(struct i2o_controller *iop, int tid, int context,
- int group, int *flag)
+int i2o_clear_table(struct i2o_controller *iop, int tid, int group)
{
u16 opblk[] = { 1, 0, I2O_PARAMS_TABLE_CLEAR, group };
u8 resblk[32]; /* min 8 bytes for result header */
- return i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context,
- opblk, sizeof(opblk), resblk, sizeof(resblk), flag);
+ return i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid,
+ opblk, sizeof(opblk), resblk, sizeof(resblk));
}
/*
@@ -1739,9 +2204,8 @@
* buf contains fieldindexes, rowcount, keyvalues
*/
-int i2o_row_add_table(struct i2o_controller *iop, int tid, int context,
- int group, int fieldcount, void *buf, int buflen,
- int *flag)
+int i2o_row_add_table(struct i2o_controller *iop, int tid,
+ int group, int fieldcount, void *buf, int buflen)
{
u16 *opblk;
u8 resblk[32]; /* min 8 bytes for header */
@@ -1761,8 +2225,8 @@
opblk[4] = fieldcount;
memcpy(opblk+5, buf, buflen);
- size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context,
- opblk, 10+buflen, resblk, sizeof(resblk), flag);
+ size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid,
+ opblk, 10+buflen, resblk, sizeof(resblk));
kfree(opblk);
return size;
@@ -1772,9 +2236,8 @@
* Delete rows from a table group.
*/
-int i2o_row_delete_table(struct i2o_controller *iop, int tid, int context,
- int group, int keycount, void *keys, int keyslen,
- int *flag)
+int i2o_row_delete_table(struct i2o_controller *iop, int tid,
+ int group, int keycount, void *keys, int keyslen)
{
u16 *opblk;
u8 resblk[32]; /* min 8 bytes for header */
@@ -1794,8 +2257,8 @@
opblk[4] = keycount;
memcpy(opblk+5, keys, keyslen);
- size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context,
- opblk, 10+keyslen, resblk, sizeof(resblk), flag);
+ size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid,
+ opblk, 10+keyslen, resblk, sizeof(resblk));
kfree(opblk);
return size;
@@ -2134,9 +2597,10 @@
#ifdef DRIVERDEBUG
int i;
- printk(KERN_INFO "Dumping I2O message @ %p\n", msg);
+ printk(KERN_INFO "Dumping I2O message size %d @ %p\n",
+ msg[0]>>16&0xffff, msg);
for(i = 0; i < ((msg[0]>>16)&0xffff); i++)
- printk(KERN_INFO "\tmsg[%d] = %#10x\n", i, msg[i]);
+ printk(KERN_INFO " msg[%d] = %0#10x\n", i, msg[i]);
#endif
}
@@ -2181,27 +2645,35 @@
int init_module(void)
{
+ printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n");
if (i2o_install_handler(&i2o_core_handler) < 0)
{
- printk(KERN_ERR "i2o_core: Unable to install core handler.\n");
+ printk(KERN_ERR
+ "i2o_core: Unable to install core handler.\nI2O stack not loaded!");
return 0;
}
core_context = i2o_core_handler.context;
/*
- * Attach core to I2O PCI subsystem
+ * Attach core to I2O PCI transport (and others as they are developed)
*/
#ifdef CONFIG_I2O_PCI_MODULE
if(i2o_pci_core_attach(&i2o_core_functions) < 0)
printk(KERN_INFO "No PCI I2O controllers found\n");
#endif
+ if(i2o_num_controllers)
+ i2o_sys_init();
+
return 0;
}
void cleanup_module(void)
{
+ if(i2o_num_controllers)
+ i2o_sys_shutdown();
+
#ifdef CONFIG_I2O_PCI_MODULE
i2o_pci_core_detach();
#endif
@@ -2220,16 +2692,23 @@
int __init i2o_init(void)
{
- if (i2o_install_handler(&i2o_core_handler) < 0)
- {
- printk(KERN_ERR "i2o_core: Unable to install core handler.\n");
- return 0;
- }
+ printk(KERN_INFO "Loading I2O Core - (c) Copyright 1999 Red Hat Software\n");
+ if (i2o_install_handler(&i2o_core_handler) < 0)
+ {
+ printk(KERN_ERR
+ "i2o_core: Unable to install core handler.\nI2O stack not loaded!");
+ return 0;
+ }
+
+ core_context = i2o_core_handler.context;
- core_context = i2o_core_handler.context;
#ifdef CONFIG_I2O_PCI
i2o_pci_init();
#endif
+
+ if(i2o_num_controllers)
+ i2o_init();
+
i2o_config_init();
#ifdef CONFIG_I2O_BLOCK
i2o_block_init();
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)