|
@@ -56,13 +56,14 @@ struct shutdown_trigger {
|
|
|
};
|
|
|
|
|
|
/*
|
|
|
- * Five shutdown action types are supported:
|
|
|
+ * The following shutdown action types are supported:
|
|
|
*/
|
|
|
#define SHUTDOWN_ACTION_IPL_STR "ipl"
|
|
|
#define SHUTDOWN_ACTION_REIPL_STR "reipl"
|
|
|
#define SHUTDOWN_ACTION_DUMP_STR "dump"
|
|
|
#define SHUTDOWN_ACTION_VMCMD_STR "vmcmd"
|
|
|
#define SHUTDOWN_ACTION_STOP_STR "stop"
|
|
|
+#define SHUTDOWN_ACTION_DUMP_REIPL_STR "dump_reipl"
|
|
|
|
|
|
struct shutdown_action {
|
|
|
char *name;
|
|
@@ -146,6 +147,7 @@ static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT;
|
|
|
static struct ipl_parameter_block *reipl_block_fcp;
|
|
|
static struct ipl_parameter_block *reipl_block_ccw;
|
|
|
static struct ipl_parameter_block *reipl_block_nss;
|
|
|
+static struct ipl_parameter_block *reipl_block_actual;
|
|
|
|
|
|
static int dump_capabilities = DUMP_TYPE_NONE;
|
|
|
static enum dump_type dump_type = DUMP_TYPE_NONE;
|
|
@@ -835,6 +837,7 @@ static int reipl_set_type(enum ipl_type type)
|
|
|
reipl_method = REIPL_METHOD_CCW_VM;
|
|
|
else
|
|
|
reipl_method = REIPL_METHOD_CCW_CIO;
|
|
|
+ reipl_block_actual = reipl_block_ccw;
|
|
|
break;
|
|
|
case IPL_TYPE_FCP:
|
|
|
if (diag308_set_works)
|
|
@@ -843,6 +846,7 @@ static int reipl_set_type(enum ipl_type type)
|
|
|
reipl_method = REIPL_METHOD_FCP_RO_VM;
|
|
|
else
|
|
|
reipl_method = REIPL_METHOD_FCP_RO_DIAG;
|
|
|
+ reipl_block_actual = reipl_block_fcp;
|
|
|
break;
|
|
|
case IPL_TYPE_FCP_DUMP:
|
|
|
reipl_method = REIPL_METHOD_FCP_DUMP;
|
|
@@ -852,6 +856,7 @@ static int reipl_set_type(enum ipl_type type)
|
|
|
reipl_method = REIPL_METHOD_NSS_DIAG;
|
|
|
else
|
|
|
reipl_method = REIPL_METHOD_NSS;
|
|
|
+ reipl_block_actual = reipl_block_nss;
|
|
|
break;
|
|
|
case IPL_TYPE_UNKNOWN:
|
|
|
reipl_method = REIPL_METHOD_DEFAULT;
|
|
@@ -1332,6 +1337,48 @@ static struct shutdown_action __refdata dump_action = {
|
|
|
.init = dump_init,
|
|
|
};
|
|
|
|
|
|
+static void dump_reipl_run(struct shutdown_trigger *trigger)
|
|
|
+{
|
|
|
+ preempt_disable();
|
|
|
+ /*
|
|
|
+ * Bypass dynamic address translation (DAT) when storing IPL parameter
|
|
|
+ * information block address and checksum into the prefix area
|
|
|
+ * (corresponding to absolute addresses 0-8191).
|
|
|
+ * When enhanced DAT applies and the STE format control in one,
|
|
|
+ * the absolute address is formed without prefixing. In this case a
|
|
|
+ * normal store (stg/st) into the prefix area would no more match to
|
|
|
+ * absolute addresses 0-8191.
|
|
|
+ */
|
|
|
+#ifdef CONFIG_64BIT
|
|
|
+ asm volatile("sturg %0,%1"
|
|
|
+ :: "a" ((unsigned long) reipl_block_actual),
|
|
|
+ "a" (&lowcore_ptr[smp_processor_id()]->ipib));
|
|
|
+#else
|
|
|
+ asm volatile("stura %0,%1"
|
|
|
+ :: "a" ((unsigned long) reipl_block_actual),
|
|
|
+ "a" (&lowcore_ptr[smp_processor_id()]->ipib));
|
|
|
+#endif
|
|
|
+ asm volatile("stura %0,%1"
|
|
|
+ :: "a" (cksm(reipl_block_actual, reipl_block_actual->hdr.len)),
|
|
|
+ "a" (&lowcore_ptr[smp_processor_id()]->ipib_checksum));
|
|
|
+ preempt_enable();
|
|
|
+ dump_run(trigger);
|
|
|
+}
|
|
|
+
|
|
|
+static int __init dump_reipl_init(void)
|
|
|
+{
|
|
|
+ if (!diag308_set_works)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+ else
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct shutdown_action __refdata dump_reipl_action = {
|
|
|
+ .name = SHUTDOWN_ACTION_DUMP_REIPL_STR,
|
|
|
+ .fn = dump_reipl_run,
|
|
|
+ .init = dump_reipl_init,
|
|
|
+};
|
|
|
+
|
|
|
/*
|
|
|
* vmcmd shutdown action: Trigger vm command on shutdown.
|
|
|
*/
|
|
@@ -1421,7 +1468,8 @@ static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR,
|
|
|
/* action list */
|
|
|
|
|
|
static struct shutdown_action *shutdown_actions_list[] = {
|
|
|
- &ipl_action, &reipl_action, &dump_action, &vmcmd_action, &stop_action};
|
|
|
+ &ipl_action, &reipl_action, &dump_reipl_action, &dump_action,
|
|
|
+ &vmcmd_action, &stop_action};
|
|
|
#define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *))
|
|
|
|
|
|
/*
|
|
@@ -1434,11 +1482,11 @@ static int set_trigger(const char *buf, struct shutdown_trigger *trigger,
|
|
|
size_t len)
|
|
|
{
|
|
|
int i;
|
|
|
+
|
|
|
for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
|
|
|
if (!shutdown_actions_list[i])
|
|
|
continue;
|
|
|
- if (strncmp(buf, shutdown_actions_list[i]->name,
|
|
|
- strlen(shutdown_actions_list[i]->name)) == 0) {
|
|
|
+ if (sysfs_streq(buf, shutdown_actions_list[i]->name)) {
|
|
|
trigger->action = shutdown_actions_list[i];
|
|
|
return len;
|
|
|
}
|