[IA64-SGI] cleanup XPC disengage related messages
[linux-2.6-block.git] / arch / ia64 / sn / kernel / xpc_main.c
index cece3c7c69be399d39031ab80fcbe697a8b97b38..948206b13f683754bc50b891b19830e3a8a3faf5 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/reboot.h>
 #include <asm/sn/intr.h>
 #include <asm/sn/sn_sal.h>
+#include <asm/kdebug.h>
 #include <asm/uaccess.h>
 #include "xpc.h"
 
@@ -161,6 +162,8 @@ static ctl_table xpc_sys_dir[] = {
 };
 static struct ctl_table_header *xpc_sysctl;
 
+/* non-zero if any remote partition disengage request was timed out */
+int xpc_disengage_request_timedout;
 
 /* #of IRQs received */
 static atomic_t xpc_act_IRQ_rcvd;
@@ -188,6 +191,11 @@ static struct notifier_block xpc_reboot_notifier = {
        .notifier_call = xpc_system_reboot,
 };
 
+static int xpc_system_die(struct notifier_block *, unsigned long, void *);
+static struct notifier_block xpc_die_notifier = {
+       .notifier_call = xpc_system_die,
+};
+
 
 /*
  * Timer function to enforce the timelimit on the partition disengage request.
@@ -767,7 +775,7 @@ xpc_daemonize_kthread(void *args)
                        ch->flags |= XPC_C_DISCONNECTCALLOUT;
                        spin_unlock_irqrestore(&ch->lock, irq_flags);
 
-                       xpc_disconnecting_callout(ch);
+                       xpc_disconnect_callout(ch, xpcDisconnecting);
                } else {
                        spin_unlock_irqrestore(&ch->lock, irq_flags);
                }
@@ -915,9 +923,9 @@ static void
 xpc_do_exit(enum xpc_retval reason)
 {
        partid_t partid;
-       int active_part_count;
+       int active_part_count, printed_waiting_msg = 0;
        struct xpc_partition *part;
-       unsigned long printmsg_time;
+       unsigned long printmsg_time, disengage_request_timeout = 0;
 
 
        /* a 'rmmod XPC' and a 'reboot' cannot both end up here together */
@@ -947,7 +955,8 @@ xpc_do_exit(enum xpc_retval reason)
 
        /* wait for all partitions to become inactive */
 
-       printmsg_time = jiffies;
+       printmsg_time = jiffies + (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ);
+       xpc_disengage_request_timedout = 0;
 
        do {
                active_part_count = 0;
@@ -963,20 +972,39 @@ xpc_do_exit(enum xpc_retval reason)
                        active_part_count++;
 
                        XPC_DEACTIVATE_PARTITION(part, reason);
-               }
 
-               if (active_part_count == 0) {
-                       break;
+                       if (part->disengage_request_timeout >
+                                               disengage_request_timeout) {
+                               disengage_request_timeout =
+                                               part->disengage_request_timeout;
+                       }
                }
 
-               if (jiffies >= printmsg_time) {
-                       dev_info(xpc_part, "waiting for partitions to "
-                               "deactivate/disengage, active count=%d, remote "
-                               "engaged=0x%lx\n", active_part_count,
-                               xpc_partition_engaged(1UL << partid));
-
-                       printmsg_time = jiffies +
+               if (xpc_partition_engaged(-1UL)) {
+                       if (time_after(jiffies, printmsg_time)) {
+                               dev_info(xpc_part, "waiting for remote "
+                                       "partitions to disengage, timeout in "
+                                       "%ld seconds\n",
+                                       (disengage_request_timeout - jiffies)
+                                                                       / HZ);
+                               printmsg_time = jiffies +
                                        (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ);
+                               printed_waiting_msg = 1;
+                       }
+
+               } else if (active_part_count > 0) {
+                       if (printed_waiting_msg) {
+                               dev_info(xpc_part, "waiting for local partition"
+                                       " to disengage\n");
+                               printed_waiting_msg = 0;
+                       }
+
+               } else {
+                       if (!xpc_disengage_request_timedout) {
+                               dev_info(xpc_part, "all partitions have "
+                                       "disengaged\n");
+                       }
+                       break;
                }
 
                /* sleep for a 1/3 of a second or so */
@@ -997,6 +1025,9 @@ xpc_do_exit(enum xpc_retval reason)
        /* take ourselves off of the reboot_notifier_list */
        (void) unregister_reboot_notifier(&xpc_reboot_notifier);
 
+       /* take ourselves off of the die_notifier list */
+       (void) unregister_die_notifier(&xpc_die_notifier);
+
        /* close down protections for IPI operations */
        xpc_restrict_IPI_ops();
 
@@ -1010,6 +1041,82 @@ xpc_do_exit(enum xpc_retval reason)
 }
 
 
+/*
+ * Called when the system is about to be either restarted or halted.
+ */
+static void
+xpc_die_disengage(void)
+{
+       struct xpc_partition *part;
+       partid_t partid;
+       unsigned long engaged;
+       long time, printmsg_time, disengage_request_timeout;
+
+
+       /* keep xpc_hb_checker thread from doing anything (just in case) */
+       xpc_exiting = 1;
+
+       xpc_vars->heartbeating_to_mask = 0;  /* indicate we're deactivated */
+
+       for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+               part = &xpc_partitions[partid];
+
+               if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part->
+                                                       remote_vars_version)) {
+
+                       /* just in case it was left set by an earlier XPC */
+                       xpc_clear_partition_engaged(1UL << partid);
+                       continue;
+               }
+
+               if (xpc_partition_engaged(1UL << partid) ||
+                                       part->act_state != XPC_P_INACTIVE) {
+                       xpc_request_partition_disengage(part);
+                       xpc_mark_partition_disengaged(part);
+                       xpc_IPI_send_disengage(part);
+               }
+       }
+
+       time = rtc_time();
+       printmsg_time = time +
+               (XPC_DISENGAGE_PRINTMSG_INTERVAL * sn_rtc_cycles_per_second);
+       disengage_request_timeout = time +
+               (xpc_disengage_request_timelimit * sn_rtc_cycles_per_second);
+
+       /* wait for all other partitions to disengage from us */
+
+       while (1) {
+               engaged = xpc_partition_engaged(-1UL);
+               if (!engaged) {
+                       dev_info(xpc_part, "all partitions have disengaged\n");
+                       break;
+               }
+
+               time = rtc_time();
+               if (time >= disengage_request_timeout) {
+                       for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+                               if (engaged & (1UL << partid)) {
+                                       dev_info(xpc_part, "disengage from "
+                                               "remote partition %d timed "
+                                               "out\n", partid);
+                               }
+                       }
+                       break;
+               }
+
+               if (time >= printmsg_time) {
+                       dev_info(xpc_part, "waiting for remote partitions to "
+                               "disengage, timeout in %ld seconds\n",
+                               (disengage_request_timeout - time) /
+                                               sn_rtc_cycles_per_second);
+                       printmsg_time = time +
+                                       (XPC_DISENGAGE_PRINTMSG_INTERVAL *
+                                               sn_rtc_cycles_per_second);
+               }
+       }
+}
+
+
 /*
  * This function is called when the system is being rebooted.
  */
@@ -1038,6 +1145,33 @@ xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused)
 }
 
 
+/*
+ * This function is called when the system is being rebooted.
+ */
+static int
+xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
+{
+       switch (event) {
+       case DIE_MACHINE_RESTART:
+       case DIE_MACHINE_HALT:
+               xpc_die_disengage();
+               break;
+       case DIE_MCA_MONARCH_ENTER:
+       case DIE_INIT_MONARCH_ENTER:
+               xpc_vars->heartbeat++;
+               xpc_vars->heartbeat_offline = 1;
+               break;
+       case DIE_MCA_MONARCH_LEAVE:
+       case DIE_INIT_MONARCH_LEAVE:
+               xpc_vars->heartbeat++;
+               xpc_vars->heartbeat_offline = 0;
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+
 int __init
 xpc_init(void)
 {
@@ -1154,6 +1288,12 @@ xpc_init(void)
                dev_warn(xpc_part, "can't register reboot notifier\n");
        }
 
+       /* add ourselves to the die_notifier list (i.e., ia64die_chain) */
+       ret = register_die_notifier(&xpc_die_notifier);
+       if (ret != 0) {
+               dev_warn(xpc_part, "can't register die notifier\n");
+       }
+
 
        /*
         * Set the beating to other partitions into motion.  This is
@@ -1179,6 +1319,9 @@ xpc_init(void)
                /* take ourselves off of the reboot_notifier_list */
                (void) unregister_reboot_notifier(&xpc_reboot_notifier);
 
+               /* take ourselves off of the die_notifier list */
+               (void) unregister_die_notifier(&xpc_die_notifier);
+
                del_timer_sync(&xpc_hb_timer);
                free_irq(SGI_XPC_ACTIVATE, NULL);
                xpc_restrict_IPI_ops();