patch-2.2.16 linux/drivers/i2o/i2o_core.c

Next file: linux/drivers/i2o/i2o_pci.c
Previous file: linux/drivers/i2o/i2o_config.c
Back to the patch index
Back to the overall index

diff -urN v2.2.15/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c
@@ -18,6 +18,7 @@
  *		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI> 
  *		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> 
  *		Deepak Saxena <deepak@plexity.net> 
+ *		Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com>
  */
 
 #include <linux/config.h>
@@ -26,17 +27,25 @@
 #include <linux/pci.h>
 
 #include <linux/i2o.h>
+#include <linux/i2o-dev.h>
 
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <asm/spinlock.h>
+#include <linux/smp_lock.h>
 
 #include <linux/bitops.h>
 #include <linux/wait.h>
+#include <linux/delay.h>
 #include <linux/timer.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <asm/semaphore.h>
 
 #include <asm/io.h>
+#include <linux/reboot.h>
 
 // #define DRIVERDEBUG
 // #define DEBUG_IRQ
@@ -47,10 +56,11 @@
  *	Size of the I2O module table
  */
  
-static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES];
-static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS];
-struct i2o_controller *i2o_controller_chain;
+static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES]= {NULL};
+static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS] = {NULL};
+struct i2o_controller *i2o_controller_chain = NULL;
 int i2o_num_controllers = 0;
+/* Initiator Context for Core Message */
 static int core_context = 0;
 
 static int i2o_activate_controller(struct i2o_controller *iop);
@@ -58,18 +68,27 @@
 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 *);
 void i2o_dump_message(u32 *msg);
 
 static int i2o_issue_claim(struct i2o_controller *, int, int, int, u32);
 
 static int i2o_reset_controller(struct i2o_controller *);
 static int i2o_lct_get(struct i2o_controller *);
+static int i2o_lct_notify(struct i2o_controller *);
 static int i2o_hrt_get(struct i2o_controller *);
 
+/* Dynamic LCT update handler */
+static int i2o_dyn_lct(void *);
+
+/* I2O core event handler */
+static int i2o_core_evt(void *);
+static int evt_pid;
+static int evt_running;
+
 static void i2o_sys_init(void);
 static void i2o_sys_shutdown(void);
+static int i2o_clear_controller(struct i2o_controller *);
+static int i2o_reboot_event(struct notifier_block *, unsigned long, void *);
 
 static int i2o_build_sys_table(void);
 static int i2o_systab_send(struct i2o_controller *c);
@@ -86,6 +105,14 @@
 static int sys_tbl_ind = 0;
 static int sys_tbl_len = 0;
 
+/*
+ * This spin lock is used to keep a device from being
+ * added and deleted concurrently across CPUs or interrupts.
+ * This can occur when a user creates a device and immediatelly
+ * deletes it before the new_dev_notify() handler is called.
+ */
+static spinlock_t i2o_dev_lock = SPIN_LOCK_UNLOCKED;
+
 #ifdef MODULE
 /* 
  * Function table to send to bus specific layers
@@ -128,17 +155,58 @@
 static struct i2o_handler i2o_core_handler =
 {
 	(void *)i2o_core_reply,
-	"I2O core layer",
-	0
+	 NULL,
+	 NULL,
+	 NULL,
+	 "I2O core layer",
+	 0,
+	 I2O_CLASS_EXECUTIVE
 };
 
+/*
+ * Used when queing a reply to be handled later
+ */
+struct reply_info
+{
+	 struct i2o_controller *iop;
+	 u32 msg[MSG_FRAME_SIZE];
+};
+static struct reply_info evt_reply;
+static struct reply_info events[I2O_EVT_Q_LEN];
+static int evt_in = 0;
+static int evt_out = 0;
+static int evt_q_len = 0;
+
+#define MODINC(x,y) (x = x++ % y)
 
 /*
- *	I2O configuration spinlock. This isnt a big deal for contention
+ *	I2O configuration semaphore. This isnt a big deal for contention
  *	so we have one only
  */
  
-static spinlock_t i2o_configuration_lock = SPIN_LOCK_UNLOCKED;
+static struct semaphore i2o_configuration_lock = MUTEX;
+
+
+/*
+ * Event spinlock.  Used to keep event queue sane and from
+ * handling multiple events simultaneously.
+ */
+static spinlock_t i2o_evt_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Semaphore used to syncrhonize event handling thread with
+ * interrupt handler.
+ */
+DECLARE_MUTEX(evt_sem);
+DECLARE_WAIT_QUEUE_HEAD(evt_wait);
+
+static struct notifier_block i2o_reboot_notifier =
+{
+	 i2o_reboot_event,
+	 NULL,
+	 0
+};
+
 
 /*
  * I2O Core reply handler
@@ -157,19 +225,36 @@
 #endif
 	
 	if (msg[0] & (1<<13)) // Fail bit is set
-        {
-                printk(KERN_ERR "%s: Failed to process the msg:\n",c->name);
-                printk(KERN_ERR "  Cmd = 0x%02X, InitiatorTid = %d, TargetTid =%d\n",
-		       (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] &
-		       0xFFF);
-                printk(KERN_ERR "  FailureCode = 0x%02X\n  Severity = 0x%02X\n"
-		       "LowestVersion = 0x%02X\n  HighestVersion = 0x%02X\n",
-		       msg[4] >> 24, (msg[4] >> 16) & 0xFF,
-		       (msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
-                printk(KERN_ERR "  FailingHostUnit = 0x%04X\n  FailingIOP = 0x%03X\n",
-		       msg[5] >> 16, msg[5] & 0xFFF);
-                return;
-        }
+	 {
+		  u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]);
+
+		  printk(KERN_ERR "%s: Failed to process the msg:\n",c->name);
+		  printk(KERN_ERR "  Cmd = 0x%02X, InitiatorTid = %d, TargetTid =%d\n",
+			(msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] &
+			0xFFF);
+		  printk(KERN_ERR "  FailureCode = 0x%02X\n  Severity = 0x%02X\n"
+			"LowestVersion = 0x%02X\n  HighestVersion = 0x%02X\n",
+			msg[4] >> 24, (msg[4] >> 16) & 0xFF,
+			(msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
+		  printk(KERN_ERR "  FailingHostUnit = 0x%04X\n  FailingIOP = 0x%03X\n",
+			msg[5] >> 16, msg[5] & 0xFFF);
+
+		  /* If the failed request needs special treatment,
+		   * it should be done here. */
+
+		  /* Release the preserved msg by resubmitting it as a NOP */
+
+		  preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+		  preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0;
+		  preserved_msg[2] = 0;
+
+		  i2o_post_message(c, msg[7]);
+
+
+		  /* If reply to i2o_post_wait failed, return causes a timeout */
+
+		  return;
+	 }
 
 	if(msg[2]&0x80000000)	// Post wait message
 	{
@@ -182,7 +267,46 @@
 			status = I2O_POST_WAIT_OK;
 	
 		i2o_post_wait_complete(context, status);
+		return;
 	}
+
+		 if(m->function == I2O_CMD_UTIL_EVT_REGISTER)
+	 {
+		  memcpy(events[evt_in].msg, msg, MSG_FRAME_SIZE);
+		  events[evt_in].iop = c;
+
+		  spin_lock(&i2o_evt_lock);
+		  MODINC(evt_in, I2O_EVT_Q_LEN);
+		  if(evt_q_len == I2O_EVT_Q_LEN)
+			   MODINC(evt_out, I2O_EVT_Q_LEN);
+		  else
+			   evt_q_len++;
+		  spin_unlock(&i2o_evt_lock);
+
+		  up(&evt_sem);
+		  wake_up_interruptible(&evt_wait);
+		  return;
+	 }
+
+	 if(m->function == I2O_CMD_LCT_NOTIFY)
+	 {
+		  up(&c->lct_sem);
+		  return;
+	 }
+
+	 /*
+	  * If this happens, we want to dump the message to the syslog so
+	  * it can be sent back to the card manufacturer by the end user
+	  * to aid in debugging.
+	  *
+	  */
+	 printk(KERN_WARNING "%s: Unsolicited message reply sent to core!"
+			   "Message dumped to syslog\n",
+			   c->name);
+	 i2o_dump_message(msg);
+
+	 return;
+
 }
 
 /*
@@ -193,18 +317,18 @@
 int i2o_install_handler(struct i2o_handler *h)
 {
 	int i;
-	spin_lock(&i2o_configuration_lock);
+	down(&i2o_configuration_lock);
 	for(i=0;i<MAX_I2O_MODULES;i++)
 	{
 		if(i2o_handlers[i]==NULL)
 		{
 			h->context = i;
 			i2o_handlers[i]=h;
-			spin_unlock(&i2o_configuration_lock);
+			up(&i2o_configuration_lock);
 			return 0;
 		}
 	}
-	spin_unlock(&i2o_configuration_lock);
+	up(&i2o_configuration_lock);
 	return -ENOSPC;
 }
 
@@ -224,7 +348,7 @@
 {
 	int i;
 
-	spin_lock(&i2o_configuration_lock);
+	down(&i2o_configuration_lock);
 	d->controller=c;
 	d->owner=NULL;
 	d->next=c->devices;
@@ -234,7 +358,7 @@
 	for(i = 0; i < I2O_MAX_MANAGERS; i++)
 		d->managers[i] = NULL;
 
-	spin_unlock(&i2o_configuration_lock);
+	up(&i2o_configuration_lock);
 	return 0;
 }
 
@@ -243,15 +367,44 @@
 int __i2o_delete_device(struct i2o_device *d)
 {
 	struct i2o_device **p;
+	int i;
 
 	p=&(d->controller->devices);
 
 	/*
 	 *	Hey we have a driver!
+ 	 * Check to see if the driver wants us to notify it of
+	 * device deletion. If it doesn't we assume that it
+	 * is unsafe to delete a device with an owner and
+	 * fail.
 	 */
 	 
 	if(d->owner)
+	{
+	if(d->owner->dev_del_notify)
+	{
+		dprintk((KERN_INFO "Device has owner, notifying\n"));
+		d->owner->dev_del_notify(d->controller, d);
+		if(d->owner)
+		{
+			printk(KERN_WARNING "Driver \"%s\" did not release device!\n", d->owner->name);
+			return -EBUSY;
+		}
+	}
+	else
 		return -EBUSY;
+	 }
+
+	/*
+	 * Tell any other users who are talking to this device
+	 * that it's going away.  We assume that everything works.
+	 */
+	for(i=0; i < I2O_MAX_MANAGERS; i++)
+	{
+	if(d->managers[i] && d->managers[i]->dev_del_notify)
+		d->managers[i]->dev_del_notify(d->controller, d);
+	}
+
 
 	/*
 	 *	Seek, locate
@@ -278,11 +431,11 @@
 {
 	int ret;
 
-	spin_lock(&i2o_configuration_lock);
+	down(&i2o_configuration_lock);
 
 	ret = __i2o_delete_device(d);
 
-	spin_unlock(&i2o_configuration_lock);
+	up(&i2o_configuration_lock);
 
 	return ret;
 }
@@ -294,24 +447,31 @@
 int i2o_install_controller(struct i2o_controller *c)
 {
 	int i;
-	spin_lock(&i2o_configuration_lock);
+	down(&i2o_configuration_lock);
 	for(i=0;i<MAX_I2O_CONTROLLERS;i++)
 	{
 		if(i2o_controllers[i]==NULL)
 		{
-			i2o_controllers[i]=c;
-			c->next=i2o_controller_chain;
-			i2o_controller_chain=c;
-			c->unit = i;
-
-			sprintf(c->name, "i2o/iop%d", i);
-			i2o_num_controllers++;
-			spin_unlock(&i2o_configuration_lock);
-			return 0;
+			   i2o_controllers[i]=c;
+			   c->devices = NULL;
+			   c->next=i2o_controller_chain;
+			   i2o_controller_chain=c;
+			   c->unit = i;
+			   c->page_frame = NULL;
+			   c->hrt = NULL;
+			   c->lct = NULL;
+			   c->dlct = (i2o_lct*)kmalloc(8192, GFP_KERNEL);
+			   c->status_block = NULL;
+			   sprintf(c->name, "i2o/iop%d", i);
+			   i2o_num_controllers++;
+			   sema_init(&c->lct_sem, 0);
+			   up(&i2o_configuration_lock);
+			   return 0;
+
 		}
 	}
 	printk(KERN_ERR "No free i2o controller slots.\n");
-	spin_unlock(&i2o_configuration_lock);
+	up(&i2o_configuration_lock);
 	return -EBUSY;
 }
 
@@ -320,13 +480,20 @@
 	struct i2o_controller **p;
 	int users;
 	char name[16];
+	int stat;
+
+	 /*
+	  * Clear event registration as this can cause weird behavior
+	  */
+	 if(c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL)
+		  i2o_event_register(c, core_context, 0, 0, 0);
 
-	spin_lock(&i2o_configuration_lock);
+	down(&i2o_configuration_lock);
 	if((users=atomic_read(&c->users)))
 	{
 		printk(KERN_INFO "%s busy: %d users for controller.\n", c->name, users);
 		c->bus_disable(c); 
-		spin_unlock(&i2o_configuration_lock);
+		up(&i2o_configuration_lock);
 		return -EBUSY;
 	}
 	while(c->devices)
@@ -335,25 +502,46 @@
 		{
 			/* Shouldnt happen */
 			c->bus_disable(c); 
-			spin_unlock(&i2o_configuration_lock);
+			up(&i2o_configuration_lock);
 			return -EBUSY;
 		}
 	}
 
+
+	 /*
+	  * If this is shutdown time, the thread's already been killed
+	  */
+	 if(c->lct_running) {
+		  stat = kill_proc(c->lct_pid, SIGTERM, 1);
+		  if(!stat) {
+			   int count = 10 * 100;
+			   while(c->lct_running && --count) {
+				    current->state = TASK_INTERRUPTIBLE;
+				    schedule_timeout(1);
+			   }
+
+			   if(!count)
+				    printk(KERN_ERR
+					     "%s: LCT thread still running!\n",
+					     c->name);
+		  }
+	 }
+
 	p=&i2o_controller_chain;
 
 	while(*p)
 	{
 		if(*p==c)
 		{
-			/* Ask the IOP to switch into RESET state */
-			i2o_reset_controller(c);
+			   /* Ask the IOP to switch to HOLD state */
+			   if (i2o_clear_controller(c) < 0)
+				    printk(KERN_ERR "Unable to clear iop%d\n", c->unit);
 
 			/* Release IRQ */
 			c->destructor(c);
 
 			*p=c->next;
-			spin_unlock(&i2o_configuration_lock);
+			up(&i2o_configuration_lock);
 
 			if(c->page_frame)
 				kfree(c->page_frame);
@@ -363,6 +551,8 @@
 				kfree(c->lct);
 			if(c->status_block)
 				kfree(c->status_block);
+			if(c->dlct)
+				kfree(c->dlct);
 
 			i2o_controllers[c->unit]=NULL;
 			memcpy(name, c->name, strlen(c->name)+1);
@@ -375,7 +565,7 @@
 		}
 		p=&((*p)->next);
 	}
-	spin_unlock(&i2o_configuration_lock);
+	up(&i2o_configuration_lock);
 	printk(KERN_ERR "i2o_delete_controller: bad pointer!\n");
 	return -ENOENT;
 }
@@ -392,11 +582,11 @@
 	if(n<0 || n>=MAX_I2O_CONTROLLERS)
 		return NULL;
 	
-	spin_lock(&i2o_configuration_lock);
+	down(&i2o_configuration_lock);
 	c=i2o_controllers[n];
 	if(c!=NULL)
 		atomic_inc(&c->users);
-	spin_unlock(&i2o_configuration_lock);
+	up(&i2o_configuration_lock);
 	return c;
 }
 	
@@ -405,117 +595,99 @@
  * Claim a device for use as either the primary user or just
  * as a management/secondary user
  */
-int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h, u32 type)
+int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h)
 {
-	/* Device already has a primary user or too many managers */
-	if((type == I2O_CLAIM_PRIMARY && d->owner) ||
-		(d->num_managers == I2O_MAX_MANAGERS))
-	{
-			return -EBUSY;
-	}
+	down(&i2o_configuration_lock);
 
-	if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 1, type))
+	if(d->owner)
 	{
+		printk(KERN_INFO "issue claim called, but dev has owner!");
+		up(&i2o_configuration_lock);
 		return -EBUSY;
 	}
 
-	spin_lock(&i2o_configuration_lock);
-	if(d->owner)
+	if(i2o_issue_claim(d->controller,d->lct_data.tid, h->context, 1, I2O_CLAIM_PRIMARY))
 	{
-		spin_unlock(&i2o_configuration_lock);
+		up(&i2o_configuration_lock);
 		return -EBUSY;
 	}
-	atomic_inc(&d->controller->users);
-
-	if(type == I2O_CLAIM_PRIMARY)
-		d->owner=h;
-	else
-		if (i2o_add_management_user(d, h))
-			printk(KERN_WARNING "i2o: Too many managers for TID %d\n",
-				d->lct_data->tid);
-									       
 
-	spin_unlock(&i2o_configuration_lock);
+	d->owner=h;
+	up(&i2o_configuration_lock);
 	return 0;
 }
 
-int i2o_release_device(struct i2o_device *d, struct i2o_handler *h, u32 type)
+int i2o_release_device(struct i2o_device *d, struct i2o_handler *h)
 {
 	int err = 0;
 
-	spin_lock(&i2o_configuration_lock);
-
-	/* Primary user */
-	if(type == I2O_CLAIM_PRIMARY)
+	down(&i2o_configuration_lock);
+	if(d->owner != h)
 	{
-		if(d->owner != h)
-			err = -ENOENT;
-		else
-		{
-			if(i2o_issue_claim(d->controller, d->lct_data->tid, h->context, 0,
-					   type))
-			{
-				err = -ENXIO;
-			}
-			else
-			{
-				d->owner = NULL;
-				atomic_dec(&d->controller->users);
-			}
-		}
-
-		spin_unlock(&i2o_configuration_lock);
-		return err;
+		up(&i2o_configuration_lock);
+		return -ENOENT;
 	}
 
-	/* Management or other user */
-	if(i2o_remove_management_user(d, h))
-		err = -ENOENT;
-	else
+	if(i2o_issue_claim(d->controller, d->lct_data.tid, h->context, 0,
+			   I2O_CLAIM_PRIMARY))
 	{
-		atomic_dec(&d->controller->users);
-
-		if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 0, 
-				   type))
-			err = -ENXIO;
+		err = -ENXIO;
 	}
 
-	spin_unlock(&i2o_configuration_lock);
+	d->owner = NULL;
+
+	up(&i2o_configuration_lock);
 	return err;
 }
 
-int i2o_add_management_user(struct i2o_device *d, struct i2o_handler *h)
+
+/*
+ * Called by OSMs to let the core know that they want to be
+ * notified if the given device is deleted from the system.
+ */
+int i2o_device_notify_on(struct i2o_device *d, struct i2o_handler *h)
 {
-	int i;
+	 int i;
 
-	if(d->num_managers == I2O_MAX_MANAGERS)
-		return 1;
+	 if(d->num_managers == I2O_MAX_MANAGERS)
+		  return -ENOSPC;
 
-	for(i = 0; i < I2O_MAX_MANAGERS; i++)
-		if(!d->managers[i])
-			d->managers[i] = h;
-	
-	d->num_managers++;
-	
-	return 0;
+	 for(i = 0; i < I2O_MAX_MANAGERS; i++)
+	 {
+		  if(!d->managers[i])
+		  {
+			   d->managers[i] = h;
+			   break;
+		  }
+	 }
+
+	 d->num_managers++;
+
+	 return 0;
 }
 
-int i2o_remove_management_user(struct i2o_device *d, struct i2o_handler *h)
+/*
+ * Called by OSMs to let the core know that they no longer
+ * are interested in the fate of the given device.
+ */
+int i2o_device_notify_off(struct i2o_device *d, struct i2o_handler *h)
 {
-	int i;
+	 int i;
 
-	for(i=0; i < I2O_MAX_MANAGERS; i++)
-	{
-		if(d->managers[i] == h)
-		{
-			d->managers[i] = NULL;
-			return 0;
-		}
-	}
+	 for(i=0; i < I2O_MAX_MANAGERS; i++)
+	 {
+		  if(d->managers[i] == h)
+		  {
+			   d->managers[i] = NULL;
+			   d->num_managers--;
+			   return 0;
+		  }
+	 }
 
-	return -ENOENT;
+	 return -ENOENT;
 }
 
+
 /*
  *	This is called by the bus specific driver layer when an interrupt
  *	or poll of this card interface is desired.
@@ -679,10 +851,14 @@
  *	 Dump the information block associated with a given unit (TID)
  */
  
-void i2o_report_controller_unit(struct i2o_controller *c, int unit)
+void i2o_report_controller_unit(struct i2o_controller *c, struct i2o_device *d)
 {
 	char buf[64];
-	
+	char str[22];
+	int unit = d->lct_data.tid;
+
+	printk(KERN_INFO "Target ID %d.\n", unit);
+
 	if(i2o_query_scalar(c, unit, 0xF100, 3, buf, 16)>=0)
 	{
 		buf[16]=0;
@@ -691,20 +867,38 @@
 	if(i2o_query_scalar(c, unit, 0xF100, 4, buf, 16)>=0)
 	{
 		buf[16]=0;
-		printk("     Device: %s", buf);
+		printk(KERN_INFO "     Device: %s", buf);
 	}
 #if 0
 	if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)>=0)
 	{
 		buf[16]=0;
-		printk("Description: %s", buf);
+		printk(KERN_INFO "Description: %s", buf);
 	}
 #endif	
 	if(i2o_query_scalar(c, unit, 0xF100, 6, buf, 8)>=0)
 	{
 		buf[8]=0;
-		printk("        Rev: %s\n", buf);
+		printk(KERN_INFO "  Rev: %s\n", buf);
 	}
+
+	 printk(KERN_INFO "    Class: ");
+	 sprintf(str, "%-21s", i2o_get_class_name(d->lct_data.class_id));
+	 printk(KERN_INFO "%s\n", str);
+
+	 printk(KERN_INFO "  Subclass: 0x%04X\n", d->lct_data.sub_class);
+	 printk(KERN_INFO "     Flags: ");
+
+	 if(d->lct_data.device_flags&(1<<0))
+		  printk("C");	     // ConfigDialog requested
+	 if(d->lct_data.device_flags&(1<<1))
+		  printk("U");	     // Multi-user capable
+	 if(!(d->lct_data.device_flags&(1<<4)))
+		  printk("P");	     // Peer service enabled!
+	 if(!(d->lct_data.device_flags&(1<<5)))
+		  printk("M");	     // Mgmt service enabled!
+	 printk("\n");
+
 }
 
 
@@ -816,9 +1010,7 @@
 	int i;
 	int max;
 	int tid;
-	u32 *p;
 	struct i2o_device *d;
-	char str[22];
 	i2o_lct *lct = c->lct;
 
 	if (lct == NULL) {
@@ -847,35 +1039,15 @@
 		d->controller = c;
 		d->next = NULL;
 
-		d->lct_data = &lct->lct_entry[i];
+		memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry));
 
 		d->flags = 0;
-		tid = d->lct_data->tid;
+		tid = d->lct_data.tid;
 		
-		printk(KERN_INFO "Target ID %d.\n", tid);
-
-		i2o_report_controller_unit(c, tid);
+		i2o_report_controller_unit(c, d);
 		
 		i2o_install_device(c, d);
 		
-		printk(KERN_INFO "     Class: ");
-		
-		sprintf(str, "%-21s", i2o_get_class_name(d->lct_data->class_id));
-		printk("%s", str);
-
-		printk(" Subclass: 0x%04X                Flags: ", 
-			d->lct_data->sub_class);
-
-		if(d->lct_data->device_flags&(1<<0))
-			printk("C");		// ConfigDialog requested
-		if(d->lct_data->device_flags&(1<<1))
-			printk("M");		// Multi-user capable
-		if(!(d->lct_data->device_flags&(1<<4)))
-			printk("P");		// Peer service enabled!
-		if(!(d->lct_data->device_flags&(1<<5)))
-			printk("m");		// Mgmt service enabled!
-		printk("\n");
-		p+=9;
 	}
 	return 0;
 }
@@ -890,6 +1062,8 @@
 	u32 msg[4];
 	int ret;
 
+	i2o_status_get(c);
+
 	/* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */
 
 	if ((c->status_block->iop_state != ADAPTER_STATE_READY) &&
@@ -924,6 +1098,15 @@
 	u32 msg[4];
 	int ret;
 	
+	i2o_status_get(c);
+
+	/* Enable only allowed on READY state */
+	if(c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL)
+		return 0;
+
+	if(c->status_block->iop_state != ADAPTER_STATE_READY)
+		return -EINVAL;
+
 	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
 	msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID;
 	/* msg[2] filled in i2o_post_wait */
@@ -995,6 +1178,7 @@
 	u32 *msg;
 	long time;
 
+	dprintk(("begin RESET\n"));
 	/* Quiesce all IOPs first */
 
 	for (iop = i2o_controller_chain; iop; iop = iop->next)
@@ -1126,6 +1310,9 @@
 	msg[6]=virt_to_phys(c->status_block);
 	msg[7]=0;	/* 64bit host FIXME */
 	msg[8]=sizeof(i2o_status_block); /* always 88 bytes */
+	
+	if(msg[8]!=88)
+		printk(KERN_CRIT "i2o compiled wrongly\n");
 
 	i2o_post_message(c,m);
 
@@ -1203,8 +1390,7 @@
 		msg[5]= virt_to_phys(c->hrt);	/* Dump it here */
 
 		if ((ret = i2o_post_wait(c, msg, sizeof(msg), 20))) {
-			printk(KERN_ERR "%s: Unable to get HRT (status=%#10x)\n",
-				c->name, ret);	
+			printk(KERN_ERR "%s: Unable to get HRT (status=%#10x)\n", c->name, ret);	
 			return ret;
 		}
 
@@ -1222,43 +1408,43 @@
 
 static int i2o_systab_send(struct i2o_controller *iop)
 {
-        u32 msg[12];
-        u32 privmem[2];
-        u32 privio[2];
-        int ret;
+	 u32 msg[12];
+	 u32 privmem[2];
+	 u32 privio[2];
+	 int ret;
 
 	/* See i2o_status_block */
 #if 0
-        iop->status->current_mem_base;
-        iop->status->current_mem_size;
-        iop->status->current_io_base;
-        iop->status->current_io_size;
+	 iop->status->current_mem_base;
+	 iop->status->current_mem_size;
+	 iop->status->current_io_base;
+	 iop->status->current_io_size;
 #endif
 
 /* FIXME */
-        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;
+	 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;
 
 	msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6;
-        msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
 	/* msg[2] filled in i2o_post_wait */
 	msg[3] = 0;
-        msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */
-        msg[5] = 0;                               /* Segment 0 */
+	msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */
+	msg[5] = 0;				   /* Segment 0 */
 
-        /* 
-         * Provide three SGL-elements:
-         * System table (SysTab), Private memory space declaration and 
-         * Private i/o space declaration  
+	/* 
+	 * Provide three SGL-elements:
+	 * System table (SysTab), Private memory space declaration and 
+	 * Private i/o space declaration  
 	 */
-        msg[6] = 0x54000000 | sys_tbl_len;
-        msg[7] = virt_to_phys(sys_tbl);
-        msg[8] = 0x54000000 | 0;
-        msg[9] = virt_to_phys(privmem);
-        msg[10] = 0xD4000000 | 0;
-        msg[11] = virt_to_phys(privio);
+	msg[6] = 0x54000000 | sys_tbl_len;
+	msg[7] = virt_to_phys(sys_tbl);
+	msg[8] = 0x54000000 | 0;
+	msg[9] = virt_to_phys(privmem);
+	msg[10] = 0xD4000000 | 0;
+	msg[11] = virt_to_phys(privio);
 
 	if ((ret=i2o_post_wait(iop, msg, sizeof(msg), 120)))
 		printk(KERN_INFO "%s: Unable to set SysTab (status=%#10x).\n", 
@@ -1297,19 +1483,46 @@
 	 * If build_sys_table fails, we kill everything and bail
 	 * as we can't init the IOPs w/o a system table
 	 */	
+	 
+	dprintk(("SYSTAB\n"));
 	if (i2o_build_sys_table() < 0) {
 		i2o_sys_shutdown();
 		return;
 	}
 
+	dprintk(("ONLINE\n"));
+
 	/* If IOP don't get online, we need to rebuild the System table */
 	for (iop = i2o_controller_chain; iop; iop = niop) {
 		niop = iop->next;
 		if (i2o_online_controller(iop) < 0)
 			goto rebuild_sys_tab;
 	}
+
+	dprintk(("ACTIVE\n"));
 	
-	/* Active IOPs now in OPERATIONAL state */
+	/* Active IOPs now in OPERATIONAL state
+	 *
+	 * Register for status updates from all IOPs
+	 */
+	for(iop = i2o_controller_chain; iop; iop=iop->next) {
+
+		/* Create a kernel thread to deal with dynamic LCT updates */
+		iop->lct_pid = kernel_thread(i2o_dyn_lct, iop, CLONE_SIGHAND);
+
+		printk(KERN_INFO "event thread created as pid %d \n", iop->lct_pid);
+
+		/* Update change ind on DLCT */
+		iop->dlct->change_ind = iop->lct->change_ind;
+
+		/* Start dynamic LCT updates */
+		i2o_lct_notify(iop);
+
+		/* Register for all events from IRTOS */
+		i2o_event_register(iop, core_context, 0, 0, 0xFFFFFFFF);
+	}
+
+	dprintk(("DONE\n"));
 }
 
 /*
@@ -1336,11 +1549,13 @@
 	/* In INIT state, Wait Inbound Q to initilaize (in i2o_status_get) */
 	/* In READY state, Get status */
 
+	dprintk(("ACTIVATE\n"));
+	
 	if (i2o_status_get(iop) < 0) {
-		printk("Unable to obtain status of IOP, attempting a reset.\n");
+		printk(KERN_INFO "Unable to obtain status of IOP, attempting a reset.\n");
 		i2o_reset_controller(iop);
 		if (i2o_status_get(iop) < 0) {
-			printk("IOP not responding.\n");
+			printk(KERN_INFO "IOP not responding.\n");
 			i2o_delete_controller(iop);
 			return -1;
 		}
@@ -1352,17 +1567,17 @@
 		return -1;
 	}
 
-//	if (iop->status_block->iop_state == ADAPTER_STATE_HOLD ||
 	if (iop->status_block->iop_state == ADAPTER_STATE_READY ||
 	    iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL ||
+	    iop->status_block->iop_state == ADAPTER_STATE_HOLD ||
 	    iop->status_block->iop_state == ADAPTER_STATE_FAILED)
 	{
 		dprintk((KERN_INFO "%s: already running...trying to reset\n",
-				iop->name));
-		i2o_reset_controller(iop);			
+			iop->name));
+		dprintk(("Outbound q2\n"));
 
-		if (i2o_status_get(iop) < 0 || 
-			iop->status_block->iop_state != ADAPTER_STATE_RESET)
+		i2o_reset_controller(iop);			
+		if (i2o_status_get(iop) < 0 || iop->status_block->iop_state != ADAPTER_STATE_RESET)
 		{
 			printk(KERN_CRIT "%s: Failed to initialize.\n", iop->name);
 			i2o_delete_controller(iop);
@@ -1376,11 +1591,13 @@
 	}
 
 	/* In HOLD state */
+	dprintk("HRT\n");
 	
 	if (i2o_hrt_get(iop) < 0) {
 		i2o_delete_controller(iop);
 		return -1;
 	}
+	dprintk("DONE\n");
 
 	return 0;
 }
@@ -1463,7 +1680,7 @@
 
 	for(i=0; i< NMBR_MSG_FRAMES; i++) {
   		I2O_REPLY_WRITE32(c,m);
-                mb();
+		  mb();
 		m += MSG_FRAME_SIZE;
 	}
 
@@ -1512,14 +1729,38 @@
 		}
 	} while (c->lct == NULL);
 
-        if ((ret=i2o_parse_lct(c)) < 0)
-                return ret;
+	 if ((ret=i2o_parse_lct(c)) < 0)
+		  return ret;
 
 	return 0;
 }
 
 
 /*
+ * Like above, but used for async notification.  The main
+ * difference is that we keep track of the CurrentChangeIndiicator
+ * so that we only get updates when it actually changes.
+ *
+ */
+int i2o_lct_notify(struct i2o_controller *c)
+{
+	 u32 msg[8];
+
+	 msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
+	 msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
+	 msg[2] = core_context;
+	 msg[3] = 0xDEADBEEF;
+	 msg[4] = 0xFFFFFFFF;    /* All devices */
+	 msg[5] = c->dlct->change_ind+1; /* Next change */
+	 msg[6] = 0xD0000000|8192;
+	 msg[7] = virt_to_bus(c->dlct);
+
+	 return i2o_post_this(c, msg, sizeof(msg));
+}
+
+
+
+/*
  *	Bring a controller online into OPERATIONAL state. 
  */
  
@@ -1661,6 +1902,7 @@
 	struct i2o_post_wait_data *wait_data =
 		kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL);
 
+
 	if(!wait_data)
 		return -ENOMEM;
 
@@ -1675,7 +1917,7 @@
 	spin_unlock_irqrestore(&post_wait_lock, flags);
 
 	wait_data->wq = &wq_i2o_post;
-	wait_data->status = -EAGAIN;
+	wait_data->status = -ETIMEDOUT;
 
 	msg[2]=0x80000000|(u32)core_context|((u32)wait_data->id<<16);
 
@@ -1684,6 +1926,18 @@
 		status = wait_data->status;
 	}
 
+	if(status == -ETIMEDOUT)
+		printk(KERN_INFO "POST WAIT TIMEOUT\n");
+
+	/*
+	 * 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.
+	 */
+
 	p2 = NULL;
 	spin_lock_irqsave(&post_wait_lock, flags);
 	for(p1 = post_wait_queue; p1; p2 = p1, p1 = p1->next) {
@@ -1733,47 +1987,329 @@
 	}
 	spin_unlock(&post_wait_lock);
 
-	printk(KERN_DEBUG "i2o: i2o_post_wait reply after timeout!");
+	printk(KERN_DEBUG "i2o: i2o_post_wait reply after timeout!\n");
 }
 
 /*
  *      Send UTIL_EVENT messages
  */
 
-int i2o_event_register(struct i2o_controller *c, int tid, int context,
-                        u32 evt_mask)
+int i2o_event_register(struct i2o_controller *c, u32 tid, u32 init_context, 
+		u32 tr_context, u32 evt_mask)
 {
-        u32 msg[5];
+	 u32 msg[5];
 
-        msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
-        msg[1] = I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | tid;
-        msg[2] = context;
-        msg[3] = 0;
-        msg[4] = evt_mask;
-
-        if (i2o_post_this(c, msg, sizeof(msg)) < 0)
-                return -ETIMEDOUT;
-
-        return 0;
-}
-
-int i2o_event_ack(struct i2o_controller *c, int tid, int context,
-                u32 evt_indicator, void *evt_data, int evt_data_len)
+	 msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+	 msg[1] = I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | tid;
+	 msg[2] = (u32) init_context;
+	 msg[3] = (u32)tr_context ;
+	 msg[4] = evt_mask;
+
+	 if (i2o_post_this(c, msg, sizeof(msg)) < 0)
+		  return -ETIMEDOUT;
+
+	 return 0;
+}
+
+int i2o_event_ack(struct i2o_controller *c, u32 *msg)
+{
+	struct i2o_message *m = (struct i2o_message *)msg;
+
+	 m->function = I2O_CMD_UTIL_EVT_ACK;
+	 return i2o_post_wait(c, msg, m->size * 4, 2);
+
+}
+
+/*
+ * Core event handler.  Runs as a separate thread and is woken
+ * up whenever there is an Executive class event.
+ */
+static int i2o_core_evt(void *reply_data)
+{
+	 struct reply_info *reply = (struct reply_info *) reply_data;
+	 u32 *msg = reply->msg;
+	 struct i2o_controller *c = NULL;
+	 int flags;
+	 struct fs_struct *fs;
+
+	 lock_kernel();
+
+	 dprintk((KERN_INFO "i2o_core_evt: I2O CORE Event thread at %p\n",
+&i2o_core_evt));
+	 exit_files(current);
+	 exit_mm(current);
+	 current->session = 1;
+	 current->pgrp = 1;
+	 /* Become as one with the init task */
+	 exit_fs(current);
+	 fs = init_task.fs;
+	 current->fs = fs;
+	 atomic_inc(&fs->count);
+
+	 unlock_kernel();
+
+	 strcpy(current->comm, "i2oevtd");
+	 evt_running = 1;
+
+	 while(1)
+	 {
+		  down_interruptible(&evt_sem);
+		  if(signal_pending(current))
+		  {
+			   dprintk((KERN_INFO "I2O event thread dead\n"));
+			   evt_running = 0;
+			   return 0;
+		  }
+
+		  /*
+		   * Copy the data out of the queue so that we don't have to lock
+		   * around the whole function and just around the qlen update
+		   */
+		  spin_lock_irqsave(&i2o_evt_lock, flags);
+		  memcpy(reply, &events[evt_out], sizeof(struct reply_info));
+		  MODINC(evt_out, I2O_EVT_Q_LEN);
+		  evt_q_len--;
+		  spin_unlock_irqrestore(&i2o_evt_lock, flags);
+
+		  c = reply->iop;
+		  dprintk((KERN_INFO "I2O IRTOS EVENT: iop%d, event %#10x\n", c->unit, msg[4]));
+
+		  /*
+		   * We do not attempt to delete/quiesce/etc. the controller if
+		   * some sort of error indidication occurs.  We may want to do
+		   * so in the future, but for now we just let the user deal with
+		   * it.  One reason for this is that what to do with an error
+		   * or when to send what ærror is not really agreed on, so
+		   * we get errors that may not be fatal but just look like they
+		   * are...so let the user deal with it.
+		   */
+		  switch(msg[4])
+		  {
+			   case I2O_EVT_IND_EXEC_RESOURCE_LIMITS:
+				    printk(KERN_ERR "iop%d: Out of resources\n", c->unit);
+				    break;
+
+			   case I2O_EVT_IND_EXEC_POWER_FAIL:
+				    printk(KERN_ERR "iop%d: Power failure\n", c->unit);
+				    break;
+
+			   case I2O_EVT_IND_EXEC_HW_FAIL:
+			   {
+				    char *fail[] =
+					     {
+						"Unknown Error",
+						"Power Lost",
+						"Code Violation",
+						"Parity Error",
+						"Code Execution Exception",
+						"Watchdog Timer Expired"
+					     };
+
+				    if(msg[5] <= 6)
+					     printk(KERN_ERR "%s: Hardware Failure: %s\n", c->name, fail[msg[5]]);
+				    else
+					     printk(KERN_ERR "%s: Unknown Hardware Failure\n", c->name);
+
+				    break;
+			   }
+
+			   /*
+			    * New device created
+			    * - Create a new i2o_device entry
+			    * - Inform all interested drivers about this device's existence
+			    */
+			   case I2O_EVT_IND_EXEC_NEW_LCT_ENTRY:
+			   {
+				    struct i2o_device *d = (struct i2o_device *)
+					     kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
+				    int i;
+
+				    memcpy(&d->lct_data, &msg[5], sizeof(i2o_lct_entry));
+
+				    d->next = NULL;
+				    d->controller = c;
+				    d->flags = 0;
+
+				    i2o_report_controller_unit(c, d);
+				    i2o_install_device(c,d);
+
+				    for(i = 0; i < MAX_I2O_MODULES; i++)
+				    {
+		 			if(i2o_handlers[i] && i2o_handlers[i]->new_dev_notify && (i2o_handlers[i]->class&d->lct_data.class_id))
+					{
+						spin_lock_irqsave(&i2o_dev_lock, flags);
+						i2o_handlers[i]->new_dev_notify(c,d);
+						spin_unlock_irqrestore(&i2o_dev_lock, flags);
+					}
+				    }
+
+				    break;
+			   }
+
+			   /*
+			    * LCT entry for a device has been modified, so update it
+			    * internally.
+			    */
+			   case I2O_EVT_IND_EXEC_MODIFIED_LCT:
+			   {
+				    struct i2o_device *d;
+				    i2o_lct_entry *new_lct = (i2o_lct_entry *)&msg[5];
+				    for(d = c->devices; d; d = d->next)
+				    {
+					     if(d->lct_data.tid == new_lct->tid)
+					     {
+						      memcpy(&d->lct_data, new_lct, sizeof(i2o_lct_entry));
+						      break;
+					     }
+				    }
+				    break;
+			   }
+
+			   case I2O_EVT_IND_CONFIGURATION_FLAG:
+				    printk(KERN_WARNING "%s requires user configuration\n", c->name);
+				    break;
+
+			   case I2O_EVT_IND_GENERAL_WARNING:
+				    printk(KERN_WARNING "%s: Warning notification received! Check configuration for errors!\n", c->name);
+				    break;
+
+			   default:
+				    printk(KERN_WARNING "%s: Unknown event...check config\n", c->name);
+				    break;
+		  }
+	 }
+
+	 return 0;
+}
+
+/*
+ * Dynamic LCT update.  This compares the LCT with the currently
+ * installed devices to check for device deletions..this needed b/c there
+ * is no DELETED_LCT_ENTRY EventIndicator for the Executive class so
+ * we can't just have the event handler do this...annoying
+ *
+ * This is a hole in the spec that will hopefully be fixed someday.
+ */
+static int i2o_dyn_lct(void *foo)
 {
-        u32 msg[c->inbound_size];
+	 struct i2o_controller *c = (struct i2o_controller *)foo;
+	 struct i2o_device *d = NULL;
+	 struct i2o_device *d1 = NULL;
+	 int i = 0;
+	 int found = 0;
+	 int entries;
+	 void *tmp;
+	 char name[16];
+	 struct fs_struct *fs;
+	 unsigned long flags;
+
+	 lock_kernel();
+
+	 dprintk((KERN_INFO "i2o_dyn_lct: I2O CORE Event thread at %p\n",
+&i2o_dyn_lct));
+	 exit_files(current);
+	 exit_mm(current);
+	 current->session = 1;
+	 current->pgrp = 1;
+	 /* Become as one with the init task */
+	 exit_fs(current);
+	 fs = init_task.fs;
+	 current->fs = fs;
+	 atomic_inc(&fs->count);
+
+	 unlock_kernel();
+
+	 sprintf(name, "iop%d_lctd", c->unit);
+	 strcpy(current->comm, name);
+
+	 c->lct_running = 1;
+
+	 while(1)
+	 {
+		  down_interruptible(&c->lct_sem);
+		  if(signal_pending(current))
+		  {
+			   dprintk((KERN_ERR "%s: LCT thread dead\n", c->name));
+			   c->lct_running = 0;
+			   return 0;
+		  }
+
+		  entries = c->dlct->table_size;
+		  entries -= 3;
+		  entries /= 9;
+
+		  dprintk((KERN_INFO "I2O: Dynamic LCT Update\n"));
+		  dprintk((KERN_INFO "I2O: Dynamic LCT contains %d entries\n", entries));
+
+		  if(!entries)
+		  {
+			   printk(KERN_INFO "iop%d: Empty LCT???\n", c->unit);
+			   continue;
+		  }
+
+		  /*
+		   * Loop through all the devices on the IOP looking for their
+		   * LCT data in the LCT.  We assume that TIDs are not repeated.
+		   * as that is the only way to really tell.  It's been confirmed
+		   * by the IRTOS vendor(s?) that TIDs are not reused until they
+		   * wrap arround(4096), and I doubt a system will up long enough
+		   * to create/delete that many devices.
+		   */
+		  for(d = c->devices; d; )
+		  {
+			   found = 0;
+			   d1 = d->next;
+
+			   for(i = 0; i < entries; i++)
+			   {
+				    if(d->lct_data.tid == c->dlct->lct_entry[i].tid) 
+				    {
+					     found = 1;
+					     break;
+				    }
+			   }
+			   if(!found)
+			   {
+				dprintk((KERN_INFO "Deleted device!\n"));
+				spin_lock_irqsave(&i2o_dev_lock,flags);
+				i2o_delete_device(d);
+				spin_unlock_irqrestore(&i2o_dev_lock,flags);
+			   }
+			   d = d1;
+		  }
+
+		  /*
+		   * Tell LCT to renotify us next time there is a change
+		   */
+		  i2o_lct_notify(c);
+
+		  /*
+		   * Copy new LCT into public LCT
+		   *
+		   * Possible race if someone is reading LCT while  we are copying 
+		   * over it. If this happens, we'll fix it then. but I doubt that
+		   * the LCT will get updated often enough or will get read by
+		   * a user often enough to worry.
+		   */
+		  if(c->lct->table_size < c->dlct->table_size)
+		  {
+			   tmp = c->lct;
+			   c->lct = kmalloc(c->dlct->table_size<<2, GFP_KERNEL);
+			   if(!c->lct)
+			   {
+				    printk(KERN_ERR "%s: No memory for LCT!\n", c->name);
+				    c->lct = tmp;
+				    continue;
+			   }
+			   kfree(tmp);
+		  }
+		  memcpy(c->lct, c->dlct, c->dlct->table_size<<2);
+	 }
 
-        msg[0] = I2O_MESSAGE_SIZE(5 + evt_data_len / 4) | SGL_OFFSET_5;
-        msg[1] = I2O_CMD_UTIL_EVT_ACK << 24 | HOST_TID << 12 | tid;
-	msg[2] = context;
-	msg[3] = 0;
-        msg[4] = evt_indicator;
-        memcpy(msg+5, evt_data, evt_data_len);
+	 return 0;
+}
 
-        if (i2o_post_this(c, msg, sizeof(msg)) < 0)
-                return -ETIMEDOUT;
 
-        return 0;
-}
 
 /*
  *	Issue UTIL_CLAIM or UTIL_RELEASE messages
@@ -1805,7 +2341,7 @@
  *	ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
  */
 int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid, 
-                void *opblk, int oplen, void *resblk, int reslen)
+		  void *opblk, int oplen, void *resblk, int reslen)
 {
 	u32 msg[9]; 
 	u32 *res = (u32 *)resblk;
@@ -1835,21 +2371,21 @@
 		return -((res[1] >> 16) & 0xFF); /* -BlockStatus */
 	}
 
-        return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */ 
+	 return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */ 
 }
 
 /*
  *	 Query one scalar group value or a whole scalar group.
- */                  	
+ */		    	
 int i2o_query_scalar(struct i2o_controller *iop, int tid, 
-                     int group, int field, void *buf, int buflen)
+			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 */
 	int size;
 
 	if (field == -1)  		/* whole group */
-       		opblk[4] = -1;
+			opblk[4] = -1;
 
 	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, 
 		opblk, sizeof(opblk), resblk, sizeof(resblk));
@@ -1869,7 +2405,7 @@
 {
 	u16 *opblk;
 	u8  resblk[8+buflen]; /* 8 bytes for header */
-        int size;
+	 int size;
 
 	opblk = kmalloc(buflen+64, GFP_KERNEL);
 	if (opblk == NULL)
@@ -1878,16 +2414,16 @@
 		return -ENOMEM;
 	}
 
-	opblk[0] = 1;                        /* operation count */
-	opblk[1] = 0;                        /* pad */
+	opblk[0] = 1;			   /* operation count */
+	opblk[1] = 0;			   /* pad */
 	opblk[2] = I2O_PARAMS_FIELD_SET;
 	opblk[3] = group;
 
-	if(field == -1) {               /* whole group */
+	if(field == -1) {		 /* whole group */
 		opblk[4] = -1;
 		memcpy(opblk+5, buf, buflen);
 	}
-	else                            /* single field */
+	else				/* single field */
 	{
 		opblk[4] = 1;
 		opblk[5] = field;
@@ -2052,9 +2588,9 @@
 	};
 
 	if (req_status > I2O_REPLY_STATUS_PROGRESS_REPORT)
-		printk("%0#4x / ", req_status);
+		printk(KERN_INFO "%0#4x / ", req_status);
 	else
-		printk("%s / ", REPLY_STATUS[req_status]);
+		printk(KERN_INFO "%s / ", REPLY_STATUS[req_status]);
 	
 	return;
 }
@@ -2099,9 +2635,9 @@
 	};
 
 	if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE)
-		printk("%0#4x.\n", detailed_status);
+		printk(KERN_INFO "%0#4x.\n", detailed_status);
 	else
-		printk("%s.\n", COMMON_DSC[detailed_status]);
+		printk(KERN_INFO "%s.\n", COMMON_DSC[detailed_status]);
 
 	return;
 }
@@ -2274,25 +2810,30 @@
 	u8 cmd = (msg[1]>>24)&0xFF;
 	u8 req_status = (msg[4]>>24)&0xFF;
 	u16 detailed_status = msg[4]&0xFFFF;
+	struct i2o_handler *h = i2o_handlers[msg[2] & (MAX_I2O_MODULES-1)];
 
 	printk("%s%s: ", severity, module);
 
-	if (cmd < 0x1F) { 			// Utility Class
-		i2o_report_util_cmd(cmd);
-		i2o_report_common_status(req_status);
-		i2o_report_common_dsc(detailed_status);
-		return;
-	}
 
-	if (cmd >= 0xA0 && cmd <= 0xEF) {	// Executive class
-		i2o_report_exec_cmd(cmd);
-		i2o_report_common_status(req_status);
-		i2o_report_common_dsc(detailed_status);
-		return;
-	}
-	
-	printk("%02x, %02x / %04x.\n", cmd, req_status, detailed_status);
-	return;
+	switch (h->class) {
+		  case I2O_CLASS_EXECUTIVE:
+			   if (cmd < 0x1F) {		 // Utility cmd
+				    i2o_report_util_cmd(cmd);
+				    i2o_report_common_status(req_status);
+				    i2o_report_common_dsc(detailed_status);
+			   }
+			   if (cmd >= 0xA0 && cmd <= 0xEF) { // Executive cmd
+				    i2o_report_exec_cmd(cmd);
+				    i2o_report_common_status(req_status);
+				    i2o_report_common_dsc(detailed_status);
+			   }
+		  break;
+
+		  default:
+			   printk(KERN_INFO "%02x, %02x / %04x.\n",
+				    cmd, req_status, detailed_status);
+	 }
+
 }
 
 /* Used to dump a message to syslog during debugging */
@@ -2308,6 +2849,55 @@
 #endif
 }
 
+
+/*
+ * I2O reboot/shutdown notification.
+ *
+ * - Call each OSM's reboot notifier (if one exists)
+ * - Quiesce each IOP in the system
+ *
+ * Each IOP has to be quiesced before we can ensure that the system
+ * can be properly shutdown as a transaction that has already been
+ * acknowledged still needs to be placed in permanent store on the IOP.
+ * The SysQuiesce causes the IOP to force all HDMs to complete their
+ * transactions before returning, so only at that point is it safe
+ *
+ */
+
+static int i2o_reboot_event(struct notifier_block *n, unsigned long code, void
+*p)
+{
+	 int i = 0;
+	 struct i2o_controller *c = NULL;
+
+	 if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF)
+		  return NOTIFY_DONE;
+
+	 printk(KERN_INFO "Shutting down I2O system.\n");
+	 printk(KERN_INFO
+		  "   This could take a few minutes if there are many devices attached\n");
+
+	 for(i = 0; i < MAX_I2O_MODULES; i++)
+	 {
+		  if(i2o_handlers[i] && i2o_handlers[i]->reboot_notify)
+			   i2o_handlers[i]->reboot_notify();
+	 }
+
+	 for(c = i2o_controller_chain; c; c = c->next)
+	 {
+		  if(i2o_quiesce_controller(c))
+		  {
+			   printk(KERN_WARNING "i2o: Could not quiesce %s."  "
+				    Verify setup on next system power up.\n", c->name);
+		  }
+	 }
+
+	 printk(KERN_INFO "I2O system down.\n");
+	 return NOTIFY_DONE;
+}
+
+
+
 #ifdef MODULE
 
 EXPORT_SYMBOL(i2o_install_handler);
@@ -2324,6 +2914,9 @@
 
 EXPORT_SYMBOL(i2o_claim_device);
 EXPORT_SYMBOL(i2o_release_device);
+EXPORT_SYMBOL(i2o_device_notify_on);
+EXPORT_SYMBOL(i2o_device_notify_off);
+
 EXPORT_SYMBOL(i2o_run_queue);
 EXPORT_SYMBOL(i2o_activate_controller);
 EXPORT_SYMBOL(i2o_get_class_name);
@@ -2363,22 +2956,62 @@
 		printk(KERN_INFO "i2o: No PCI I2O controllers found\n");
 #endif
 
+
+	/*
+	 * Initialize event handling thread
+	 */
+	 sema_init(&evt_sem, 0);
+	 evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND);
+	 if(evt_pid < 0)
+	 {
+		  printk(KERN_ERR "I2O: Could not create event handler kernel thread\n");
+		  i2o_remove_handler(&i2o_core_handler);
+		  return 0;
+	 }
+	 else printk(KERN_INFO "event thread created as pid %d \n", evt_pid);
+
 	if(i2o_num_controllers)
 		i2o_sys_init();
 
+	register_reboot_notifier(&i2o_reboot_notifier);
+
 	return 0;
 }
 
 void cleanup_module(void)
 {
+	 int stat;
+
+	 unregister_reboot_notifier(&i2o_reboot_notifier);
+
 	if(i2o_num_controllers)
 		i2o_sys_shutdown();
 
+	 /*
+	  * If this is shutdown time, the thread has already been killed
+	  */
+	 if(evt_running) {
+		  stat = kill_proc(evt_pid, SIGTERM, 1);
+		  if(!stat) {
+			   int count = 10 * 100;
+			   while(evt_running && count) {
+				    current->state = TASK_INTERRUPTIBLE;
+				    schedule_timeout(1);
+			   }
+
+			   if(!count)
+				    printk(KERN_ERR "i2o: Event thread still running!\n");
+		  }
+	 }
+
+
 #ifdef CONFIG_I2O_PCI_MODULE
 	i2o_pci_core_detach();
 #endif
 
 	i2o_remove_handler(&i2o_core_handler);
+	 unregister_reboot_notifier(&i2o_reboot_notifier);
+
 }
 
 #else
@@ -2402,6 +3035,21 @@
 
 	core_context = i2o_core_handler.context;
 
+	 /*
+	  * Initialize event handling thread
+	  * We may not find any controllers, but still want this as
+	  * down the road we may have hot pluggable controllers that
+	  * need to be dealt with.
+	  */
+	 sema_init(&evt_sem, 0);
+	 if((evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND)) <
+0)
+	 {
+		  printk(KERN_ERR "I2O: Could not create event handler kernel thread\n");
+		  i2o_remove_handler(&i2o_core_handler);
+		  return 0;
+	 }
+
 #ifdef CONFIG_I2O_PCI
 	i2o_pci_init();
 #endif
@@ -2409,16 +3057,22 @@
 	if(i2o_num_controllers)
 		i2o_sys_init();
 
+	 register_reboot_notifier(&i2o_reboot_notifier);
+
 	i2o_config_init();
+
 #ifdef CONFIG_I2O_BLOCK
 	i2o_block_init();
 #endif
+
 #ifdef CONFIG_I2O_SCSI
 	i2o_scsi_init();
 #endif
+
 #ifdef CONFIG_I2O_LAN
 	i2o_lan_init();
 #endif
+
 #ifdef CONFIG_I2O_PROC
 	i2o_proc_init();
 #endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)