diff options
Diffstat (limited to 'arch/s390/kernel/ipl.c')
-rw-r--r-- | arch/s390/kernel/ipl.c | 74 |
1 files changed, 61 insertions, 13 deletions
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 2dcf590faba6..6f3711a0eaaa 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -23,7 +23,7 @@ | |||
23 | #include <asm/ebcdic.h> | 23 | #include <asm/ebcdic.h> |
24 | #include <asm/reset.h> | 24 | #include <asm/reset.h> |
25 | #include <asm/sclp.h> | 25 | #include <asm/sclp.h> |
26 | #include <asm/setup.h> | 26 | #include <asm/checksum.h> |
27 | 27 | ||
28 | #define IPL_PARM_BLOCK_VERSION 0 | 28 | #define IPL_PARM_BLOCK_VERSION 0 |
29 | 29 | ||
@@ -56,13 +56,14 @@ struct shutdown_trigger { | |||
56 | }; | 56 | }; |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * Five shutdown action types are supported: | 59 | * The following shutdown action types are supported: |
60 | */ | 60 | */ |
61 | #define SHUTDOWN_ACTION_IPL_STR "ipl" | 61 | #define SHUTDOWN_ACTION_IPL_STR "ipl" |
62 | #define SHUTDOWN_ACTION_REIPL_STR "reipl" | 62 | #define SHUTDOWN_ACTION_REIPL_STR "reipl" |
63 | #define SHUTDOWN_ACTION_DUMP_STR "dump" | 63 | #define SHUTDOWN_ACTION_DUMP_STR "dump" |
64 | #define SHUTDOWN_ACTION_VMCMD_STR "vmcmd" | 64 | #define SHUTDOWN_ACTION_VMCMD_STR "vmcmd" |
65 | #define SHUTDOWN_ACTION_STOP_STR "stop" | 65 | #define SHUTDOWN_ACTION_STOP_STR "stop" |
66 | #define SHUTDOWN_ACTION_DUMP_REIPL_STR "dump_reipl" | ||
66 | 67 | ||
67 | struct shutdown_action { | 68 | struct shutdown_action { |
68 | char *name; | 69 | char *name; |
@@ -146,6 +147,7 @@ static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT; | |||
146 | static struct ipl_parameter_block *reipl_block_fcp; | 147 | static struct ipl_parameter_block *reipl_block_fcp; |
147 | static struct ipl_parameter_block *reipl_block_ccw; | 148 | static struct ipl_parameter_block *reipl_block_ccw; |
148 | static struct ipl_parameter_block *reipl_block_nss; | 149 | static struct ipl_parameter_block *reipl_block_nss; |
150 | static struct ipl_parameter_block *reipl_block_actual; | ||
149 | 151 | ||
150 | static int dump_capabilities = DUMP_TYPE_NONE; | 152 | static int dump_capabilities = DUMP_TYPE_NONE; |
151 | static enum dump_type dump_type = DUMP_TYPE_NONE; | 153 | static enum dump_type dump_type = DUMP_TYPE_NONE; |
@@ -835,6 +837,7 @@ static int reipl_set_type(enum ipl_type type) | |||
835 | reipl_method = REIPL_METHOD_CCW_VM; | 837 | reipl_method = REIPL_METHOD_CCW_VM; |
836 | else | 838 | else |
837 | reipl_method = REIPL_METHOD_CCW_CIO; | 839 | reipl_method = REIPL_METHOD_CCW_CIO; |
840 | reipl_block_actual = reipl_block_ccw; | ||
838 | break; | 841 | break; |
839 | case IPL_TYPE_FCP: | 842 | case IPL_TYPE_FCP: |
840 | if (diag308_set_works) | 843 | if (diag308_set_works) |
@@ -843,6 +846,7 @@ static int reipl_set_type(enum ipl_type type) | |||
843 | reipl_method = REIPL_METHOD_FCP_RO_VM; | 846 | reipl_method = REIPL_METHOD_FCP_RO_VM; |
844 | else | 847 | else |
845 | reipl_method = REIPL_METHOD_FCP_RO_DIAG; | 848 | reipl_method = REIPL_METHOD_FCP_RO_DIAG; |
849 | reipl_block_actual = reipl_block_fcp; | ||
846 | break; | 850 | break; |
847 | case IPL_TYPE_FCP_DUMP: | 851 | case IPL_TYPE_FCP_DUMP: |
848 | reipl_method = REIPL_METHOD_FCP_DUMP; | 852 | reipl_method = REIPL_METHOD_FCP_DUMP; |
@@ -852,6 +856,7 @@ static int reipl_set_type(enum ipl_type type) | |||
852 | reipl_method = REIPL_METHOD_NSS_DIAG; | 856 | reipl_method = REIPL_METHOD_NSS_DIAG; |
853 | else | 857 | else |
854 | reipl_method = REIPL_METHOD_NSS; | 858 | reipl_method = REIPL_METHOD_NSS; |
859 | reipl_block_actual = reipl_block_nss; | ||
855 | break; | 860 | break; |
856 | case IPL_TYPE_UNKNOWN: | 861 | case IPL_TYPE_UNKNOWN: |
857 | reipl_method = REIPL_METHOD_DEFAULT; | 862 | reipl_method = REIPL_METHOD_DEFAULT; |
@@ -960,7 +965,6 @@ static void reipl_run(struct shutdown_trigger *trigger) | |||
960 | diag308(DIAG308_IPL, NULL); | 965 | diag308(DIAG308_IPL, NULL); |
961 | break; | 966 | break; |
962 | case REIPL_METHOD_FCP_DUMP: | 967 | case REIPL_METHOD_FCP_DUMP: |
963 | default: | ||
964 | break; | 968 | break; |
965 | } | 969 | } |
966 | disabled_wait((unsigned long) __builtin_return_address(0)); | 970 | disabled_wait((unsigned long) __builtin_return_address(0)); |
@@ -1069,10 +1073,12 @@ static int __init reipl_fcp_init(void) | |||
1069 | { | 1073 | { |
1070 | int rc; | 1074 | int rc; |
1071 | 1075 | ||
1072 | if ((!diag308_set_works) && (ipl_info.type != IPL_TYPE_FCP)) | 1076 | if (!diag308_set_works) { |
1073 | return 0; | 1077 | if (ipl_info.type == IPL_TYPE_FCP) |
1074 | if ((!diag308_set_works) && (ipl_info.type == IPL_TYPE_FCP)) | 1078 | make_attrs_ro(reipl_fcp_attrs); |
1075 | make_attrs_ro(reipl_fcp_attrs); | 1079 | else |
1080 | return 0; | ||
1081 | } | ||
1076 | 1082 | ||
1077 | reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); | 1083 | reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); |
1078 | if (!reipl_block_fcp) | 1084 | if (!reipl_block_fcp) |
@@ -1253,7 +1259,6 @@ static void dump_run(struct shutdown_trigger *trigger) | |||
1253 | diag308(DIAG308_DUMP, NULL); | 1259 | diag308(DIAG308_DUMP, NULL); |
1254 | break; | 1260 | break; |
1255 | case DUMP_METHOD_NONE: | 1261 | case DUMP_METHOD_NONE: |
1256 | default: | ||
1257 | return; | 1262 | return; |
1258 | } | 1263 | } |
1259 | printk(KERN_EMERG "Dump failed!\n"); | 1264 | printk(KERN_EMERG "Dump failed!\n"); |
@@ -1332,6 +1337,49 @@ static struct shutdown_action __refdata dump_action = { | |||
1332 | .init = dump_init, | 1337 | .init = dump_init, |
1333 | }; | 1338 | }; |
1334 | 1339 | ||
1340 | static void dump_reipl_run(struct shutdown_trigger *trigger) | ||
1341 | { | ||
1342 | preempt_disable(); | ||
1343 | /* | ||
1344 | * Bypass dynamic address translation (DAT) when storing IPL parameter | ||
1345 | * information block address and checksum into the prefix area | ||
1346 | * (corresponding to absolute addresses 0-8191). | ||
1347 | * When enhanced DAT applies and the STE format control in one, | ||
1348 | * the absolute address is formed without prefixing. In this case a | ||
1349 | * normal store (stg/st) into the prefix area would no more match to | ||
1350 | * absolute addresses 0-8191. | ||
1351 | */ | ||
1352 | #ifdef CONFIG_64BIT | ||
1353 | asm volatile("sturg %0,%1" | ||
1354 | :: "a" ((unsigned long) reipl_block_actual), | ||
1355 | "a" (&lowcore_ptr[smp_processor_id()]->ipib)); | ||
1356 | #else | ||
1357 | asm volatile("stura %0,%1" | ||
1358 | :: "a" ((unsigned long) reipl_block_actual), | ||
1359 | "a" (&lowcore_ptr[smp_processor_id()]->ipib)); | ||
1360 | #endif | ||
1361 | asm volatile("stura %0,%1" | ||
1362 | :: "a" (csum_partial(reipl_block_actual, | ||
1363 | reipl_block_actual->hdr.len, 0)), | ||
1364 | "a" (&lowcore_ptr[smp_processor_id()]->ipib_checksum)); | ||
1365 | preempt_enable(); | ||
1366 | dump_run(trigger); | ||
1367 | } | ||
1368 | |||
1369 | static int __init dump_reipl_init(void) | ||
1370 | { | ||
1371 | if (!diag308_set_works) | ||
1372 | return -EOPNOTSUPP; | ||
1373 | else | ||
1374 | return 0; | ||
1375 | } | ||
1376 | |||
1377 | static struct shutdown_action __refdata dump_reipl_action = { | ||
1378 | .name = SHUTDOWN_ACTION_DUMP_REIPL_STR, | ||
1379 | .fn = dump_reipl_run, | ||
1380 | .init = dump_reipl_init, | ||
1381 | }; | ||
1382 | |||
1335 | /* | 1383 | /* |
1336 | * vmcmd shutdown action: Trigger vm command on shutdown. | 1384 | * vmcmd shutdown action: Trigger vm command on shutdown. |
1337 | */ | 1385 | */ |
@@ -1421,7 +1469,8 @@ static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR, | |||
1421 | /* action list */ | 1469 | /* action list */ |
1422 | 1470 | ||
1423 | static struct shutdown_action *shutdown_actions_list[] = { | 1471 | static struct shutdown_action *shutdown_actions_list[] = { |
1424 | &ipl_action, &reipl_action, &dump_action, &vmcmd_action, &stop_action}; | 1472 | &ipl_action, &reipl_action, &dump_reipl_action, &dump_action, |
1473 | &vmcmd_action, &stop_action}; | ||
1425 | #define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *)) | 1474 | #define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *)) |
1426 | 1475 | ||
1427 | /* | 1476 | /* |
@@ -1434,11 +1483,11 @@ static int set_trigger(const char *buf, struct shutdown_trigger *trigger, | |||
1434 | size_t len) | 1483 | size_t len) |
1435 | { | 1484 | { |
1436 | int i; | 1485 | int i; |
1486 | |||
1437 | for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) { | 1487 | for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) { |
1438 | if (!shutdown_actions_list[i]) | 1488 | if (!shutdown_actions_list[i]) |
1439 | continue; | 1489 | continue; |
1440 | if (strncmp(buf, shutdown_actions_list[i]->name, | 1490 | if (sysfs_streq(buf, shutdown_actions_list[i]->name)) { |
1441 | strlen(shutdown_actions_list[i]->name)) == 0) { | ||
1442 | trigger->action = shutdown_actions_list[i]; | 1491 | trigger->action = shutdown_actions_list[i]; |
1443 | return len; | 1492 | return len; |
1444 | } | 1493 | } |
@@ -1672,7 +1721,7 @@ static int on_panic_notify(struct notifier_block *self, | |||
1672 | 1721 | ||
1673 | static struct notifier_block on_panic_nb = { | 1722 | static struct notifier_block on_panic_nb = { |
1674 | .notifier_call = on_panic_notify, | 1723 | .notifier_call = on_panic_notify, |
1675 | .priority = 0, | 1724 | .priority = INT_MIN, |
1676 | }; | 1725 | }; |
1677 | 1726 | ||
1678 | void __init setup_ipl(void) | 1727 | void __init setup_ipl(void) |
@@ -1696,7 +1745,6 @@ void __init setup_ipl(void) | |||
1696 | sizeof(ipl_info.data.nss.name)); | 1745 | sizeof(ipl_info.data.nss.name)); |
1697 | break; | 1746 | break; |
1698 | case IPL_TYPE_UNKNOWN: | 1747 | case IPL_TYPE_UNKNOWN: |
1699 | default: | ||
1700 | /* We have no info to copy */ | 1748 | /* We have no info to copy */ |
1701 | break; | 1749 | break; |
1702 | } | 1750 | } |