#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"
};
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;
.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.
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);
}
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 */
/* 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;
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 */
/* 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();
}
+/*
+ * 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.
*/
}
+/*
+ * 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)
{
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
/* 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();