aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/ipl.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/ipl.c')
-rw-r--r--arch/s390/kernel/ipl.c139
1 files changed, 105 insertions, 34 deletions
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 9e9972e8a52b..5a863a3bf10c 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -14,32 +14,41 @@
14#include <linux/delay.h> 14#include <linux/delay.h>
15#include <linux/reboot.h> 15#include <linux/reboot.h>
16#include <linux/ctype.h> 16#include <linux/ctype.h>
17#include <asm/ipl.h>
17#include <asm/smp.h> 18#include <asm/smp.h>
18#include <asm/setup.h> 19#include <asm/setup.h>
19#include <asm/cpcmd.h> 20#include <asm/cpcmd.h>
20#include <asm/cio.h> 21#include <asm/cio.h>
21#include <asm/ebcdic.h> 22#include <asm/ebcdic.h>
22#include <asm/reset.h> 23#include <asm/reset.h>
24#include <asm/sclp.h>
23 25
24#define IPL_PARM_BLOCK_VERSION 0 26#define IPL_PARM_BLOCK_VERSION 0
25#define LOADPARM_LEN 8
26 27
27extern char s390_readinfo_sccb[]; 28#define SCCB_VALID (s390_readinfo_sccb.header.response_code == 0x10)
28#define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010) 29#define SCCB_LOADPARM (&s390_readinfo_sccb.loadparm)
29#define SCCB_LOADPARM (&s390_readinfo_sccb[24]) 30#define SCCB_FLAG (s390_readinfo_sccb.flags)
30#define SCCB_FLAG (s390_readinfo_sccb[91])
31 31
32enum ipl_type { 32enum ipl_type {
33 IPL_TYPE_NONE = 1, 33 IPL_TYPE_NONE = 1,
34 IPL_TYPE_UNKNOWN = 2, 34 IPL_TYPE_UNKNOWN = 2,
35 IPL_TYPE_CCW = 4, 35 IPL_TYPE_CCW = 4,
36 IPL_TYPE_FCP = 8, 36 IPL_TYPE_FCP = 8,
37 IPL_TYPE_NSS = 16,
37}; 38};
38 39
39#define IPL_NONE_STR "none" 40#define IPL_NONE_STR "none"
40#define IPL_UNKNOWN_STR "unknown" 41#define IPL_UNKNOWN_STR "unknown"
41#define IPL_CCW_STR "ccw" 42#define IPL_CCW_STR "ccw"
42#define IPL_FCP_STR "fcp" 43#define IPL_FCP_STR "fcp"
44#define IPL_NSS_STR "nss"
45
46/*
47 * Must be in data section since the bss section
48 * is not cleared when these are accessed.
49 */
50u16 ipl_devno __attribute__((__section__(".data"))) = 0;
51u32 ipl_flags __attribute__((__section__(".data"))) = 0;
43 52
44static char *ipl_type_str(enum ipl_type type) 53static char *ipl_type_str(enum ipl_type type)
45{ 54{
@@ -50,6 +59,8 @@ static char *ipl_type_str(enum ipl_type type)
50 return IPL_CCW_STR; 59 return IPL_CCW_STR;
51 case IPL_TYPE_FCP: 60 case IPL_TYPE_FCP:
52 return IPL_FCP_STR; 61 return IPL_FCP_STR;
62 case IPL_TYPE_NSS:
63 return IPL_NSS_STR;
53 case IPL_TYPE_UNKNOWN: 64 case IPL_TYPE_UNKNOWN:
54 default: 65 default:
55 return IPL_UNKNOWN_STR; 66 return IPL_UNKNOWN_STR;
@@ -64,6 +75,7 @@ enum ipl_method {
64 IPL_METHOD_FCP_RO_DIAG, 75 IPL_METHOD_FCP_RO_DIAG,
65 IPL_METHOD_FCP_RW_DIAG, 76 IPL_METHOD_FCP_RW_DIAG,
66 IPL_METHOD_FCP_RO_VM, 77 IPL_METHOD_FCP_RO_VM,
78 IPL_METHOD_NSS,
67}; 79};
68 80
69enum shutdown_action { 81enum shutdown_action {
@@ -86,39 +98,21 @@ static char *shutdown_action_str(enum shutdown_action action)
86 case SHUTDOWN_STOP: 98 case SHUTDOWN_STOP:
87 return SHUTDOWN_STOP_STR; 99 return SHUTDOWN_STOP_STR;
88 default: 100 default:
89 BUG(); 101 return NULL;
90 } 102 }
91} 103}
92 104
93enum diag308_subcode {
94 DIAG308_IPL = 3,
95 DIAG308_DUMP = 4,
96 DIAG308_SET = 5,
97 DIAG308_STORE = 6,
98};
99
100enum diag308_ipl_type {
101 DIAG308_IPL_TYPE_FCP = 0,
102 DIAG308_IPL_TYPE_CCW = 2,
103};
104
105enum diag308_opt {
106 DIAG308_IPL_OPT_IPL = 0x10,
107 DIAG308_IPL_OPT_DUMP = 0x20,
108};
109
110enum diag308_rc {
111 DIAG308_RC_OK = 1,
112};
113
114static int diag308_set_works = 0; 105static int diag308_set_works = 0;
115 106
116static int reipl_capabilities = IPL_TYPE_UNKNOWN; 107static int reipl_capabilities = IPL_TYPE_UNKNOWN;
108
117static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN; 109static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
118static enum ipl_method reipl_method = IPL_METHOD_NONE; 110static enum ipl_method reipl_method = IPL_METHOD_NONE;
119static struct ipl_parameter_block *reipl_block_fcp; 111static struct ipl_parameter_block *reipl_block_fcp;
120static struct ipl_parameter_block *reipl_block_ccw; 112static struct ipl_parameter_block *reipl_block_ccw;
121 113
114static char reipl_nss_name[NSS_NAME_SIZE + 1];
115
122static int dump_capabilities = IPL_TYPE_NONE; 116static int dump_capabilities = IPL_TYPE_NONE;
123static enum ipl_type dump_type = IPL_TYPE_NONE; 117static enum ipl_type dump_type = IPL_TYPE_NONE;
124static enum ipl_method dump_method = IPL_METHOD_NONE; 118static enum ipl_method dump_method = IPL_METHOD_NONE;
@@ -127,7 +121,7 @@ static struct ipl_parameter_block *dump_block_ccw;
127 121
128static enum shutdown_action on_panic_action = SHUTDOWN_STOP; 122static enum shutdown_action on_panic_action = SHUTDOWN_STOP;
129 123
130static int diag308(unsigned long subcode, void *addr) 124int diag308(unsigned long subcode, void *addr)
131{ 125{
132 register unsigned long _addr asm("0") = (unsigned long) addr; 126 register unsigned long _addr asm("0") = (unsigned long) addr;
133 register unsigned long _rc asm("1") = 0; 127 register unsigned long _rc asm("1") = 0;
@@ -173,6 +167,24 @@ static struct subsys_attribute sys_##_prefix##_##_name##_attr = \
173 sys_##_prefix##_##_name##_show, \ 167 sys_##_prefix##_##_name##_show, \
174 sys_##_prefix##_##_name##_store); 168 sys_##_prefix##_##_name##_store);
175 169
170#define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
171static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
172 char *page) \
173{ \
174 return sprintf(page, _fmt_out, _value); \
175} \
176static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
177 const char *buf, size_t len) \
178{ \
179 if (sscanf(buf, _fmt_in, _value) != 1) \
180 return -EINVAL; \
181 return len; \
182} \
183static struct subsys_attribute sys_##_prefix##_##_name##_attr = \
184 __ATTR(_name,(S_IRUGO | S_IWUSR), \
185 sys_##_prefix##_##_name##_show, \
186 sys_##_prefix##_##_name##_store);
187
176static void make_attrs_ro(struct attribute **attrs) 188static void make_attrs_ro(struct attribute **attrs)
177{ 189{
178 while (*attrs) { 190 while (*attrs) {
@@ -189,6 +201,8 @@ static enum ipl_type ipl_get_type(void)
189{ 201{
190 struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START; 202 struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
191 203
204 if (ipl_flags & IPL_NSS_VALID)
205 return IPL_TYPE_NSS;
192 if (!(ipl_flags & IPL_DEVNO_VALID)) 206 if (!(ipl_flags & IPL_DEVNO_VALID))
193 return IPL_TYPE_UNKNOWN; 207 return IPL_TYPE_UNKNOWN;
194 if (!(ipl_flags & IPL_PARMBLOCK_VALID)) 208 if (!(ipl_flags & IPL_PARMBLOCK_VALID))
@@ -324,6 +338,20 @@ static struct attribute_group ipl_ccw_attr_group = {
324 .attrs = ipl_ccw_attrs, 338 .attrs = ipl_ccw_attrs,
325}; 339};
326 340
341/* NSS ipl device attributes */
342
343DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
344
345static struct attribute *ipl_nss_attrs[] = {
346 &sys_ipl_type_attr.attr,
347 &sys_ipl_nss_name_attr.attr,
348 NULL,
349};
350
351static struct attribute_group ipl_nss_attr_group = {
352 .attrs = ipl_nss_attrs,
353};
354
327/* UNKNOWN ipl device attributes */ 355/* UNKNOWN ipl device attributes */
328 356
329static struct attribute *ipl_unknown_attrs[] = { 357static struct attribute *ipl_unknown_attrs[] = {
@@ -432,6 +460,21 @@ static struct attribute_group reipl_ccw_attr_group = {
432 .attrs = reipl_ccw_attrs, 460 .attrs = reipl_ccw_attrs,
433}; 461};
434 462
463
464/* NSS reipl device attributes */
465
466DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name);
467
468static struct attribute *reipl_nss_attrs[] = {
469 &sys_reipl_nss_name_attr.attr,
470 NULL,
471};
472
473static struct attribute_group reipl_nss_attr_group = {
474 .name = IPL_NSS_STR,
475 .attrs = reipl_nss_attrs,
476};
477
435/* reipl type */ 478/* reipl type */
436 479
437static int reipl_set_type(enum ipl_type type) 480static int reipl_set_type(enum ipl_type type)
@@ -454,6 +497,9 @@ static int reipl_set_type(enum ipl_type type)
454 else 497 else
455 reipl_method = IPL_METHOD_FCP_RO_DIAG; 498 reipl_method = IPL_METHOD_FCP_RO_DIAG;
456 break; 499 break;
500 case IPL_TYPE_NSS:
501 reipl_method = IPL_METHOD_NSS;
502 break;
457 default: 503 default:
458 reipl_method = IPL_METHOD_NONE; 504 reipl_method = IPL_METHOD_NONE;
459 } 505 }
@@ -475,6 +521,8 @@ static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf,
475 rc = reipl_set_type(IPL_TYPE_CCW); 521 rc = reipl_set_type(IPL_TYPE_CCW);
476 else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0) 522 else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
477 rc = reipl_set_type(IPL_TYPE_FCP); 523 rc = reipl_set_type(IPL_TYPE_FCP);
524 else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0)
525 rc = reipl_set_type(IPL_TYPE_NSS);
478 return (rc != 0) ? rc : len; 526 return (rc != 0) ? rc : len;
479} 527}
480 528
@@ -647,6 +695,10 @@ void do_reipl(void)
647 case IPL_METHOD_FCP_RO_VM: 695 case IPL_METHOD_FCP_RO_VM:
648 __cpcmd("IPL", NULL, 0, NULL); 696 __cpcmd("IPL", NULL, 0, NULL);
649 break; 697 break;
698 case IPL_METHOD_NSS:
699 sprintf(buf, "IPL %s", reipl_nss_name);
700 __cpcmd(buf, NULL, 0, NULL);
701 break;
650 case IPL_METHOD_NONE: 702 case IPL_METHOD_NONE:
651 default: 703 default:
652 if (MACHINE_IS_VM) 704 if (MACHINE_IS_VM)
@@ -733,6 +785,10 @@ static int __init ipl_init(void)
733 case IPL_TYPE_FCP: 785 case IPL_TYPE_FCP:
734 rc = ipl_register_fcp_files(); 786 rc = ipl_register_fcp_files();
735 break; 787 break;
788 case IPL_TYPE_NSS:
789 rc = sysfs_create_group(&ipl_subsys.kset.kobj,
790 &ipl_nss_attr_group);
791 break;
736 default: 792 default:
737 rc = sysfs_create_group(&ipl_subsys.kset.kobj, 793 rc = sysfs_create_group(&ipl_subsys.kset.kobj,
738 &ipl_unknown_attr_group); 794 &ipl_unknown_attr_group);
@@ -755,6 +811,20 @@ static void __init reipl_probe(void)
755 free_page((unsigned long)buffer); 811 free_page((unsigned long)buffer);
756} 812}
757 813
814static int __init reipl_nss_init(void)
815{
816 int rc;
817
818 if (!MACHINE_IS_VM)
819 return 0;
820 rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_nss_attr_group);
821 if (rc)
822 return rc;
823 strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
824 reipl_capabilities |= IPL_TYPE_NSS;
825 return 0;
826}
827
758static int __init reipl_ccw_init(void) 828static int __init reipl_ccw_init(void)
759{ 829{
760 int rc; 830 int rc;
@@ -837,6 +907,9 @@ static int __init reipl_init(void)
837 rc = reipl_fcp_init(); 907 rc = reipl_fcp_init();
838 if (rc) 908 if (rc)
839 return rc; 909 return rc;
910 rc = reipl_nss_init();
911 if (rc)
912 return rc;
840 rc = reipl_set_type(ipl_get_type()); 913 rc = reipl_set_type(ipl_get_type());
841 if (rc) 914 if (rc)
842 return rc; 915 return rc;
@@ -993,8 +1066,6 @@ static void do_reset_calls(void)
993 reset->fn(); 1066 reset->fn();
994} 1067}
995 1068
996extern void reset_mcck_handler(void);
997extern void reset_pgm_handler(void);
998extern __u32 dump_prefix_page; 1069extern __u32 dump_prefix_page;
999 1070
1000void s390_reset_system(void) 1071void s390_reset_system(void)
@@ -1016,14 +1087,14 @@ void s390_reset_system(void)
1016 __ctl_clear_bit(0,28); 1087 __ctl_clear_bit(0,28);
1017 1088
1018 /* Set new machine check handler */ 1089 /* Set new machine check handler */
1019 S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK; 1090 S390_lowcore.mcck_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
1020 S390_lowcore.mcck_new_psw.addr = 1091 S390_lowcore.mcck_new_psw.addr =
1021 PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler; 1092 PSW_ADDR_AMODE | (unsigned long) s390_base_mcck_handler;
1022 1093
1023 /* Set new program check handler */ 1094 /* Set new program check handler */
1024 S390_lowcore.program_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK; 1095 S390_lowcore.program_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
1025 S390_lowcore.program_new_psw.addr = 1096 S390_lowcore.program_new_psw.addr =
1026 PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler; 1097 PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
1027 1098
1028 do_reset_calls(); 1099 do_reset_calls();
1029} 1100}