#define SI_SHORT_TIMEOUT_USEC  250 /* .25ms when the SM request a
                                        short timeout */
 
+/* Bit for BMC global enables. */
+#define IPMI_BMC_RCV_MSG_INTR     0x01
+#define IPMI_BMC_EVT_MSG_INTR     0x02
+#define IPMI_BMC_EVT_MSG_BUFF     0x04
+#define IPMI_BMC_SYS_LOG          0x08
+
 enum si_intf_state {
        SI_NORMAL,
        SI_GETTING_FLAGS,
        SI_CLEARING_FLAGS_THEN_SET_IRQ,
        SI_GETTING_MESSAGES,
        SI_ENABLE_INTERRUPTS1,
-       SI_ENABLE_INTERRUPTS2
+       SI_ENABLE_INTERRUPTS2,
+       SI_DISABLE_INTERRUPTS1,
+       SI_DISABLE_INTERRUPTS2
        /* FIXME - add watchdog stuff. */
 };
 
        smi_info->si_state = SI_ENABLE_INTERRUPTS1;
 }
 
+static void start_disable_irq(struct smi_info *smi_info)
+{
+       unsigned char msg[2];
+
+       msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+       msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
+
+       smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
+       smi_info->si_state = SI_DISABLE_INTERRUPTS1;
+}
+
 static void start_clear_flags(struct smi_info *smi_info)
 {
        unsigned char msg[3];
 static inline void disable_si_irq(struct smi_info *smi_info)
 {
        if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
-               disable_irq_nosync(smi_info->irq);
+               start_disable_irq(smi_info);
                smi_info->interrupt_disabled = 1;
        }
 }
 static inline void enable_si_irq(struct smi_info *smi_info)
 {
        if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
-               enable_irq(smi_info->irq);
+               start_enable_irq(smi_info);
                smi_info->interrupt_disabled = 0;
        }
 }
                } else {
                        msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
                        msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
-                       msg[2] = msg[3] | 1; /* enable msg queue int */
+                       msg[2] = (msg[3] |
+                                 IPMI_BMC_RCV_MSG_INTR |
+                                 IPMI_BMC_EVT_MSG_INTR);
                        smi_info->handlers->start_transaction(
                                smi_info->si_sm, msg, 3);
                        smi_info->si_state = SI_ENABLE_INTERRUPTS2;
                smi_info->si_state = SI_NORMAL;
                break;
        }
+
+       case SI_DISABLE_INTERRUPTS1:
+       {
+               unsigned char msg[4];
+
+               /* We got the flags from the SMI, now handle them. */
+               smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
+               if (msg[2] != 0) {
+                       printk(KERN_WARNING
+                              "ipmi_si: Could not disable interrupts"
+                              ", failed get.\n");
+                       smi_info->si_state = SI_NORMAL;
+               } else {
+                       msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+                       msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
+                       msg[2] = (msg[3] &
+                                 ~(IPMI_BMC_RCV_MSG_INTR |
+                                   IPMI_BMC_EVT_MSG_INTR));
+                       smi_info->handlers->start_transaction(
+                               smi_info->si_sm, msg, 3);
+                       smi_info->si_state = SI_DISABLE_INTERRUPTS2;
+               }
+               break;
+       }
+
+       case SI_DISABLE_INTERRUPTS2:
+       {
+               unsigned char msg[4];
+
+               /* We got the flags from the SMI, now handle them. */
+               smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
+               if (msg[2] != 0) {
+                       printk(KERN_WARNING
+                              "ipmi_si: Could not disable interrupts"
+                              ", failed set.\n");
+               }
+               smi_info->si_state = SI_NORMAL;
+               break;
+       }
        }
 }
 
        struct timeval    t;
 #endif
 
-       if (atomic_read(&smi_info->stop_operation))
-               return;
-
        spin_lock_irqsave(&(smi_info->si_lock), flags);
 #ifdef DEBUG_TIMING
        do_gettimeofday(&t);
        smi_info->interrupts++;
        spin_unlock(&smi_info->count_lock);
 
-       if (atomic_read(&smi_info->stop_operation))
-               goto out;
-
 #ifdef DEBUG_TIMING
        do_gettimeofday(&t);
        printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
 #endif
        smi_event_handler(smi_info, 0);
- out:
        spin_unlock_irqrestore(&(smi_info->si_lock), flags);
        return IRQ_HANDLED;
 }
        if (info->si_type == SI_BT) {
                rv = request_irq(info->irq,
                                 si_bt_irq_handler,
-                                IRQF_DISABLED,
+                                IRQF_SHARED | IRQF_DISABLED,
                                 DEVICE_NAME,
                                 info);
                if (!rv)
        } else
                rv = request_irq(info->irq,
                                 si_irq_handler,
-                                IRQF_DISABLED,
+                                IRQF_SHARED | IRQF_DISABLED,
                                 DEVICE_NAME,
                                 info);
        if (rv) {
        smi_info->interrupts++;
        spin_unlock(&smi_info->count_lock);
 
-       if (atomic_read(&smi_info->stop_operation))
-               goto out;
-
 #ifdef DEBUG_TIMING
        do_gettimeofday(&t);
        printk("**ACPI_GPE: %d.%9.9d\n", t.tv_sec, t.tv_usec);
 #endif
        smi_event_handler(smi_info, 0);
- out:
        spin_unlock_irqrestore(&(smi_info->si_lock), flags);
 
        return ACPI_INTERRUPT_HANDLED;
 
        list_del(&to_clean->link);
 
-       /* Tell the timer and interrupt handlers that we are shutting
-          down. */
-       spin_lock_irqsave(&(to_clean->si_lock), flags);
-       spin_lock(&(to_clean->msg_lock));
-
+       /* Tell the driver that we are shutting down. */
        atomic_inc(&to_clean->stop_operation);
 
-       if (to_clean->irq_cleanup)
-               to_clean->irq_cleanup(to_clean);
-
-       spin_unlock(&(to_clean->msg_lock));
-       spin_unlock_irqrestore(&(to_clean->si_lock), flags);
-
-       /* Wait until we know that we are out of any interrupt
-          handlers might have been running before we freed the
-          interrupt. */
-       synchronize_sched();
-
+       /* Make sure the timer and thread are stopped and will not run
+          again. */
        wait_for_timer_and_thread(to_clean);
 
-       /* Interrupts and timeouts are stopped, now make sure the
-          interface is in a clean state. */
+       /* Timeouts are stopped, now make sure the interrupts are off
+          for the device.  A little tricky with locks to make sure
+          there are no races. */
+       spin_lock_irqsave(&to_clean->si_lock, flags);
+       while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
+               spin_unlock_irqrestore(&to_clean->si_lock, flags);
+               poll(to_clean);
+               schedule_timeout_uninterruptible(1);
+               spin_lock_irqsave(&to_clean->si_lock, flags);
+       }
+       disable_si_irq(to_clean);
+       spin_unlock_irqrestore(&to_clean->si_lock, flags);
+       while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
+               poll(to_clean);
+               schedule_timeout_uninterruptible(1);
+       }
+
+       /* Clean up interrupts and make sure that everything is done. */
+       if (to_clean->irq_cleanup)
+               to_clean->irq_cleanup(to_clean);
        while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
                poll(to_clean);
                schedule_timeout_uninterruptible(1);