1a17ae4c3SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2ff6b8ea6SMichael Holzheu /*
3ff6b8ea6SMichael Holzheu * ipl/reipl/dump support for Linux on s390.
4ff6b8ea6SMichael Holzheu *
58b646bd7SMartin Schwidefsky * Copyright IBM Corp. 2005, 2012
6ff6b8ea6SMichael Holzheu * Author(s): Michael Holzheu <holzheu@de.ibm.com>
7ff6b8ea6SMichael Holzheu * Volker Sameske <sameske@de.ibm.com>
8ff6b8ea6SMichael Holzheu */
9ff6b8ea6SMichael Holzheu
10ff6b8ea6SMichael Holzheu #include <linux/types.h>
113994a52bSPaul Gortmaker #include <linux/export.h>
123994a52bSPaul Gortmaker #include <linux/init.h>
13ff6b8ea6SMichael Holzheu #include <linux/device.h>
14ff6b8ea6SMichael Holzheu #include <linux/delay.h>
15d9b25bdfSChristophe JAILLET #include <linux/kstrtox.h>
16f39650deSAndy Shevchenko #include <linux/panic_notifier.h>
17ff6b8ea6SMichael Holzheu #include <linux/reboot.h>
1803a4d208SMichael Holzheu #include <linux/ctype.h>
190788fea4SAkinobu Mita #include <linux/fs.h>
205a0e3ad6STejun Heo #include <linux/gfp.h>
2160a0c68dSMichael Holzheu #include <linux/crash_dump.h>
223ab121abSMichael Holzheu #include <linux/debug_locks.h>
23d09a307fSHeiko Carstens #include <asm/asm-extable.h>
241ec2772eSMartin Schwidefsky #include <asm/diag.h>
2546b05d26SMichael Holzheu #include <asm/ipl.h>
26ff6b8ea6SMichael Holzheu #include <asm/smp.h>
27ff6b8ea6SMichael Holzheu #include <asm/setup.h>
28ff6b8ea6SMichael Holzheu #include <asm/cpcmd.h>
2903a4d208SMichael Holzheu #include <asm/ebcdic.h>
30ab14de6cSHeiko Carstens #include <asm/sclp.h>
31159d1ff8SFrank Munzert #include <asm/checksum.h>
323ab121abSMichael Holzheu #include <asm/debug.h>
334df29d2bSAlexander Gordeev #include <asm/abs_lowcore.h>
344857d4bbSMichael Holzheu #include <asm/os_info.h>
3549698745SVasily Gorbik #include <asm/sections.h>
3649698745SVasily Gorbik #include <asm/boot_data.h>
37638ad34aSMartin Schwidefsky #include "entry.h"
38ff6b8ea6SMichael Holzheu
39ff6b8ea6SMichael Holzheu #define IPL_PARM_BLOCK_VERSION 0
4003a4d208SMichael Holzheu
41ff6b8ea6SMichael Holzheu #define IPL_UNKNOWN_STR "unknown"
42ff6b8ea6SMichael Holzheu #define IPL_CCW_STR "ccw"
4387fd22e0SSven Schnelle #define IPL_ECKD_STR "eckd"
44e2d2a296SSven Schnelle #define IPL_ECKD_DUMP_STR "eckd_dump"
45ff6b8ea6SMichael Holzheu #define IPL_FCP_STR "fcp"
46411ed322SMichael Holzheu #define IPL_FCP_DUMP_STR "fcp_dump"
473737e8eeSJason J. Herne #define IPL_NVME_STR "nvme"
48d70e38cbSJason J. Herne #define IPL_NVME_DUMP_STR "nvme_dump"
49fe355b7fSHongjie Yang #define IPL_NSS_STR "nss"
50ff6b8ea6SMichael Holzheu
5199ca4e58SMichael Holzheu #define DUMP_CCW_STR "ccw"
52e2d2a296SSven Schnelle #define DUMP_ECKD_STR "eckd"
5399ca4e58SMichael Holzheu #define DUMP_FCP_STR "fcp"
54d70e38cbSJason J. Herne #define DUMP_NVME_STR "nvme"
5599ca4e58SMichael Holzheu #define DUMP_NONE_STR "none"
5699ca4e58SMichael Holzheu
5799ca4e58SMichael Holzheu /*
5899ca4e58SMichael Holzheu * Four shutdown trigger types are supported:
5999ca4e58SMichael Holzheu * - panic
6099ca4e58SMichael Holzheu * - halt
6199ca4e58SMichael Holzheu * - power off
6299ca4e58SMichael Holzheu * - reipl
637dd6b334SMichael Holzheu * - restart
6499ca4e58SMichael Holzheu */
6599ca4e58SMichael Holzheu #define ON_PANIC_STR "on_panic"
6699ca4e58SMichael Holzheu #define ON_HALT_STR "on_halt"
6799ca4e58SMichael Holzheu #define ON_POFF_STR "on_poff"
6899ca4e58SMichael Holzheu #define ON_REIPL_STR "on_reboot"
697dd6b334SMichael Holzheu #define ON_RESTART_STR "on_restart"
7099ca4e58SMichael Holzheu
7199ca4e58SMichael Holzheu struct shutdown_action;
7299ca4e58SMichael Holzheu struct shutdown_trigger {
7399ca4e58SMichael Holzheu char *name;
7499ca4e58SMichael Holzheu struct shutdown_action *action;
7599ca4e58SMichael Holzheu };
7699ca4e58SMichael Holzheu
7799ca4e58SMichael Holzheu /*
78099b7651SFrank Munzert * The following shutdown action types are supported:
7999ca4e58SMichael Holzheu */
8099ca4e58SMichael Holzheu #define SHUTDOWN_ACTION_IPL_STR "ipl"
8199ca4e58SMichael Holzheu #define SHUTDOWN_ACTION_REIPL_STR "reipl"
8299ca4e58SMichael Holzheu #define SHUTDOWN_ACTION_DUMP_STR "dump"
8399ca4e58SMichael Holzheu #define SHUTDOWN_ACTION_VMCMD_STR "vmcmd"
8499ca4e58SMichael Holzheu #define SHUTDOWN_ACTION_STOP_STR "stop"
85099b7651SFrank Munzert #define SHUTDOWN_ACTION_DUMP_REIPL_STR "dump_reipl"
8699ca4e58SMichael Holzheu
8799ca4e58SMichael Holzheu struct shutdown_action {
8899ca4e58SMichael Holzheu char *name;
8999ca4e58SMichael Holzheu void (*fn) (struct shutdown_trigger *trigger);
9099ca4e58SMichael Holzheu int (*init) (void);
9181088819SFrank Munzert int init_rc;
9299ca4e58SMichael Holzheu };
9399ca4e58SMichael Holzheu
ipl_type_str(enum ipl_type type)94ff6b8ea6SMichael Holzheu static char *ipl_type_str(enum ipl_type type)
95ff6b8ea6SMichael Holzheu {
96ff6b8ea6SMichael Holzheu switch (type) {
97ff6b8ea6SMichael Holzheu case IPL_TYPE_CCW:
98ff6b8ea6SMichael Holzheu return IPL_CCW_STR;
9987fd22e0SSven Schnelle case IPL_TYPE_ECKD:
10087fd22e0SSven Schnelle return IPL_ECKD_STR;
101e2d2a296SSven Schnelle case IPL_TYPE_ECKD_DUMP:
102e2d2a296SSven Schnelle return IPL_ECKD_DUMP_STR;
103ff6b8ea6SMichael Holzheu case IPL_TYPE_FCP:
104ff6b8ea6SMichael Holzheu return IPL_FCP_STR;
105411ed322SMichael Holzheu case IPL_TYPE_FCP_DUMP:
106411ed322SMichael Holzheu return IPL_FCP_DUMP_STR;
107fe355b7fSHongjie Yang case IPL_TYPE_NSS:
108fe355b7fSHongjie Yang return IPL_NSS_STR;
1093737e8eeSJason J. Herne case IPL_TYPE_NVME:
1103737e8eeSJason J. Herne return IPL_NVME_STR;
111d70e38cbSJason J. Herne case IPL_TYPE_NVME_DUMP:
112d70e38cbSJason J. Herne return IPL_NVME_DUMP_STR;
113ff6b8ea6SMichael Holzheu case IPL_TYPE_UNKNOWN:
114ff6b8ea6SMichael Holzheu default:
115ff6b8ea6SMichael Holzheu return IPL_UNKNOWN_STR;
116ff6b8ea6SMichael Holzheu }
117ff6b8ea6SMichael Holzheu }
118ff6b8ea6SMichael Holzheu
119411ed322SMichael Holzheu enum dump_type {
120411ed322SMichael Holzheu DUMP_TYPE_NONE = 1,
121411ed322SMichael Holzheu DUMP_TYPE_CCW = 2,
122411ed322SMichael Holzheu DUMP_TYPE_FCP = 4,
123d70e38cbSJason J. Herne DUMP_TYPE_NVME = 8,
124e2d2a296SSven Schnelle DUMP_TYPE_ECKD = 16,
125411ed322SMichael Holzheu };
126411ed322SMichael Holzheu
dump_type_str(enum dump_type type)127411ed322SMichael Holzheu static char *dump_type_str(enum dump_type type)
128411ed322SMichael Holzheu {
129411ed322SMichael Holzheu switch (type) {
130411ed322SMichael Holzheu case DUMP_TYPE_NONE:
131411ed322SMichael Holzheu return DUMP_NONE_STR;
132411ed322SMichael Holzheu case DUMP_TYPE_CCW:
133411ed322SMichael Holzheu return DUMP_CCW_STR;
134e2d2a296SSven Schnelle case DUMP_TYPE_ECKD:
135e2d2a296SSven Schnelle return DUMP_ECKD_STR;
136411ed322SMichael Holzheu case DUMP_TYPE_FCP:
137411ed322SMichael Holzheu return DUMP_FCP_STR;
138d70e38cbSJason J. Herne case DUMP_TYPE_NVME:
139d70e38cbSJason J. Herne return DUMP_NVME_STR;
140411ed322SMichael Holzheu default:
141411ed322SMichael Holzheu return NULL;
142411ed322SMichael Holzheu }
143411ed322SMichael Holzheu }
144411ed322SMichael Holzheu
1451e941d39SVasily Gorbik int __bootdata_preserved(ipl_block_valid);
1461e941d39SVasily Gorbik struct ipl_parameter_block __bootdata_preserved(ipl_block);
1479641b8ccSMartin Schwidefsky int __bootdata_preserved(ipl_secure_flag);
1489641b8ccSMartin Schwidefsky
1499641b8ccSMartin Schwidefsky unsigned long __bootdata_preserved(ipl_cert_list_addr);
1509641b8ccSMartin Schwidefsky unsigned long __bootdata_preserved(ipl_cert_list_size);
1519641b8ccSMartin Schwidefsky
1529641b8ccSMartin Schwidefsky unsigned long __bootdata(early_ipl_comp_list_addr);
1539641b8ccSMartin Schwidefsky unsigned long __bootdata(early_ipl_comp_list_size);
154a0443fbbSHendrik Brueckner
155ff6b8ea6SMichael Holzheu static int reipl_capabilities = IPL_TYPE_UNKNOWN;
156fe355b7fSHongjie Yang
157ff6b8ea6SMichael Holzheu static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
158ff6b8ea6SMichael Holzheu static struct ipl_parameter_block *reipl_block_fcp;
15923a457b8SJason J. Herne static struct ipl_parameter_block *reipl_block_nvme;
160ff6b8ea6SMichael Holzheu static struct ipl_parameter_block *reipl_block_ccw;
16187fd22e0SSven Schnelle static struct ipl_parameter_block *reipl_block_eckd;
162a0443fbbSHendrik Brueckner static struct ipl_parameter_block *reipl_block_nss;
163099b7651SFrank Munzert static struct ipl_parameter_block *reipl_block_actual;
164fe355b7fSHongjie Yang
165411ed322SMichael Holzheu static int dump_capabilities = DUMP_TYPE_NONE;
166411ed322SMichael Holzheu static enum dump_type dump_type = DUMP_TYPE_NONE;
167ff6b8ea6SMichael Holzheu static struct ipl_parameter_block *dump_block_fcp;
168d70e38cbSJason J. Herne static struct ipl_parameter_block *dump_block_nvme;
169ff6b8ea6SMichael Holzheu static struct ipl_parameter_block *dump_block_ccw;
170e2d2a296SSven Schnelle static struct ipl_parameter_block *dump_block_eckd;
171ff6b8ea6SMichael Holzheu
17205dd2530SHeiko Carstens static struct sclp_ipl_info sclp_ipl_info;
17305dd2530SHeiko Carstens
1745627b922SGerald Schaefer static bool reipl_nvme_clear;
1751a2ae03bSGerald Schaefer static bool reipl_fcp_clear;
1761a2ae03bSGerald Schaefer static bool reipl_ccw_clear;
17787fd22e0SSven Schnelle static bool reipl_eckd_clear;
1781a2ae03bSGerald Schaefer
17931e9ccc6SMikhail Zaslonko static unsigned long os_info_flags;
18031e9ccc6SMikhail Zaslonko
__diag308(unsigned long subcode,unsigned long addr)181bac30ea9SNico Boehr static inline int __diag308(unsigned long subcode, unsigned long addr)
182ff6b8ea6SMichael Holzheu {
1835a4e0f58SHeiko Carstens union register_pair r1;
184ff6b8ea6SMichael Holzheu
185bac30ea9SNico Boehr r1.even = addr;
1865a4e0f58SHeiko Carstens r1.odd = 0;
187ff6b8ea6SMichael Holzheu asm volatile(
1885a4e0f58SHeiko Carstens " diag %[r1],%[subcode],0x308\n"
1896c22c986SHeiko Carstens "0: nopr %%r7\n"
19094c12cc7SMartin Schwidefsky EX_TABLE(0b,0b)
1915a4e0f58SHeiko Carstens : [r1] "+&d" (r1.pair)
1925a4e0f58SHeiko Carstens : [subcode] "d" (subcode)
1935a4e0f58SHeiko Carstens : "cc", "memory");
1945a4e0f58SHeiko Carstens return r1.odd;
195ff6b8ea6SMichael Holzheu }
1961ec2772eSMartin Schwidefsky
diag308(unsigned long subcode,void * addr)1971ec2772eSMartin Schwidefsky int diag308(unsigned long subcode, void *addr)
1981ec2772eSMartin Schwidefsky {
1991ec2772eSMartin Schwidefsky diag_stat_inc(DIAG_STAT_X308);
200bac30ea9SNico Boehr return __diag308(subcode, addr ? virt_to_phys(addr) : 0);
2011ec2772eSMartin Schwidefsky }
202411ed322SMichael Holzheu EXPORT_SYMBOL_GPL(diag308);
203ff6b8ea6SMichael Holzheu
204ff6b8ea6SMichael Holzheu /* SYSFS */
205ff6b8ea6SMichael Holzheu
2063be7ae63SSebastian Ott #define IPL_ATTR_SHOW_FN(_prefix, _name, _format, args...) \
2079b949165SGreg Kroah-Hartman static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj, \
2089b949165SGreg Kroah-Hartman struct kobj_attribute *attr, \
209ff6b8ea6SMichael Holzheu char *page) \
210ff6b8ea6SMichael Holzheu { \
21192fd3565SChen Zhou return scnprintf(page, PAGE_SIZE, _format, ##args); \
2123be7ae63SSebastian Ott }
2133be7ae63SSebastian Ott
21418e22a17SSebastian Ott #define IPL_ATTR_CCW_STORE_FN(_prefix, _name, _ipl_blk) \
21518e22a17SSebastian Ott static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
21618e22a17SSebastian Ott struct kobj_attribute *attr, \
21718e22a17SSebastian Ott const char *buf, size_t len) \
21818e22a17SSebastian Ott { \
21918e22a17SSebastian Ott unsigned long long ssid, devno; \
22018e22a17SSebastian Ott \
22118e22a17SSebastian Ott if (sscanf(buf, "0.%llx.%llx\n", &ssid, &devno) != 2) \
22218e22a17SSebastian Ott return -EINVAL; \
22318e22a17SSebastian Ott \
22418e22a17SSebastian Ott if (ssid > __MAX_SSID || devno > __MAX_SUBCHANNEL) \
22518e22a17SSebastian Ott return -EINVAL; \
22618e22a17SSebastian Ott \
22718e22a17SSebastian Ott _ipl_blk.ssid = ssid; \
22818e22a17SSebastian Ott _ipl_blk.devno = devno; \
22918e22a17SSebastian Ott return len; \
23018e22a17SSebastian Ott }
23118e22a17SSebastian Ott
23218e22a17SSebastian Ott #define DEFINE_IPL_CCW_ATTR_RW(_prefix, _name, _ipl_blk) \
23318e22a17SSebastian Ott IPL_ATTR_SHOW_FN(_prefix, _name, "0.%x.%04x\n", \
23418e22a17SSebastian Ott _ipl_blk.ssid, _ipl_blk.devno); \
23518e22a17SSebastian Ott IPL_ATTR_CCW_STORE_FN(_prefix, _name, _ipl_blk); \
23618e22a17SSebastian Ott static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
237a70f7276SSven Schnelle __ATTR(_name, 0644, \
23818e22a17SSebastian Ott sys_##_prefix##_##_name##_show, \
23918e22a17SSebastian Ott sys_##_prefix##_##_name##_store) \
24018e22a17SSebastian Ott
2413be7ae63SSebastian Ott #define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \
2423be7ae63SSebastian Ott IPL_ATTR_SHOW_FN(_prefix, _name, _format, _value) \
2439b949165SGreg Kroah-Hartman static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
244a70f7276SSven Schnelle __ATTR(_name, 0444, sys_##_prefix##_##_name##_show, NULL)
245ff6b8ea6SMichael Holzheu
246ff6b8ea6SMichael Holzheu #define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value) \
2473be7ae63SSebastian Ott IPL_ATTR_SHOW_FN(_prefix, _name, _fmt_out, (unsigned long long) _value) \
2489b949165SGreg Kroah-Hartman static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
2499b949165SGreg Kroah-Hartman struct kobj_attribute *attr, \
250ff6b8ea6SMichael Holzheu const char *buf, size_t len) \
251ff6b8ea6SMichael Holzheu { \
252ff6b8ea6SMichael Holzheu unsigned long long value; \
253ff6b8ea6SMichael Holzheu if (sscanf(buf, _fmt_in, &value) != 1) \
254ff6b8ea6SMichael Holzheu return -EINVAL; \
255ff6b8ea6SMichael Holzheu _value = value; \
256ff6b8ea6SMichael Holzheu return len; \
257ff6b8ea6SMichael Holzheu } \
2589b949165SGreg Kroah-Hartman static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
259a70f7276SSven Schnelle __ATTR(_name, 0644, \
260ff6b8ea6SMichael Holzheu sys_##_prefix##_##_name##_show, \
2613be7ae63SSebastian Ott sys_##_prefix##_##_name##_store)
262ff6b8ea6SMichael Holzheu
263fe355b7fSHongjie Yang #define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
2643be7ae63SSebastian Ott IPL_ATTR_SHOW_FN(_prefix, _name, _fmt_out, _value) \
2659b949165SGreg Kroah-Hartman static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
2669b949165SGreg Kroah-Hartman struct kobj_attribute *attr, \
267fe355b7fSHongjie Yang const char *buf, size_t len) \
268fe355b7fSHongjie Yang { \
269cfd01210SJustin Stitt strscpy(_value, buf, sizeof(_value)); \
2701d802e24SHeiko Carstens strim(_value); \
271fe355b7fSHongjie Yang return len; \
272fe355b7fSHongjie Yang } \
2739b949165SGreg Kroah-Hartman static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
274a70f7276SSven Schnelle __ATTR(_name, 0644, \
275fe355b7fSHongjie Yang sys_##_prefix##_##_name##_show, \
2763be7ae63SSebastian Ott sys_##_prefix##_##_name##_store)
277fe355b7fSHongjie Yang
278ff6b8ea6SMichael Holzheu /*
279ff6b8ea6SMichael Holzheu * ipl section
280ff6b8ea6SMichael Holzheu */
281ff6b8ea6SMichael Holzheu
get_ipl_type(void)282411ed322SMichael Holzheu static __init enum ipl_type get_ipl_type(void)
283ff6b8ea6SMichael Holzheu {
284d08091acSVasily Gorbik if (!ipl_block_valid)
285ff6b8ea6SMichael Holzheu return IPL_TYPE_UNKNOWN;
286d08091acSVasily Gorbik
2875f1207fbSMartin Schwidefsky switch (ipl_block.pb0_hdr.pbt) {
2885f1207fbSMartin Schwidefsky case IPL_PBT_CCW:
289ff6b8ea6SMichael Holzheu return IPL_TYPE_CCW;
2905f1207fbSMartin Schwidefsky case IPL_PBT_FCP:
2915f1207fbSMartin Schwidefsky if (ipl_block.fcp.opt == IPL_PB0_FCP_OPT_DUMP)
292411ed322SMichael Holzheu return IPL_TYPE_FCP_DUMP;
293d08091acSVasily Gorbik else
294ff6b8ea6SMichael Holzheu return IPL_TYPE_FCP;
2953737e8eeSJason J. Herne case IPL_PBT_NVME:
296d70e38cbSJason J. Herne if (ipl_block.nvme.opt == IPL_PB0_NVME_OPT_DUMP)
297d70e38cbSJason J. Herne return IPL_TYPE_NVME_DUMP;
298d70e38cbSJason J. Herne else
2993737e8eeSJason J. Herne return IPL_TYPE_NVME;
30087fd22e0SSven Schnelle case IPL_PBT_ECKD:
301e2d2a296SSven Schnelle if (ipl_block.eckd.opt == IPL_PB0_ECKD_OPT_DUMP)
302e2d2a296SSven Schnelle return IPL_TYPE_ECKD_DUMP;
303e2d2a296SSven Schnelle else
30487fd22e0SSven Schnelle return IPL_TYPE_ECKD;
305ff6b8ea6SMichael Holzheu }
306d08091acSVasily Gorbik return IPL_TYPE_UNKNOWN;
307d08091acSVasily Gorbik }
308ff6b8ea6SMichael Holzheu
309411ed322SMichael Holzheu struct ipl_info ipl_info;
310411ed322SMichael Holzheu EXPORT_SYMBOL_GPL(ipl_info);
311411ed322SMichael Holzheu
ipl_type_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)3129b949165SGreg Kroah-Hartman static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr,
3139b949165SGreg Kroah-Hartman char *page)
314ff6b8ea6SMichael Holzheu {
315411ed322SMichael Holzheu return sprintf(page, "%s\n", ipl_type_str(ipl_info.type));
316ff6b8ea6SMichael Holzheu }
317ff6b8ea6SMichael Holzheu
3189b949165SGreg Kroah-Hartman static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
319ff6b8ea6SMichael Holzheu
ipl_secure_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)3209641b8ccSMartin Schwidefsky static ssize_t ipl_secure_show(struct kobject *kobj,
3219641b8ccSMartin Schwidefsky struct kobj_attribute *attr, char *page)
3229641b8ccSMartin Schwidefsky {
3239641b8ccSMartin Schwidefsky return sprintf(page, "%i\n", !!ipl_secure_flag);
3249641b8ccSMartin Schwidefsky }
3259641b8ccSMartin Schwidefsky
3269641b8ccSMartin Schwidefsky static struct kobj_attribute sys_ipl_secure_attr =
3279641b8ccSMartin Schwidefsky __ATTR(secure, 0444, ipl_secure_show, NULL);
3289641b8ccSMartin Schwidefsky
ipl_has_secure_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)329c9896accSPhilipp Rudo static ssize_t ipl_has_secure_show(struct kobject *kobj,
330c9896accSPhilipp Rudo struct kobj_attribute *attr, char *page)
331c9896accSPhilipp Rudo {
332c9896accSPhilipp Rudo return sprintf(page, "%i\n", !!sclp.has_sipl);
333c9896accSPhilipp Rudo }
334c9896accSPhilipp Rudo
335c9896accSPhilipp Rudo static struct kobj_attribute sys_ipl_has_secure_attr =
336c9896accSPhilipp Rudo __ATTR(has_secure, 0444, ipl_has_secure_show, NULL);
337c9896accSPhilipp Rudo
ipl_vm_parm_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)338a0443fbbSHendrik Brueckner static ssize_t ipl_vm_parm_show(struct kobject *kobj,
339a0443fbbSHendrik Brueckner struct kobj_attribute *attr, char *page)
340a0443fbbSHendrik Brueckner {
341a0443fbbSHendrik Brueckner char parm[DIAG308_VMPARM_SIZE + 1] = {};
342a0443fbbSHendrik Brueckner
3435f1207fbSMartin Schwidefsky if (ipl_block_valid && (ipl_block.pb0_hdr.pbt == IPL_PBT_CCW))
34449698745SVasily Gorbik ipl_block_get_ascii_vmparm(parm, sizeof(parm), &ipl_block);
345a0443fbbSHendrik Brueckner return sprintf(page, "%s\n", parm);
346a0443fbbSHendrik Brueckner }
347a0443fbbSHendrik Brueckner
348a0443fbbSHendrik Brueckner static struct kobj_attribute sys_ipl_vm_parm_attr =
349a70f7276SSven Schnelle __ATTR(parm, 0444, ipl_vm_parm_show, NULL);
350a0443fbbSHendrik Brueckner
sys_ipl_device_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)3519b949165SGreg Kroah-Hartman static ssize_t sys_ipl_device_show(struct kobject *kobj,
3529b949165SGreg Kroah-Hartman struct kobj_attribute *attr, char *page)
353ff6b8ea6SMichael Holzheu {
354411ed322SMichael Holzheu switch (ipl_info.type) {
355ff6b8ea6SMichael Holzheu case IPL_TYPE_CCW:
35686c74d86SMartin Schwidefsky return sprintf(page, "0.%x.%04x\n", ipl_block.ccw.ssid,
35786c74d86SMartin Schwidefsky ipl_block.ccw.devno);
35887fd22e0SSven Schnelle case IPL_TYPE_ECKD:
359e2d2a296SSven Schnelle case IPL_TYPE_ECKD_DUMP:
36087fd22e0SSven Schnelle return sprintf(page, "0.%x.%04x\n", ipl_block.eckd.ssid,
36187fd22e0SSven Schnelle ipl_block.eckd.devno);
362ff6b8ea6SMichael Holzheu case IPL_TYPE_FCP:
363411ed322SMichael Holzheu case IPL_TYPE_FCP_DUMP:
36486c74d86SMartin Schwidefsky return sprintf(page, "0.0.%04x\n", ipl_block.fcp.devno);
3653737e8eeSJason J. Herne case IPL_TYPE_NVME:
366d70e38cbSJason J. Herne case IPL_TYPE_NVME_DUMP:
3673737e8eeSJason J. Herne return sprintf(page, "%08ux\n", ipl_block.nvme.fid);
368ff6b8ea6SMichael Holzheu default:
369ff6b8ea6SMichael Holzheu return 0;
370ff6b8ea6SMichael Holzheu }
371ff6b8ea6SMichael Holzheu }
372ff6b8ea6SMichael Holzheu
3739b949165SGreg Kroah-Hartman static struct kobj_attribute sys_ipl_device_attr =
374a70f7276SSven Schnelle __ATTR(device, 0444, sys_ipl_device_show, NULL);
375ff6b8ea6SMichael Holzheu
ipl_parameter_read(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)3762c3c8beaSChris Wright static ssize_t ipl_parameter_read(struct file *filp, struct kobject *kobj,
3772c3c8beaSChris Wright struct bin_attribute *attr, char *buf,
3782c3c8beaSChris Wright loff_t off, size_t count)
379ff6b8ea6SMichael Holzheu {
380bdbfe185SVasily Gorbik return memory_read_from_buffer(buf, count, &off, &ipl_block,
381bdbfe185SVasily Gorbik ipl_block.hdr.len);
382ff6b8ea6SMichael Holzheu }
38322d557abSSebastian Ott static struct bin_attribute ipl_parameter_attr =
384a70f7276SSven Schnelle __BIN_ATTR(binary_parameter, 0444, ipl_parameter_read, NULL,
38522d557abSSebastian Ott PAGE_SIZE);
386ff6b8ea6SMichael Holzheu
ipl_scp_data_read(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)3872c3c8beaSChris Wright static ssize_t ipl_scp_data_read(struct file *filp, struct kobject *kobj,
3882c3c8beaSChris Wright struct bin_attribute *attr, char *buf,
3892c3c8beaSChris Wright loff_t off, size_t count)
390ff6b8ea6SMichael Holzheu {
39186c74d86SMartin Schwidefsky unsigned int size = ipl_block.fcp.scp_data_len;
39286c74d86SMartin Schwidefsky void *scp_data = &ipl_block.fcp.scp_data;
393ff6b8ea6SMichael Holzheu
3940788fea4SAkinobu Mita return memory_read_from_buffer(buf, count, &off, scp_data, size);
395ff6b8ea6SMichael Holzheu }
3963737e8eeSJason J. Herne
ipl_nvme_scp_data_read(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)3973737e8eeSJason J. Herne static ssize_t ipl_nvme_scp_data_read(struct file *filp, struct kobject *kobj,
3983737e8eeSJason J. Herne struct bin_attribute *attr, char *buf,
3993737e8eeSJason J. Herne loff_t off, size_t count)
4003737e8eeSJason J. Herne {
4013737e8eeSJason J. Herne unsigned int size = ipl_block.nvme.scp_data_len;
4023737e8eeSJason J. Herne void *scp_data = &ipl_block.nvme.scp_data;
4033737e8eeSJason J. Herne
4043737e8eeSJason J. Herne return memory_read_from_buffer(buf, count, &off, scp_data, size);
4053737e8eeSJason J. Herne }
4063737e8eeSJason J. Herne
ipl_eckd_scp_data_read(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)40787fd22e0SSven Schnelle static ssize_t ipl_eckd_scp_data_read(struct file *filp, struct kobject *kobj,
40887fd22e0SSven Schnelle struct bin_attribute *attr, char *buf,
40987fd22e0SSven Schnelle loff_t off, size_t count)
41087fd22e0SSven Schnelle {
41187fd22e0SSven Schnelle unsigned int size = ipl_block.eckd.scp_data_len;
41287fd22e0SSven Schnelle void *scp_data = &ipl_block.eckd.scp_data;
41387fd22e0SSven Schnelle
41487fd22e0SSven Schnelle return memory_read_from_buffer(buf, count, &off, scp_data, size);
41587fd22e0SSven Schnelle }
41687fd22e0SSven Schnelle
41722d557abSSebastian Ott static struct bin_attribute ipl_scp_data_attr =
418a70f7276SSven Schnelle __BIN_ATTR(scp_data, 0444, ipl_scp_data_read, NULL, PAGE_SIZE);
419ff6b8ea6SMichael Holzheu
4203737e8eeSJason J. Herne static struct bin_attribute ipl_nvme_scp_data_attr =
421a70f7276SSven Schnelle __BIN_ATTR(scp_data, 0444, ipl_nvme_scp_data_read, NULL, PAGE_SIZE);
4223737e8eeSJason J. Herne
42387fd22e0SSven Schnelle static struct bin_attribute ipl_eckd_scp_data_attr =
424a70f7276SSven Schnelle __BIN_ATTR(scp_data, 0444, ipl_eckd_scp_data_read, NULL, PAGE_SIZE);
42587fd22e0SSven Schnelle
42622d557abSSebastian Ott static struct bin_attribute *ipl_fcp_bin_attrs[] = {
42722d557abSSebastian Ott &ipl_parameter_attr,
42822d557abSSebastian Ott &ipl_scp_data_attr,
42922d557abSSebastian Ott NULL,
430ff6b8ea6SMichael Holzheu };
431ff6b8ea6SMichael Holzheu
4323737e8eeSJason J. Herne static struct bin_attribute *ipl_nvme_bin_attrs[] = {
4333737e8eeSJason J. Herne &ipl_parameter_attr,
4343737e8eeSJason J. Herne &ipl_nvme_scp_data_attr,
4353737e8eeSJason J. Herne NULL,
4363737e8eeSJason J. Herne };
4373737e8eeSJason J. Herne
43887fd22e0SSven Schnelle static struct bin_attribute *ipl_eckd_bin_attrs[] = {
43987fd22e0SSven Schnelle &ipl_parameter_attr,
44087fd22e0SSven Schnelle &ipl_eckd_scp_data_attr,
44187fd22e0SSven Schnelle NULL,
44287fd22e0SSven Schnelle };
44387fd22e0SSven Schnelle
444ff6b8ea6SMichael Holzheu /* FCP ipl device attributes */
445ff6b8ea6SMichael Holzheu
446bdbfe185SVasily Gorbik DEFINE_IPL_ATTR_RO(ipl_fcp, wwpn, "0x%016llx\n",
44786c74d86SMartin Schwidefsky (unsigned long long)ipl_block.fcp.wwpn);
448bdbfe185SVasily Gorbik DEFINE_IPL_ATTR_RO(ipl_fcp, lun, "0x%016llx\n",
44986c74d86SMartin Schwidefsky (unsigned long long)ipl_block.fcp.lun);
450bdbfe185SVasily Gorbik DEFINE_IPL_ATTR_RO(ipl_fcp, bootprog, "%lld\n",
45186c74d86SMartin Schwidefsky (unsigned long long)ipl_block.fcp.bootprog);
452bdbfe185SVasily Gorbik DEFINE_IPL_ATTR_RO(ipl_fcp, br_lba, "%lld\n",
45386c74d86SMartin Schwidefsky (unsigned long long)ipl_block.fcp.br_lba);
454ff6b8ea6SMichael Holzheu
4553737e8eeSJason J. Herne /* NVMe ipl device attributes */
4563737e8eeSJason J. Herne DEFINE_IPL_ATTR_RO(ipl_nvme, fid, "0x%08llx\n",
4573737e8eeSJason J. Herne (unsigned long long)ipl_block.nvme.fid);
4583737e8eeSJason J. Herne DEFINE_IPL_ATTR_RO(ipl_nvme, nsid, "0x%08llx\n",
4593737e8eeSJason J. Herne (unsigned long long)ipl_block.nvme.nsid);
4603737e8eeSJason J. Herne DEFINE_IPL_ATTR_RO(ipl_nvme, bootprog, "%lld\n",
4613737e8eeSJason J. Herne (unsigned long long)ipl_block.nvme.bootprog);
4623737e8eeSJason J. Herne DEFINE_IPL_ATTR_RO(ipl_nvme, br_lba, "%lld\n",
4633737e8eeSJason J. Herne (unsigned long long)ipl_block.nvme.br_lba);
4643737e8eeSJason J. Herne
46587fd22e0SSven Schnelle /* ECKD ipl device attributes */
46687fd22e0SSven Schnelle DEFINE_IPL_ATTR_RO(ipl_eckd, bootprog, "%lld\n",
46787fd22e0SSven Schnelle (unsigned long long)ipl_block.eckd.bootprog);
46887fd22e0SSven Schnelle
46987fd22e0SSven Schnelle #define IPL_ATTR_BR_CHR_SHOW_FN(_name, _ipb) \
47087fd22e0SSven Schnelle static ssize_t eckd_##_name##_br_chr_show(struct kobject *kobj, \
47187fd22e0SSven Schnelle struct kobj_attribute *attr, \
47287fd22e0SSven Schnelle char *buf) \
47387fd22e0SSven Schnelle { \
47487fd22e0SSven Schnelle struct ipl_pb0_eckd *ipb = &(_ipb); \
47587fd22e0SSven Schnelle \
47687fd22e0SSven Schnelle if (!ipb->br_chr.cyl && \
47787fd22e0SSven Schnelle !ipb->br_chr.head && \
47887fd22e0SSven Schnelle !ipb->br_chr.record) \
47987fd22e0SSven Schnelle return sprintf(buf, "auto\n"); \
48087fd22e0SSven Schnelle \
48187fd22e0SSven Schnelle return sprintf(buf, "0x%x,0x%x,0x%x\n", \
48287fd22e0SSven Schnelle ipb->br_chr.cyl, \
48387fd22e0SSven Schnelle ipb->br_chr.head, \
48487fd22e0SSven Schnelle ipb->br_chr.record); \
48587fd22e0SSven Schnelle }
48687fd22e0SSven Schnelle
48787fd22e0SSven Schnelle #define IPL_ATTR_BR_CHR_STORE_FN(_name, _ipb) \
48887fd22e0SSven Schnelle static ssize_t eckd_##_name##_br_chr_store(struct kobject *kobj, \
48987fd22e0SSven Schnelle struct kobj_attribute *attr, \
49087fd22e0SSven Schnelle const char *buf, size_t len) \
49187fd22e0SSven Schnelle { \
49287fd22e0SSven Schnelle struct ipl_pb0_eckd *ipb = &(_ipb); \
49387fd22e0SSven Schnelle unsigned long args[3] = { 0 }; \
49487fd22e0SSven Schnelle char *p, *p1, *tmp = NULL; \
49587fd22e0SSven Schnelle int i, rc; \
49687fd22e0SSven Schnelle \
49787fd22e0SSven Schnelle if (!strncmp(buf, "auto", 4)) \
49887fd22e0SSven Schnelle goto out; \
49987fd22e0SSven Schnelle \
50087fd22e0SSven Schnelle tmp = kstrdup(buf, GFP_KERNEL); \
50187fd22e0SSven Schnelle p = tmp; \
50287fd22e0SSven Schnelle for (i = 0; i < 3; i++) { \
50387fd22e0SSven Schnelle p1 = strsep(&p, ", "); \
50487fd22e0SSven Schnelle if (!p1) { \
50587fd22e0SSven Schnelle rc = -EINVAL; \
50687fd22e0SSven Schnelle goto err; \
50787fd22e0SSven Schnelle } \
50887fd22e0SSven Schnelle rc = kstrtoul(p1, 0, args + i); \
50987fd22e0SSven Schnelle if (rc) \
51087fd22e0SSven Schnelle goto err; \
51187fd22e0SSven Schnelle } \
51287fd22e0SSven Schnelle \
51387fd22e0SSven Schnelle rc = -EINVAL; \
51487fd22e0SSven Schnelle if (i != 3) \
51587fd22e0SSven Schnelle goto err; \
51687fd22e0SSven Schnelle \
51787fd22e0SSven Schnelle if ((args[0] || args[1]) && !args[2]) \
51887fd22e0SSven Schnelle goto err; \
51987fd22e0SSven Schnelle \
52087fd22e0SSven Schnelle if (args[0] > UINT_MAX || args[1] > 255 || args[2] > 255) \
52187fd22e0SSven Schnelle goto err; \
52287fd22e0SSven Schnelle \
52387fd22e0SSven Schnelle out: \
52487fd22e0SSven Schnelle ipb->br_chr.cyl = args[0]; \
52587fd22e0SSven Schnelle ipb->br_chr.head = args[1]; \
52687fd22e0SSven Schnelle ipb->br_chr.record = args[2]; \
52787fd22e0SSven Schnelle rc = len; \
52887fd22e0SSven Schnelle err: \
52987fd22e0SSven Schnelle kfree(tmp); \
53087fd22e0SSven Schnelle return rc; \
53187fd22e0SSven Schnelle }
53287fd22e0SSven Schnelle
53387fd22e0SSven Schnelle IPL_ATTR_BR_CHR_SHOW_FN(ipl, ipl_block.eckd);
53487fd22e0SSven Schnelle static struct kobj_attribute sys_ipl_eckd_br_chr_attr =
535a70f7276SSven Schnelle __ATTR(br_chr, 0644, eckd_ipl_br_chr_show, NULL);
53687fd22e0SSven Schnelle
53787fd22e0SSven Schnelle IPL_ATTR_BR_CHR_SHOW_FN(reipl, reipl_block_eckd->eckd);
53887fd22e0SSven Schnelle IPL_ATTR_BR_CHR_STORE_FN(reipl, reipl_block_eckd->eckd);
53987fd22e0SSven Schnelle
54087fd22e0SSven Schnelle static struct kobj_attribute sys_reipl_eckd_br_chr_attr =
541a70f7276SSven Schnelle __ATTR(br_chr, 0644, eckd_reipl_br_chr_show, eckd_reipl_br_chr_store);
54287fd22e0SSven Schnelle
ipl_ccw_loadparm_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)5439b949165SGreg Kroah-Hartman static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
5449b949165SGreg Kroah-Hartman struct kobj_attribute *attr, char *page)
54503a4d208SMichael Holzheu {
54603a4d208SMichael Holzheu char loadparm[LOADPARM_LEN + 1] = {};
54703a4d208SMichael Holzheu
54805dd2530SHeiko Carstens if (!sclp_ipl_info.is_valid)
54903a4d208SMichael Holzheu return sprintf(page, "#unknown#\n");
55005dd2530SHeiko Carstens memcpy(loadparm, &sclp_ipl_info.loadparm, LOADPARM_LEN);
55103a4d208SMichael Holzheu EBCASC(loadparm, LOADPARM_LEN);
5521d802e24SHeiko Carstens strim(loadparm);
55303a4d208SMichael Holzheu return sprintf(page, "%s\n", loadparm);
55403a4d208SMichael Holzheu }
55503a4d208SMichael Holzheu
5569b949165SGreg Kroah-Hartman static struct kobj_attribute sys_ipl_ccw_loadparm_attr =
55703a4d208SMichael Holzheu __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
55803a4d208SMichael Holzheu
55969928601SMichael Holzheu static struct attribute *ipl_fcp_attrs[] = {
56069928601SMichael Holzheu &sys_ipl_device_attr.attr,
56169928601SMichael Holzheu &sys_ipl_fcp_wwpn_attr.attr,
56269928601SMichael Holzheu &sys_ipl_fcp_lun_attr.attr,
56369928601SMichael Holzheu &sys_ipl_fcp_bootprog_attr.attr,
56469928601SMichael Holzheu &sys_ipl_fcp_br_lba_attr.attr,
56569928601SMichael Holzheu &sys_ipl_ccw_loadparm_attr.attr,
56669928601SMichael Holzheu NULL,
56769928601SMichael Holzheu };
56869928601SMichael Holzheu
56969928601SMichael Holzheu static struct attribute_group ipl_fcp_attr_group = {
57069928601SMichael Holzheu .attrs = ipl_fcp_attrs,
57122d557abSSebastian Ott .bin_attrs = ipl_fcp_bin_attrs,
57269928601SMichael Holzheu };
57369928601SMichael Holzheu
5743737e8eeSJason J. Herne static struct attribute *ipl_nvme_attrs[] = {
5753737e8eeSJason J. Herne &sys_ipl_nvme_fid_attr.attr,
5763737e8eeSJason J. Herne &sys_ipl_nvme_nsid_attr.attr,
5773737e8eeSJason J. Herne &sys_ipl_nvme_bootprog_attr.attr,
5783737e8eeSJason J. Herne &sys_ipl_nvme_br_lba_attr.attr,
5793737e8eeSJason J. Herne &sys_ipl_ccw_loadparm_attr.attr,
5803737e8eeSJason J. Herne NULL,
5813737e8eeSJason J. Herne };
5823737e8eeSJason J. Herne
5833737e8eeSJason J. Herne static struct attribute_group ipl_nvme_attr_group = {
5843737e8eeSJason J. Herne .attrs = ipl_nvme_attrs,
5853737e8eeSJason J. Herne .bin_attrs = ipl_nvme_bin_attrs,
5863737e8eeSJason J. Herne };
5873737e8eeSJason J. Herne
58887fd22e0SSven Schnelle static struct attribute *ipl_eckd_attrs[] = {
58987fd22e0SSven Schnelle &sys_ipl_eckd_bootprog_attr.attr,
59087fd22e0SSven Schnelle &sys_ipl_eckd_br_chr_attr.attr,
5916bb361d5SSven Schnelle &sys_ipl_ccw_loadparm_attr.attr,
59287fd22e0SSven Schnelle &sys_ipl_device_attr.attr,
59387fd22e0SSven Schnelle NULL,
59487fd22e0SSven Schnelle };
59587fd22e0SSven Schnelle
59687fd22e0SSven Schnelle static struct attribute_group ipl_eckd_attr_group = {
59787fd22e0SSven Schnelle .attrs = ipl_eckd_attrs,
59887fd22e0SSven Schnelle .bin_attrs = ipl_eckd_bin_attrs,
59987fd22e0SSven Schnelle };
6003737e8eeSJason J. Herne
60169928601SMichael Holzheu /* CCW ipl device attributes */
60269928601SMichael Holzheu
603a0443fbbSHendrik Brueckner static struct attribute *ipl_ccw_attrs_vm[] = {
604a0443fbbSHendrik Brueckner &sys_ipl_device_attr.attr,
605a0443fbbSHendrik Brueckner &sys_ipl_ccw_loadparm_attr.attr,
606a0443fbbSHendrik Brueckner &sys_ipl_vm_parm_attr.attr,
607a0443fbbSHendrik Brueckner NULL,
608a0443fbbSHendrik Brueckner };
609a0443fbbSHendrik Brueckner
610a0443fbbSHendrik Brueckner static struct attribute *ipl_ccw_attrs_lpar[] = {
611ff6b8ea6SMichael Holzheu &sys_ipl_device_attr.attr,
61203a4d208SMichael Holzheu &sys_ipl_ccw_loadparm_attr.attr,
613ff6b8ea6SMichael Holzheu NULL,
614ff6b8ea6SMichael Holzheu };
615ff6b8ea6SMichael Holzheu
616a0443fbbSHendrik Brueckner static struct attribute_group ipl_ccw_attr_group_vm = {
617a0443fbbSHendrik Brueckner .attrs = ipl_ccw_attrs_vm,
618a0443fbbSHendrik Brueckner };
619a0443fbbSHendrik Brueckner
620a0443fbbSHendrik Brueckner static struct attribute_group ipl_ccw_attr_group_lpar = {
621a0443fbbSHendrik Brueckner .attrs = ipl_ccw_attrs_lpar
622ff6b8ea6SMichael Holzheu };
623ff6b8ea6SMichael Holzheu
6247645dcddSSven Schnelle static struct attribute *ipl_common_attrs[] = {
625ff6b8ea6SMichael Holzheu &sys_ipl_type_attr.attr,
626ea5717cbSSven Schnelle &sys_ipl_secure_attr.attr,
627ea5717cbSSven Schnelle &sys_ipl_has_secure_attr.attr,
628ff6b8ea6SMichael Holzheu NULL,
629ff6b8ea6SMichael Holzheu };
630ff6b8ea6SMichael Holzheu
6317645dcddSSven Schnelle static struct attribute_group ipl_common_attr_group = {
6327645dcddSSven Schnelle .attrs = ipl_common_attrs,
633ff6b8ea6SMichael Holzheu };
634ff6b8ea6SMichael Holzheu
635d91885beSGreg Kroah-Hartman static struct kset *ipl_kset;
636ff6b8ea6SMichael Holzheu
__ipl_run(void * unused)6372c2df118SHeiko Carstens static void __ipl_run(void *unused)
63899ca4e58SMichael Holzheu {
6390599eeadSHeiko Carstens diag308(DIAG308_LOAD_CLEAR, NULL);
64099ca4e58SMichael Holzheu }
64199ca4e58SMichael Holzheu
ipl_run(struct shutdown_trigger * trigger)6422c2df118SHeiko Carstens static void ipl_run(struct shutdown_trigger *trigger)
6432c2df118SHeiko Carstens {
6448b646bd7SMartin Schwidefsky smp_call_ipl_cpu(__ipl_run, NULL);
6452c2df118SHeiko Carstens }
6462c2df118SHeiko Carstens
ipl_init(void)6472bc89b5eSHeiko Carstens static int __init ipl_init(void)
64899ca4e58SMichael Holzheu {
64999ca4e58SMichael Holzheu int rc;
65099ca4e58SMichael Holzheu
65199ca4e58SMichael Holzheu ipl_kset = kset_create_and_add("ipl", NULL, firmware_kobj);
65299ca4e58SMichael Holzheu if (!ipl_kset) {
65399ca4e58SMichael Holzheu rc = -ENOMEM;
65499ca4e58SMichael Holzheu goto out;
65599ca4e58SMichael Holzheu }
6567645dcddSSven Schnelle rc = sysfs_create_group(&ipl_kset->kobj, &ipl_common_attr_group);
6577645dcddSSven Schnelle if (rc)
6587645dcddSSven Schnelle goto out;
65999ca4e58SMichael Holzheu switch (ipl_info.type) {
66099ca4e58SMichael Holzheu case IPL_TYPE_CCW:
661a0443fbbSHendrik Brueckner if (MACHINE_IS_VM)
662a0443fbbSHendrik Brueckner rc = sysfs_create_group(&ipl_kset->kobj,
663a0443fbbSHendrik Brueckner &ipl_ccw_attr_group_vm);
664a0443fbbSHendrik Brueckner else
665a0443fbbSHendrik Brueckner rc = sysfs_create_group(&ipl_kset->kobj,
666a0443fbbSHendrik Brueckner &ipl_ccw_attr_group_lpar);
66799ca4e58SMichael Holzheu break;
66887fd22e0SSven Schnelle case IPL_TYPE_ECKD:
669322b3f6cSMikhail Zaslonko case IPL_TYPE_ECKD_DUMP:
67087fd22e0SSven Schnelle rc = sysfs_create_group(&ipl_kset->kobj, &ipl_eckd_attr_group);
67187fd22e0SSven Schnelle break;
67299ca4e58SMichael Holzheu case IPL_TYPE_FCP:
67399ca4e58SMichael Holzheu case IPL_TYPE_FCP_DUMP:
67422d557abSSebastian Ott rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
67599ca4e58SMichael Holzheu break;
6763737e8eeSJason J. Herne case IPL_TYPE_NVME:
677d70e38cbSJason J. Herne case IPL_TYPE_NVME_DUMP:
6783737e8eeSJason J. Herne rc = sysfs_create_group(&ipl_kset->kobj, &ipl_nvme_attr_group);
6793737e8eeSJason J. Herne break;
68099ca4e58SMichael Holzheu default:
68199ca4e58SMichael Holzheu break;
68299ca4e58SMichael Holzheu }
68399ca4e58SMichael Holzheu out:
68499ca4e58SMichael Holzheu if (rc)
68599ca4e58SMichael Holzheu panic("ipl_init failed: rc = %i\n", rc);
68699ca4e58SMichael Holzheu
68799ca4e58SMichael Holzheu return 0;
68899ca4e58SMichael Holzheu }
68999ca4e58SMichael Holzheu
6902bc89b5eSHeiko Carstens static struct shutdown_action __refdata ipl_action = {
6912bc89b5eSHeiko Carstens .name = SHUTDOWN_ACTION_IPL_STR,
6922bc89b5eSHeiko Carstens .fn = ipl_run,
6932bc89b5eSHeiko Carstens .init = ipl_init,
6942bc89b5eSHeiko Carstens };
69599ca4e58SMichael Holzheu
696ff6b8ea6SMichael Holzheu /*
69799ca4e58SMichael Holzheu * reipl shutdown action: Reboot Linux on shutdown.
698ff6b8ea6SMichael Holzheu */
699ff6b8ea6SMichael Holzheu
700a0443fbbSHendrik Brueckner /* VM IPL PARM attributes */
reipl_generic_vmparm_show(struct ipl_parameter_block * ipb,char * page)701a0443fbbSHendrik Brueckner static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb,
702a0443fbbSHendrik Brueckner char *page)
703a0443fbbSHendrik Brueckner {
704a0443fbbSHendrik Brueckner char vmparm[DIAG308_VMPARM_SIZE + 1] = {};
705a0443fbbSHendrik Brueckner
70649698745SVasily Gorbik ipl_block_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb);
707a0443fbbSHendrik Brueckner return sprintf(page, "%s\n", vmparm);
708a0443fbbSHendrik Brueckner }
709a0443fbbSHendrik Brueckner
reipl_generic_vmparm_store(struct ipl_parameter_block * ipb,size_t vmparm_max,const char * buf,size_t len)710a0443fbbSHendrik Brueckner static ssize_t reipl_generic_vmparm_store(struct ipl_parameter_block *ipb,
711a0443fbbSHendrik Brueckner size_t vmparm_max,
712a0443fbbSHendrik Brueckner const char *buf, size_t len)
713a0443fbbSHendrik Brueckner {
714a0443fbbSHendrik Brueckner int i, ip_len;
715a0443fbbSHendrik Brueckner
716a0443fbbSHendrik Brueckner /* ignore trailing newline */
717a0443fbbSHendrik Brueckner ip_len = len;
718a0443fbbSHendrik Brueckner if ((len > 0) && (buf[len - 1] == '\n'))
719a0443fbbSHendrik Brueckner ip_len--;
720a0443fbbSHendrik Brueckner
721a0443fbbSHendrik Brueckner if (ip_len > vmparm_max)
722a0443fbbSHendrik Brueckner return -EINVAL;
723a0443fbbSHendrik Brueckner
724a0443fbbSHendrik Brueckner /* parm is used to store kernel options, check for common chars */
725a0443fbbSHendrik Brueckner for (i = 0; i < ip_len; i++)
726a0443fbbSHendrik Brueckner if (!(isalnum(buf[i]) || isascii(buf[i]) || isprint(buf[i])))
727a0443fbbSHendrik Brueckner return -EINVAL;
728a0443fbbSHendrik Brueckner
72986c74d86SMartin Schwidefsky memset(ipb->ccw.vm_parm, 0, DIAG308_VMPARM_SIZE);
73086c74d86SMartin Schwidefsky ipb->ccw.vm_parm_len = ip_len;
731a0443fbbSHendrik Brueckner if (ip_len > 0) {
7325f1207fbSMartin Schwidefsky ipb->ccw.vm_flags |= IPL_PB0_CCW_VM_FLAG_VP;
73386c74d86SMartin Schwidefsky memcpy(ipb->ccw.vm_parm, buf, ip_len);
73486c74d86SMartin Schwidefsky ASCEBC(ipb->ccw.vm_parm, ip_len);
735a0443fbbSHendrik Brueckner } else {
7365f1207fbSMartin Schwidefsky ipb->ccw.vm_flags &= ~IPL_PB0_CCW_VM_FLAG_VP;
737a0443fbbSHendrik Brueckner }
738a0443fbbSHendrik Brueckner
739a0443fbbSHendrik Brueckner return len;
740a0443fbbSHendrik Brueckner }
741a0443fbbSHendrik Brueckner
742a0443fbbSHendrik Brueckner /* NSS wrapper */
reipl_nss_vmparm_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)743a0443fbbSHendrik Brueckner static ssize_t reipl_nss_vmparm_show(struct kobject *kobj,
744a0443fbbSHendrik Brueckner struct kobj_attribute *attr, char *page)
745a0443fbbSHendrik Brueckner {
746a0443fbbSHendrik Brueckner return reipl_generic_vmparm_show(reipl_block_nss, page);
747a0443fbbSHendrik Brueckner }
748a0443fbbSHendrik Brueckner
reipl_nss_vmparm_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t len)749a0443fbbSHendrik Brueckner static ssize_t reipl_nss_vmparm_store(struct kobject *kobj,
750a0443fbbSHendrik Brueckner struct kobj_attribute *attr,
751a0443fbbSHendrik Brueckner const char *buf, size_t len)
752a0443fbbSHendrik Brueckner {
753a0443fbbSHendrik Brueckner return reipl_generic_vmparm_store(reipl_block_nss, 56, buf, len);
754a0443fbbSHendrik Brueckner }
755a0443fbbSHendrik Brueckner
756a0443fbbSHendrik Brueckner /* CCW wrapper */
reipl_ccw_vmparm_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)757a0443fbbSHendrik Brueckner static ssize_t reipl_ccw_vmparm_show(struct kobject *kobj,
758a0443fbbSHendrik Brueckner struct kobj_attribute *attr, char *page)
759a0443fbbSHendrik Brueckner {
760a0443fbbSHendrik Brueckner return reipl_generic_vmparm_show(reipl_block_ccw, page);
761a0443fbbSHendrik Brueckner }
762a0443fbbSHendrik Brueckner
reipl_ccw_vmparm_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t len)763a0443fbbSHendrik Brueckner static ssize_t reipl_ccw_vmparm_store(struct kobject *kobj,
764a0443fbbSHendrik Brueckner struct kobj_attribute *attr,
765a0443fbbSHendrik Brueckner const char *buf, size_t len)
766a0443fbbSHendrik Brueckner {
767a0443fbbSHendrik Brueckner return reipl_generic_vmparm_store(reipl_block_ccw, 64, buf, len);
768a0443fbbSHendrik Brueckner }
769a0443fbbSHendrik Brueckner
770a0443fbbSHendrik Brueckner static struct kobj_attribute sys_reipl_nss_vmparm_attr =
771a70f7276SSven Schnelle __ATTR(parm, 0644, reipl_nss_vmparm_show,
772a0443fbbSHendrik Brueckner reipl_nss_vmparm_store);
773a0443fbbSHendrik Brueckner static struct kobj_attribute sys_reipl_ccw_vmparm_attr =
774a70f7276SSven Schnelle __ATTR(parm, 0644, reipl_ccw_vmparm_show,
775a0443fbbSHendrik Brueckner reipl_ccw_vmparm_store);
776a0443fbbSHendrik Brueckner
777ff6b8ea6SMichael Holzheu /* FCP reipl device attributes */
778ff6b8ea6SMichael Holzheu
reipl_fcp_scpdata_read(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)7792c3c8beaSChris Wright static ssize_t reipl_fcp_scpdata_read(struct file *filp, struct kobject *kobj,
780684d2fd4SHendrik Brueckner struct bin_attribute *attr,
781684d2fd4SHendrik Brueckner char *buf, loff_t off, size_t count)
782684d2fd4SHendrik Brueckner {
78386c74d86SMartin Schwidefsky size_t size = reipl_block_fcp->fcp.scp_data_len;
78486c74d86SMartin Schwidefsky void *scp_data = reipl_block_fcp->fcp.scp_data;
785684d2fd4SHendrik Brueckner
786684d2fd4SHendrik Brueckner return memory_read_from_buffer(buf, count, &off, scp_data, size);
787684d2fd4SHendrik Brueckner }
788684d2fd4SHendrik Brueckner
reipl_fcp_scpdata_write(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)7892c3c8beaSChris Wright static ssize_t reipl_fcp_scpdata_write(struct file *filp, struct kobject *kobj,
790684d2fd4SHendrik Brueckner struct bin_attribute *attr,
791684d2fd4SHendrik Brueckner char *buf, loff_t off, size_t count)
792684d2fd4SHendrik Brueckner {
793e0bedadaSSebastian Ott size_t scpdata_len = count;
794684d2fd4SHendrik Brueckner size_t padding;
795684d2fd4SHendrik Brueckner
796e0bedadaSSebastian Ott
797e0bedadaSSebastian Ott if (off)
798684d2fd4SHendrik Brueckner return -EINVAL;
799684d2fd4SHendrik Brueckner
80086c74d86SMartin Schwidefsky memcpy(reipl_block_fcp->fcp.scp_data, buf, count);
801684d2fd4SHendrik Brueckner if (scpdata_len % 8) {
802684d2fd4SHendrik Brueckner padding = 8 - (scpdata_len % 8);
80386c74d86SMartin Schwidefsky memset(reipl_block_fcp->fcp.scp_data + scpdata_len,
804684d2fd4SHendrik Brueckner 0, padding);
805684d2fd4SHendrik Brueckner scpdata_len += padding;
806684d2fd4SHendrik Brueckner }
807684d2fd4SHendrik Brueckner
8085f1207fbSMartin Schwidefsky reipl_block_fcp->hdr.len = IPL_BP_FCP_LEN + scpdata_len;
8095f1207fbSMartin Schwidefsky reipl_block_fcp->fcp.len = IPL_BP0_FCP_LEN + scpdata_len;
81086c74d86SMartin Schwidefsky reipl_block_fcp->fcp.scp_data_len = scpdata_len;
811684d2fd4SHendrik Brueckner
812684d2fd4SHendrik Brueckner return count;
813684d2fd4SHendrik Brueckner }
81422d557abSSebastian Ott static struct bin_attribute sys_reipl_fcp_scp_data_attr =
815a70f7276SSven Schnelle __BIN_ATTR(scp_data, 0644, reipl_fcp_scpdata_read,
816e0bedadaSSebastian Ott reipl_fcp_scpdata_write, DIAG308_SCPDATA_SIZE);
817684d2fd4SHendrik Brueckner
81822d557abSSebastian Ott static struct bin_attribute *reipl_fcp_bin_attrs[] = {
81922d557abSSebastian Ott &sys_reipl_fcp_scp_data_attr,
82022d557abSSebastian Ott NULL,
821684d2fd4SHendrik Brueckner };
822684d2fd4SHendrik Brueckner
823eda4ddf7SMichael Holzheu DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%llx\n",
82486c74d86SMartin Schwidefsky reipl_block_fcp->fcp.wwpn);
825eda4ddf7SMichael Holzheu DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%llx\n",
82686c74d86SMartin Schwidefsky reipl_block_fcp->fcp.lun);
827ff6b8ea6SMichael Holzheu DEFINE_IPL_ATTR_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n",
82886c74d86SMartin Schwidefsky reipl_block_fcp->fcp.bootprog);
829ff6b8ea6SMichael Holzheu DEFINE_IPL_ATTR_RW(reipl_fcp, br_lba, "%lld\n", "%lld\n",
83086c74d86SMartin Schwidefsky reipl_block_fcp->fcp.br_lba);
831ff6b8ea6SMichael Holzheu DEFINE_IPL_ATTR_RW(reipl_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
83286c74d86SMartin Schwidefsky reipl_block_fcp->fcp.devno);
833ff6b8ea6SMichael Holzheu
reipl_get_ascii_loadparm(char * loadparm,struct ipl_parameter_block * ibp)834a0443fbbSHendrik Brueckner static void reipl_get_ascii_loadparm(char *loadparm,
835a0443fbbSHendrik Brueckner struct ipl_parameter_block *ibp)
83603a4d208SMichael Holzheu {
8375f1207fbSMartin Schwidefsky memcpy(loadparm, ibp->common.loadparm, LOADPARM_LEN);
83803a4d208SMichael Holzheu EBCASC(loadparm, LOADPARM_LEN);
83903a4d208SMichael Holzheu loadparm[LOADPARM_LEN] = 0;
8401d802e24SHeiko Carstens strim(loadparm);
84103a4d208SMichael Holzheu }
84203a4d208SMichael Holzheu
reipl_generic_loadparm_show(struct ipl_parameter_block * ipb,char * page)843a0443fbbSHendrik Brueckner static ssize_t reipl_generic_loadparm_show(struct ipl_parameter_block *ipb,
844a0443fbbSHendrik Brueckner char *page)
84503a4d208SMichael Holzheu {
84603a4d208SMichael Holzheu char buf[LOADPARM_LEN + 1];
84703a4d208SMichael Holzheu
848a0443fbbSHendrik Brueckner reipl_get_ascii_loadparm(buf, ipb);
84903a4d208SMichael Holzheu return sprintf(page, "%s\n", buf);
85003a4d208SMichael Holzheu }
85103a4d208SMichael Holzheu
reipl_generic_loadparm_store(struct ipl_parameter_block * ipb,const char * buf,size_t len)852a0443fbbSHendrik Brueckner static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb,
85303a4d208SMichael Holzheu const char *buf, size_t len)
85403a4d208SMichael Holzheu {
85503a4d208SMichael Holzheu int i, lp_len;
85603a4d208SMichael Holzheu
85703a4d208SMichael Holzheu /* ignore trailing newline */
85803a4d208SMichael Holzheu lp_len = len;
85903a4d208SMichael Holzheu if ((len > 0) && (buf[len - 1] == '\n'))
86003a4d208SMichael Holzheu lp_len--;
86103a4d208SMichael Holzheu /* loadparm can have max 8 characters and must not start with a blank */
86203a4d208SMichael Holzheu if ((lp_len > LOADPARM_LEN) || ((lp_len > 0) && (buf[0] == ' ')))
86303a4d208SMichael Holzheu return -EINVAL;
86403a4d208SMichael Holzheu /* loadparm can only contain "a-z,A-Z,0-9,SP,." */
86503a4d208SMichael Holzheu for (i = 0; i < lp_len; i++) {
86603a4d208SMichael Holzheu if (isalpha(buf[i]) || isdigit(buf[i]) || (buf[i] == ' ') ||
86703a4d208SMichael Holzheu (buf[i] == '.'))
86803a4d208SMichael Holzheu continue;
86903a4d208SMichael Holzheu return -EINVAL;
87003a4d208SMichael Holzheu }
87103a4d208SMichael Holzheu /* initialize loadparm with blanks */
8725f1207fbSMartin Schwidefsky memset(ipb->common.loadparm, ' ', LOADPARM_LEN);
87303a4d208SMichael Holzheu /* copy and convert to ebcdic */
8745f1207fbSMartin Schwidefsky memcpy(ipb->common.loadparm, buf, lp_len);
8755f1207fbSMartin Schwidefsky ASCEBC(ipb->common.loadparm, LOADPARM_LEN);
8765f1207fbSMartin Schwidefsky ipb->common.flags |= IPL_PB0_FLAG_LOADPARM;
87703a4d208SMichael Holzheu return len;
87803a4d208SMichael Holzheu }
87903a4d208SMichael Holzheu
880c676aac6SSven Schnelle #define DEFINE_GENERIC_LOADPARM(name) \
881c676aac6SSven Schnelle static ssize_t reipl_##name##_loadparm_show(struct kobject *kobj, \
882c676aac6SSven Schnelle struct kobj_attribute *attr, char *page) \
883c676aac6SSven Schnelle { \
884c676aac6SSven Schnelle return reipl_generic_loadparm_show(reipl_block_##name, page); \
885c676aac6SSven Schnelle } \
886c676aac6SSven Schnelle static ssize_t reipl_##name##_loadparm_store(struct kobject *kobj, \
887c676aac6SSven Schnelle struct kobj_attribute *attr, \
888c676aac6SSven Schnelle const char *buf, size_t len) \
889c676aac6SSven Schnelle { \
890c676aac6SSven Schnelle return reipl_generic_loadparm_store(reipl_block_##name, buf, len); \
891c676aac6SSven Schnelle } \
892c676aac6SSven Schnelle static struct kobj_attribute sys_reipl_##name##_loadparm_attr = \
893c676aac6SSven Schnelle __ATTR(loadparm, 0644, reipl_##name##_loadparm_show, \
894c676aac6SSven Schnelle reipl_##name##_loadparm_store)
89569928601SMichael Holzheu
896c676aac6SSven Schnelle DEFINE_GENERIC_LOADPARM(fcp);
897c676aac6SSven Schnelle DEFINE_GENERIC_LOADPARM(nvme);
898c676aac6SSven Schnelle DEFINE_GENERIC_LOADPARM(ccw);
899c676aac6SSven Schnelle DEFINE_GENERIC_LOADPARM(nss);
9006bb361d5SSven Schnelle DEFINE_GENERIC_LOADPARM(eckd);
90169928601SMichael Holzheu
reipl_fcp_clear_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)9021a2ae03bSGerald Schaefer static ssize_t reipl_fcp_clear_show(struct kobject *kobj,
9031a2ae03bSGerald Schaefer struct kobj_attribute *attr, char *page)
9041a2ae03bSGerald Schaefer {
9051a2ae03bSGerald Schaefer return sprintf(page, "%u\n", reipl_fcp_clear);
9061a2ae03bSGerald Schaefer }
9071a2ae03bSGerald Schaefer
reipl_fcp_clear_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t len)9081a2ae03bSGerald Schaefer static ssize_t reipl_fcp_clear_store(struct kobject *kobj,
9091a2ae03bSGerald Schaefer struct kobj_attribute *attr,
9101a2ae03bSGerald Schaefer const char *buf, size_t len)
9111a2ae03bSGerald Schaefer {
912d9b25bdfSChristophe JAILLET if (kstrtobool(buf, &reipl_fcp_clear) < 0)
9131a2ae03bSGerald Schaefer return -EINVAL;
9141a2ae03bSGerald Schaefer return len;
9151a2ae03bSGerald Schaefer }
9161a2ae03bSGerald Schaefer
91769928601SMichael Holzheu static struct attribute *reipl_fcp_attrs[] = {
91869928601SMichael Holzheu &sys_reipl_fcp_device_attr.attr,
91969928601SMichael Holzheu &sys_reipl_fcp_wwpn_attr.attr,
92069928601SMichael Holzheu &sys_reipl_fcp_lun_attr.attr,
92169928601SMichael Holzheu &sys_reipl_fcp_bootprog_attr.attr,
92269928601SMichael Holzheu &sys_reipl_fcp_br_lba_attr.attr,
92369928601SMichael Holzheu &sys_reipl_fcp_loadparm_attr.attr,
92469928601SMichael Holzheu NULL,
92569928601SMichael Holzheu };
92669928601SMichael Holzheu
92769928601SMichael Holzheu static struct attribute_group reipl_fcp_attr_group = {
92869928601SMichael Holzheu .attrs = reipl_fcp_attrs,
92922d557abSSebastian Ott .bin_attrs = reipl_fcp_bin_attrs,
93069928601SMichael Holzheu };
93169928601SMichael Holzheu
9321a2ae03bSGerald Schaefer static struct kobj_attribute sys_reipl_fcp_clear_attr =
9331a2ae03bSGerald Schaefer __ATTR(clear, 0644, reipl_fcp_clear_show, reipl_fcp_clear_store);
9341a2ae03bSGerald Schaefer
93523a457b8SJason J. Herne /* NVME reipl device attributes */
93623a457b8SJason J. Herne
reipl_nvme_scpdata_read(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)93723a457b8SJason J. Herne static ssize_t reipl_nvme_scpdata_read(struct file *filp, struct kobject *kobj,
93823a457b8SJason J. Herne struct bin_attribute *attr,
93923a457b8SJason J. Herne char *buf, loff_t off, size_t count)
94023a457b8SJason J. Herne {
94123a457b8SJason J. Herne size_t size = reipl_block_nvme->nvme.scp_data_len;
94223a457b8SJason J. Herne void *scp_data = reipl_block_nvme->nvme.scp_data;
94323a457b8SJason J. Herne
94423a457b8SJason J. Herne return memory_read_from_buffer(buf, count, &off, scp_data, size);
94523a457b8SJason J. Herne }
94623a457b8SJason J. Herne
reipl_nvme_scpdata_write(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)94723a457b8SJason J. Herne static ssize_t reipl_nvme_scpdata_write(struct file *filp, struct kobject *kobj,
94823a457b8SJason J. Herne struct bin_attribute *attr,
94923a457b8SJason J. Herne char *buf, loff_t off, size_t count)
95023a457b8SJason J. Herne {
95123a457b8SJason J. Herne size_t scpdata_len = count;
95223a457b8SJason J. Herne size_t padding;
95323a457b8SJason J. Herne
95423a457b8SJason J. Herne if (off)
95523a457b8SJason J. Herne return -EINVAL;
95623a457b8SJason J. Herne
95723a457b8SJason J. Herne memcpy(reipl_block_nvme->nvme.scp_data, buf, count);
95823a457b8SJason J. Herne if (scpdata_len % 8) {
95923a457b8SJason J. Herne padding = 8 - (scpdata_len % 8);
96023a457b8SJason J. Herne memset(reipl_block_nvme->nvme.scp_data + scpdata_len,
96123a457b8SJason J. Herne 0, padding);
96223a457b8SJason J. Herne scpdata_len += padding;
96323a457b8SJason J. Herne }
96423a457b8SJason J. Herne
965b34ea5b9SAlexander Egorenkov reipl_block_nvme->hdr.len = IPL_BP_NVME_LEN + scpdata_len;
966b34ea5b9SAlexander Egorenkov reipl_block_nvme->nvme.len = IPL_BP0_NVME_LEN + scpdata_len;
96723a457b8SJason J. Herne reipl_block_nvme->nvme.scp_data_len = scpdata_len;
96823a457b8SJason J. Herne
96923a457b8SJason J. Herne return count;
97023a457b8SJason J. Herne }
97123a457b8SJason J. Herne
97223a457b8SJason J. Herne static struct bin_attribute sys_reipl_nvme_scp_data_attr =
973a70f7276SSven Schnelle __BIN_ATTR(scp_data, 0644, reipl_nvme_scpdata_read,
97423a457b8SJason J. Herne reipl_nvme_scpdata_write, DIAG308_SCPDATA_SIZE);
97523a457b8SJason J. Herne
97623a457b8SJason J. Herne static struct bin_attribute *reipl_nvme_bin_attrs[] = {
97723a457b8SJason J. Herne &sys_reipl_nvme_scp_data_attr,
97823a457b8SJason J. Herne NULL,
97923a457b8SJason J. Herne };
98023a457b8SJason J. Herne
98123a457b8SJason J. Herne DEFINE_IPL_ATTR_RW(reipl_nvme, fid, "0x%08llx\n", "%llx\n",
98223a457b8SJason J. Herne reipl_block_nvme->nvme.fid);
98323a457b8SJason J. Herne DEFINE_IPL_ATTR_RW(reipl_nvme, nsid, "0x%08llx\n", "%llx\n",
98423a457b8SJason J. Herne reipl_block_nvme->nvme.nsid);
98523a457b8SJason J. Herne DEFINE_IPL_ATTR_RW(reipl_nvme, bootprog, "%lld\n", "%lld\n",
98623a457b8SJason J. Herne reipl_block_nvme->nvme.bootprog);
98723a457b8SJason J. Herne DEFINE_IPL_ATTR_RW(reipl_nvme, br_lba, "%lld\n", "%lld\n",
98823a457b8SJason J. Herne reipl_block_nvme->nvme.br_lba);
98923a457b8SJason J. Herne
99023a457b8SJason J. Herne static struct attribute *reipl_nvme_attrs[] = {
99123a457b8SJason J. Herne &sys_reipl_nvme_fid_attr.attr,
99223a457b8SJason J. Herne &sys_reipl_nvme_nsid_attr.attr,
99323a457b8SJason J. Herne &sys_reipl_nvme_bootprog_attr.attr,
99423a457b8SJason J. Herne &sys_reipl_nvme_br_lba_attr.attr,
99523a457b8SJason J. Herne &sys_reipl_nvme_loadparm_attr.attr,
99623a457b8SJason J. Herne NULL,
99723a457b8SJason J. Herne };
99823a457b8SJason J. Herne
99923a457b8SJason J. Herne static struct attribute_group reipl_nvme_attr_group = {
100023a457b8SJason J. Herne .attrs = reipl_nvme_attrs,
100123a457b8SJason J. Herne .bin_attrs = reipl_nvme_bin_attrs
100223a457b8SJason J. Herne };
100323a457b8SJason J. Herne
reipl_nvme_clear_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)10045627b922SGerald Schaefer static ssize_t reipl_nvme_clear_show(struct kobject *kobj,
10055627b922SGerald Schaefer struct kobj_attribute *attr, char *page)
10065627b922SGerald Schaefer {
10075627b922SGerald Schaefer return sprintf(page, "%u\n", reipl_nvme_clear);
10085627b922SGerald Schaefer }
10095627b922SGerald Schaefer
reipl_nvme_clear_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t len)10105627b922SGerald Schaefer static ssize_t reipl_nvme_clear_store(struct kobject *kobj,
10115627b922SGerald Schaefer struct kobj_attribute *attr,
10125627b922SGerald Schaefer const char *buf, size_t len)
10135627b922SGerald Schaefer {
1014d9b25bdfSChristophe JAILLET if (kstrtobool(buf, &reipl_nvme_clear) < 0)
10155627b922SGerald Schaefer return -EINVAL;
10165627b922SGerald Schaefer return len;
10175627b922SGerald Schaefer }
10185627b922SGerald Schaefer
10195627b922SGerald Schaefer static struct kobj_attribute sys_reipl_nvme_clear_attr =
10205627b922SGerald Schaefer __ATTR(clear, 0644, reipl_nvme_clear_show, reipl_nvme_clear_store);
10215627b922SGerald Schaefer
102269928601SMichael Holzheu /* CCW reipl device attributes */
102386c74d86SMartin Schwidefsky DEFINE_IPL_CCW_ATTR_RW(reipl_ccw, device, reipl_block_ccw->ccw);
102469928601SMichael Holzheu
reipl_ccw_clear_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)10251a2ae03bSGerald Schaefer static ssize_t reipl_ccw_clear_show(struct kobject *kobj,
10261a2ae03bSGerald Schaefer struct kobj_attribute *attr, char *page)
10271a2ae03bSGerald Schaefer {
10281a2ae03bSGerald Schaefer return sprintf(page, "%u\n", reipl_ccw_clear);
10291a2ae03bSGerald Schaefer }
10301a2ae03bSGerald Schaefer
reipl_ccw_clear_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t len)10311a2ae03bSGerald Schaefer static ssize_t reipl_ccw_clear_store(struct kobject *kobj,
10321a2ae03bSGerald Schaefer struct kobj_attribute *attr,
10331a2ae03bSGerald Schaefer const char *buf, size_t len)
10341a2ae03bSGerald Schaefer {
1035d9b25bdfSChristophe JAILLET if (kstrtobool(buf, &reipl_ccw_clear) < 0)
10361a2ae03bSGerald Schaefer return -EINVAL;
10371a2ae03bSGerald Schaefer return len;
10381a2ae03bSGerald Schaefer }
10391a2ae03bSGerald Schaefer
10401a2ae03bSGerald Schaefer static struct kobj_attribute sys_reipl_ccw_clear_attr =
10411a2ae03bSGerald Schaefer __ATTR(clear, 0644, reipl_ccw_clear_show, reipl_ccw_clear_store);
10421a2ae03bSGerald Schaefer
1043a0443fbbSHendrik Brueckner static struct attribute *reipl_ccw_attrs_vm[] = {
1044a0443fbbSHendrik Brueckner &sys_reipl_ccw_device_attr.attr,
1045a0443fbbSHendrik Brueckner &sys_reipl_ccw_loadparm_attr.attr,
1046a0443fbbSHendrik Brueckner &sys_reipl_ccw_vmparm_attr.attr,
10471a2ae03bSGerald Schaefer &sys_reipl_ccw_clear_attr.attr,
1048a0443fbbSHendrik Brueckner NULL,
1049a0443fbbSHendrik Brueckner };
1050a0443fbbSHendrik Brueckner
1051a0443fbbSHendrik Brueckner static struct attribute *reipl_ccw_attrs_lpar[] = {
1052ff6b8ea6SMichael Holzheu &sys_reipl_ccw_device_attr.attr,
105303a4d208SMichael Holzheu &sys_reipl_ccw_loadparm_attr.attr,
10541a2ae03bSGerald Schaefer &sys_reipl_ccw_clear_attr.attr,
1055ff6b8ea6SMichael Holzheu NULL,
1056ff6b8ea6SMichael Holzheu };
1057ff6b8ea6SMichael Holzheu
1058a0443fbbSHendrik Brueckner static struct attribute_group reipl_ccw_attr_group_vm = {
1059ff6b8ea6SMichael Holzheu .name = IPL_CCW_STR,
1060a0443fbbSHendrik Brueckner .attrs = reipl_ccw_attrs_vm,
1061a0443fbbSHendrik Brueckner };
1062a0443fbbSHendrik Brueckner
1063a0443fbbSHendrik Brueckner static struct attribute_group reipl_ccw_attr_group_lpar = {
1064a0443fbbSHendrik Brueckner .name = IPL_CCW_STR,
1065a0443fbbSHendrik Brueckner .attrs = reipl_ccw_attrs_lpar,
1066ff6b8ea6SMichael Holzheu };
1067ff6b8ea6SMichael Holzheu
106887fd22e0SSven Schnelle /* ECKD reipl device attributes */
106987fd22e0SSven Schnelle
reipl_eckd_scpdata_read(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)107087fd22e0SSven Schnelle static ssize_t reipl_eckd_scpdata_read(struct file *filp, struct kobject *kobj,
107187fd22e0SSven Schnelle struct bin_attribute *attr,
107287fd22e0SSven Schnelle char *buf, loff_t off, size_t count)
107387fd22e0SSven Schnelle {
107487fd22e0SSven Schnelle size_t size = reipl_block_eckd->eckd.scp_data_len;
107587fd22e0SSven Schnelle void *scp_data = reipl_block_eckd->eckd.scp_data;
107687fd22e0SSven Schnelle
107787fd22e0SSven Schnelle return memory_read_from_buffer(buf, count, &off, scp_data, size);
107887fd22e0SSven Schnelle }
107987fd22e0SSven Schnelle
reipl_eckd_scpdata_write(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)108087fd22e0SSven Schnelle static ssize_t reipl_eckd_scpdata_write(struct file *filp, struct kobject *kobj,
108187fd22e0SSven Schnelle struct bin_attribute *attr,
108287fd22e0SSven Schnelle char *buf, loff_t off, size_t count)
108387fd22e0SSven Schnelle {
108487fd22e0SSven Schnelle size_t scpdata_len = count;
108587fd22e0SSven Schnelle size_t padding;
108687fd22e0SSven Schnelle
108787fd22e0SSven Schnelle if (off)
108887fd22e0SSven Schnelle return -EINVAL;
108987fd22e0SSven Schnelle
109087fd22e0SSven Schnelle memcpy(reipl_block_eckd->eckd.scp_data, buf, count);
109187fd22e0SSven Schnelle if (scpdata_len % 8) {
109287fd22e0SSven Schnelle padding = 8 - (scpdata_len % 8);
109387fd22e0SSven Schnelle memset(reipl_block_eckd->eckd.scp_data + scpdata_len,
109487fd22e0SSven Schnelle 0, padding);
109587fd22e0SSven Schnelle scpdata_len += padding;
109687fd22e0SSven Schnelle }
109787fd22e0SSven Schnelle
109887fd22e0SSven Schnelle reipl_block_eckd->hdr.len = IPL_BP_ECKD_LEN + scpdata_len;
109987fd22e0SSven Schnelle reipl_block_eckd->eckd.len = IPL_BP0_ECKD_LEN + scpdata_len;
110087fd22e0SSven Schnelle reipl_block_eckd->eckd.scp_data_len = scpdata_len;
110187fd22e0SSven Schnelle
110287fd22e0SSven Schnelle return count;
110387fd22e0SSven Schnelle }
110487fd22e0SSven Schnelle
110587fd22e0SSven Schnelle static struct bin_attribute sys_reipl_eckd_scp_data_attr =
1106a70f7276SSven Schnelle __BIN_ATTR(scp_data, 0644, reipl_eckd_scpdata_read,
110787fd22e0SSven Schnelle reipl_eckd_scpdata_write, DIAG308_SCPDATA_SIZE);
110887fd22e0SSven Schnelle
110987fd22e0SSven Schnelle static struct bin_attribute *reipl_eckd_bin_attrs[] = {
111087fd22e0SSven Schnelle &sys_reipl_eckd_scp_data_attr,
111187fd22e0SSven Schnelle NULL,
111287fd22e0SSven Schnelle };
111387fd22e0SSven Schnelle
111487fd22e0SSven Schnelle DEFINE_IPL_CCW_ATTR_RW(reipl_eckd, device, reipl_block_eckd->eckd);
111587fd22e0SSven Schnelle DEFINE_IPL_ATTR_RW(reipl_eckd, bootprog, "%lld\n", "%lld\n",
111687fd22e0SSven Schnelle reipl_block_eckd->eckd.bootprog);
111787fd22e0SSven Schnelle
111887fd22e0SSven Schnelle static struct attribute *reipl_eckd_attrs[] = {
111987fd22e0SSven Schnelle &sys_reipl_eckd_device_attr.attr,
112087fd22e0SSven Schnelle &sys_reipl_eckd_bootprog_attr.attr,
112187fd22e0SSven Schnelle &sys_reipl_eckd_br_chr_attr.attr,
11226bb361d5SSven Schnelle &sys_reipl_eckd_loadparm_attr.attr,
112387fd22e0SSven Schnelle NULL,
112487fd22e0SSven Schnelle };
112587fd22e0SSven Schnelle
112687fd22e0SSven Schnelle static struct attribute_group reipl_eckd_attr_group = {
112787fd22e0SSven Schnelle .attrs = reipl_eckd_attrs,
112887fd22e0SSven Schnelle .bin_attrs = reipl_eckd_bin_attrs
112987fd22e0SSven Schnelle };
113087fd22e0SSven Schnelle
reipl_eckd_clear_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)113187fd22e0SSven Schnelle static ssize_t reipl_eckd_clear_show(struct kobject *kobj,
113287fd22e0SSven Schnelle struct kobj_attribute *attr, char *page)
113387fd22e0SSven Schnelle {
113487fd22e0SSven Schnelle return sprintf(page, "%u\n", reipl_eckd_clear);
113587fd22e0SSven Schnelle }
113687fd22e0SSven Schnelle
reipl_eckd_clear_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t len)113787fd22e0SSven Schnelle static ssize_t reipl_eckd_clear_store(struct kobject *kobj,
113887fd22e0SSven Schnelle struct kobj_attribute *attr,
113987fd22e0SSven Schnelle const char *buf, size_t len)
114087fd22e0SSven Schnelle {
1141c3130944SChristophe JAILLET if (kstrtobool(buf, &reipl_eckd_clear) < 0)
114287fd22e0SSven Schnelle return -EINVAL;
114387fd22e0SSven Schnelle return len;
114487fd22e0SSven Schnelle }
114587fd22e0SSven Schnelle
114687fd22e0SSven Schnelle static struct kobj_attribute sys_reipl_eckd_clear_attr =
114787fd22e0SSven Schnelle __ATTR(clear, 0644, reipl_eckd_clear_show, reipl_eckd_clear_store);
1148fe355b7fSHongjie Yang
1149fe355b7fSHongjie Yang /* NSS reipl device attributes */
reipl_get_ascii_nss_name(char * dst,struct ipl_parameter_block * ipb)1150a0443fbbSHendrik Brueckner static void reipl_get_ascii_nss_name(char *dst,
1151a0443fbbSHendrik Brueckner struct ipl_parameter_block *ipb)
1152a0443fbbSHendrik Brueckner {
115386c74d86SMartin Schwidefsky memcpy(dst, ipb->ccw.nss_name, NSS_NAME_SIZE);
1154a0443fbbSHendrik Brueckner EBCASC(dst, NSS_NAME_SIZE);
1155a0443fbbSHendrik Brueckner dst[NSS_NAME_SIZE] = 0;
1156a0443fbbSHendrik Brueckner }
1157fe355b7fSHongjie Yang
reipl_nss_name_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)1158a0443fbbSHendrik Brueckner static ssize_t reipl_nss_name_show(struct kobject *kobj,
1159a0443fbbSHendrik Brueckner struct kobj_attribute *attr, char *page)
1160a0443fbbSHendrik Brueckner {
1161a0443fbbSHendrik Brueckner char nss_name[NSS_NAME_SIZE + 1] = {};
1162a0443fbbSHendrik Brueckner
1163a0443fbbSHendrik Brueckner reipl_get_ascii_nss_name(nss_name, reipl_block_nss);
1164a0443fbbSHendrik Brueckner return sprintf(page, "%s\n", nss_name);
1165a0443fbbSHendrik Brueckner }
1166a0443fbbSHendrik Brueckner
reipl_nss_name_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t len)1167a0443fbbSHendrik Brueckner static ssize_t reipl_nss_name_store(struct kobject *kobj,
1168a0443fbbSHendrik Brueckner struct kobj_attribute *attr,
1169a0443fbbSHendrik Brueckner const char *buf, size_t len)
1170a0443fbbSHendrik Brueckner {
1171a0443fbbSHendrik Brueckner int nss_len;
1172a0443fbbSHendrik Brueckner
1173a0443fbbSHendrik Brueckner /* ignore trailing newline */
1174a0443fbbSHendrik Brueckner nss_len = len;
1175a0443fbbSHendrik Brueckner if ((len > 0) && (buf[len - 1] == '\n'))
1176a0443fbbSHendrik Brueckner nss_len--;
1177a0443fbbSHendrik Brueckner
1178a0443fbbSHendrik Brueckner if (nss_len > NSS_NAME_SIZE)
1179a0443fbbSHendrik Brueckner return -EINVAL;
1180a0443fbbSHendrik Brueckner
118186c74d86SMartin Schwidefsky memset(reipl_block_nss->ccw.nss_name, 0x40, NSS_NAME_SIZE);
1182a0443fbbSHendrik Brueckner if (nss_len > 0) {
11835f1207fbSMartin Schwidefsky reipl_block_nss->ccw.vm_flags |= IPL_PB0_CCW_VM_FLAG_NSS;
118486c74d86SMartin Schwidefsky memcpy(reipl_block_nss->ccw.nss_name, buf, nss_len);
118586c74d86SMartin Schwidefsky ASCEBC(reipl_block_nss->ccw.nss_name, nss_len);
118686c74d86SMartin Schwidefsky EBC_TOUPPER(reipl_block_nss->ccw.nss_name, nss_len);
1187a0443fbbSHendrik Brueckner } else {
11885f1207fbSMartin Schwidefsky reipl_block_nss->ccw.vm_flags &= ~IPL_PB0_CCW_VM_FLAG_NSS;
1189a0443fbbSHendrik Brueckner }
1190a0443fbbSHendrik Brueckner
1191a0443fbbSHendrik Brueckner return len;
1192a0443fbbSHendrik Brueckner }
1193a0443fbbSHendrik Brueckner
1194a0443fbbSHendrik Brueckner static struct kobj_attribute sys_reipl_nss_name_attr =
1195a70f7276SSven Schnelle __ATTR(name, 0644, reipl_nss_name_show,
1196a0443fbbSHendrik Brueckner reipl_nss_name_store);
1197a0443fbbSHendrik Brueckner
1198fe355b7fSHongjie Yang static struct attribute *reipl_nss_attrs[] = {
1199fe355b7fSHongjie Yang &sys_reipl_nss_name_attr.attr,
1200a0443fbbSHendrik Brueckner &sys_reipl_nss_loadparm_attr.attr,
1201a0443fbbSHendrik Brueckner &sys_reipl_nss_vmparm_attr.attr,
1202fe355b7fSHongjie Yang NULL,
1203fe355b7fSHongjie Yang };
1204fe355b7fSHongjie Yang
1205fe355b7fSHongjie Yang static struct attribute_group reipl_nss_attr_group = {
1206fe355b7fSHongjie Yang .name = IPL_NSS_STR,
1207fe355b7fSHongjie Yang .attrs = reipl_nss_attrs,
1208fe355b7fSHongjie Yang };
1209fe355b7fSHongjie Yang
set_os_info_reipl_block(void)12103b967847SVasily Gorbik void set_os_info_reipl_block(void)
12114857d4bbSMichael Holzheu {
12124857d4bbSMichael Holzheu os_info_entry_add(OS_INFO_REIPL_BLOCK, reipl_block_actual,
12133b967847SVasily Gorbik reipl_block_actual->hdr.len);
12144857d4bbSMichael Holzheu }
12154857d4bbSMichael Holzheu
1216ff6b8ea6SMichael Holzheu /* reipl type */
1217ff6b8ea6SMichael Holzheu
reipl_set_type(enum ipl_type type)1218ff6b8ea6SMichael Holzheu static int reipl_set_type(enum ipl_type type)
1219ff6b8ea6SMichael Holzheu {
1220ff6b8ea6SMichael Holzheu if (!(reipl_capabilities & type))
1221ff6b8ea6SMichael Holzheu return -EINVAL;
1222ff6b8ea6SMichael Holzheu
1223ff6b8ea6SMichael Holzheu switch(type) {
1224ff6b8ea6SMichael Holzheu case IPL_TYPE_CCW:
12253b967847SVasily Gorbik reipl_block_actual = reipl_block_ccw;
1226ff6b8ea6SMichael Holzheu break;
122787fd22e0SSven Schnelle case IPL_TYPE_ECKD:
122887fd22e0SSven Schnelle reipl_block_actual = reipl_block_eckd;
122987fd22e0SSven Schnelle break;
1230ff6b8ea6SMichael Holzheu case IPL_TYPE_FCP:
12313b967847SVasily Gorbik reipl_block_actual = reipl_block_fcp;
1232411ed322SMichael Holzheu break;
123323a457b8SJason J. Herne case IPL_TYPE_NVME:
123423a457b8SJason J. Herne reipl_block_actual = reipl_block_nvme;
123523a457b8SJason J. Herne break;
1236fe355b7fSHongjie Yang case IPL_TYPE_NSS:
12373b967847SVasily Gorbik reipl_block_actual = reipl_block_nss;
1238411ed322SMichael Holzheu break;
1239ff6b8ea6SMichael Holzheu default:
124096c0cdbcSVasily Gorbik break;
1241ff6b8ea6SMichael Holzheu }
1242ff6b8ea6SMichael Holzheu reipl_type = type;
1243ff6b8ea6SMichael Holzheu return 0;
1244ff6b8ea6SMichael Holzheu }
1245ff6b8ea6SMichael Holzheu
reipl_type_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)12469b949165SGreg Kroah-Hartman static ssize_t reipl_type_show(struct kobject *kobj,
12479b949165SGreg Kroah-Hartman struct kobj_attribute *attr, char *page)
1248ff6b8ea6SMichael Holzheu {
1249ff6b8ea6SMichael Holzheu return sprintf(page, "%s\n", ipl_type_str(reipl_type));
1250ff6b8ea6SMichael Holzheu }
1251ff6b8ea6SMichael Holzheu
reipl_type_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t len)12529b949165SGreg Kroah-Hartman static ssize_t reipl_type_store(struct kobject *kobj,
12539b949165SGreg Kroah-Hartman struct kobj_attribute *attr,
12549b949165SGreg Kroah-Hartman const char *buf, size_t len)
1255ff6b8ea6SMichael Holzheu {
1256ff6b8ea6SMichael Holzheu int rc = -EINVAL;
1257ff6b8ea6SMichael Holzheu
1258ff6b8ea6SMichael Holzheu if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
1259ff6b8ea6SMichael Holzheu rc = reipl_set_type(IPL_TYPE_CCW);
126087fd22e0SSven Schnelle else if (strncmp(buf, IPL_ECKD_STR, strlen(IPL_ECKD_STR)) == 0)
126187fd22e0SSven Schnelle rc = reipl_set_type(IPL_TYPE_ECKD);
1262ff6b8ea6SMichael Holzheu else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
1263ff6b8ea6SMichael Holzheu rc = reipl_set_type(IPL_TYPE_FCP);
126423a457b8SJason J. Herne else if (strncmp(buf, IPL_NVME_STR, strlen(IPL_NVME_STR)) == 0)
126523a457b8SJason J. Herne rc = reipl_set_type(IPL_TYPE_NVME);
1266fe355b7fSHongjie Yang else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0)
1267fe355b7fSHongjie Yang rc = reipl_set_type(IPL_TYPE_NSS);
1268ff6b8ea6SMichael Holzheu return (rc != 0) ? rc : len;
1269ff6b8ea6SMichael Holzheu }
1270ff6b8ea6SMichael Holzheu
12719b949165SGreg Kroah-Hartman static struct kobj_attribute reipl_type_attr =
1272ff6b8ea6SMichael Holzheu __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
1273ff6b8ea6SMichael Holzheu
1274d91885beSGreg Kroah-Hartman static struct kset *reipl_kset;
1275684d2fd4SHendrik Brueckner static struct kset *reipl_fcp_kset;
127623a457b8SJason J. Herne static struct kset *reipl_nvme_kset;
127787fd22e0SSven Schnelle static struct kset *reipl_eckd_kset;
1278ff6b8ea6SMichael Holzheu
__reipl_run(void * unused)12792c2df118SHeiko Carstens static void __reipl_run(void *unused)
1280ff6b8ea6SMichael Holzheu {
128196c0cdbcSVasily Gorbik switch (reipl_type) {
128296c0cdbcSVasily Gorbik case IPL_TYPE_CCW:
1283ff6b8ea6SMichael Holzheu diag308(DIAG308_SET, reipl_block_ccw);
12841a2ae03bSGerald Schaefer if (reipl_ccw_clear)
12850599eeadSHeiko Carstens diag308(DIAG308_LOAD_CLEAR, NULL);
12861a2ae03bSGerald Schaefer else
12871a2ae03bSGerald Schaefer diag308(DIAG308_LOAD_NORMAL_DUMP, NULL);
1288ff6b8ea6SMichael Holzheu break;
128987fd22e0SSven Schnelle case IPL_TYPE_ECKD:
129087fd22e0SSven Schnelle diag308(DIAG308_SET, reipl_block_eckd);
129187fd22e0SSven Schnelle if (reipl_eckd_clear)
129287fd22e0SSven Schnelle diag308(DIAG308_LOAD_CLEAR, NULL);
129387fd22e0SSven Schnelle else
129487fd22e0SSven Schnelle diag308(DIAG308_LOAD_NORMAL, NULL);
129587fd22e0SSven Schnelle break;
129696c0cdbcSVasily Gorbik case IPL_TYPE_FCP:
1297ff6b8ea6SMichael Holzheu diag308(DIAG308_SET, reipl_block_fcp);
12981a2ae03bSGerald Schaefer if (reipl_fcp_clear)
12990599eeadSHeiko Carstens diag308(DIAG308_LOAD_CLEAR, NULL);
13001a2ae03bSGerald Schaefer else
13011a2ae03bSGerald Schaefer diag308(DIAG308_LOAD_NORMAL, NULL);
1302ff6b8ea6SMichael Holzheu break;
130323a457b8SJason J. Herne case IPL_TYPE_NVME:
130423a457b8SJason J. Herne diag308(DIAG308_SET, reipl_block_nvme);
13055627b922SGerald Schaefer if (reipl_nvme_clear)
130623a457b8SJason J. Herne diag308(DIAG308_LOAD_CLEAR, NULL);
13075627b922SGerald Schaefer else
13085627b922SGerald Schaefer diag308(DIAG308_LOAD_NORMAL, NULL);
130923a457b8SJason J. Herne break;
131096c0cdbcSVasily Gorbik case IPL_TYPE_NSS:
1311a0443fbbSHendrik Brueckner diag308(DIAG308_SET, reipl_block_nss);
13120599eeadSHeiko Carstens diag308(DIAG308_LOAD_CLEAR, NULL);
1313a0443fbbSHendrik Brueckner break;
131496c0cdbcSVasily Gorbik case IPL_TYPE_UNKNOWN:
13150599eeadSHeiko Carstens diag308(DIAG308_LOAD_CLEAR, NULL);
1316ff6b8ea6SMichael Holzheu break;
131796c0cdbcSVasily Gorbik case IPL_TYPE_FCP_DUMP:
1318d70e38cbSJason J. Herne case IPL_TYPE_NVME_DUMP:
1319e2d2a296SSven Schnelle case IPL_TYPE_ECKD_DUMP:
1320411ed322SMichael Holzheu break;
1321ff6b8ea6SMichael Holzheu }
132298587c2dSMartin Schwidefsky disabled_wait();
1323ff6b8ea6SMichael Holzheu }
1324ff6b8ea6SMichael Holzheu
reipl_run(struct shutdown_trigger * trigger)13252c2df118SHeiko Carstens static void reipl_run(struct shutdown_trigger *trigger)
13262c2df118SHeiko Carstens {
13278b646bd7SMartin Schwidefsky smp_call_ipl_cpu(__reipl_run, NULL);
13282c2df118SHeiko Carstens }
13292c2df118SHeiko Carstens
reipl_block_ccw_init(struct ipl_parameter_block * ipb)1330a0443fbbSHendrik Brueckner static void reipl_block_ccw_init(struct ipl_parameter_block *ipb)
1331ff6b8ea6SMichael Holzheu {
13325f1207fbSMartin Schwidefsky ipb->hdr.len = IPL_BP_CCW_LEN;
1333a0443fbbSHendrik Brueckner ipb->hdr.version = IPL_PARM_BLOCK_VERSION;
13345f1207fbSMartin Schwidefsky ipb->pb0_hdr.len = IPL_BP0_CCW_LEN;
13355f1207fbSMartin Schwidefsky ipb->pb0_hdr.pbt = IPL_PBT_CCW;
1336a0443fbbSHendrik Brueckner }
1337ff6b8ea6SMichael Holzheu
reipl_block_ccw_fill_parms(struct ipl_parameter_block * ipb)1338a0443fbbSHendrik Brueckner static void reipl_block_ccw_fill_parms(struct ipl_parameter_block *ipb)
1339a0443fbbSHendrik Brueckner {
1340a0443fbbSHendrik Brueckner /* LOADPARM */
1341a0443fbbSHendrik Brueckner /* check if read scp info worked and set loadparm */
1342a0443fbbSHendrik Brueckner if (sclp_ipl_info.is_valid)
13435f1207fbSMartin Schwidefsky memcpy(ipb->ccw.loadparm, &sclp_ipl_info.loadparm, LOADPARM_LEN);
1344a0443fbbSHendrik Brueckner else
1345a0443fbbSHendrik Brueckner /* read scp info failed: set empty loadparm (EBCDIC blanks) */
13465f1207fbSMartin Schwidefsky memset(ipb->ccw.loadparm, 0x40, LOADPARM_LEN);
13475f1207fbSMartin Schwidefsky ipb->ccw.flags = IPL_PB0_FLAG_LOADPARM;
1348a0443fbbSHendrik Brueckner
1349a0443fbbSHendrik Brueckner /* VM PARM */
1350a0832b3aSVasily Gorbik if (MACHINE_IS_VM && ipl_block_valid &&
13515f1207fbSMartin Schwidefsky (ipl_block.ccw.vm_flags & IPL_PB0_CCW_VM_FLAG_VP)) {
1352a0443fbbSHendrik Brueckner
13535f1207fbSMartin Schwidefsky ipb->ccw.vm_flags |= IPL_PB0_CCW_VM_FLAG_VP;
135486c74d86SMartin Schwidefsky ipb->ccw.vm_parm_len = ipl_block.ccw.vm_parm_len;
135586c74d86SMartin Schwidefsky memcpy(ipb->ccw.vm_parm,
135686c74d86SMartin Schwidefsky ipl_block.ccw.vm_parm, DIAG308_VMPARM_SIZE);
1357a0443fbbSHendrik Brueckner }
1358ff6b8ea6SMichael Holzheu }
1359ff6b8ea6SMichael Holzheu
reipl_nss_init(void)1360fe355b7fSHongjie Yang static int __init reipl_nss_init(void)
1361fe355b7fSHongjie Yang {
1362fe355b7fSHongjie Yang int rc;
1363fe355b7fSHongjie Yang
1364fe355b7fSHongjie Yang if (!MACHINE_IS_VM)
1365fe355b7fSHongjie Yang return 0;
1366a0443fbbSHendrik Brueckner
1367a0443fbbSHendrik Brueckner reipl_block_nss = (void *) get_zeroed_page(GFP_KERNEL);
1368a0443fbbSHendrik Brueckner if (!reipl_block_nss)
1369a0443fbbSHendrik Brueckner return -ENOMEM;
1370a0443fbbSHendrik Brueckner
1371d91885beSGreg Kroah-Hartman rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group);
1372fe355b7fSHongjie Yang if (rc)
1373fe355b7fSHongjie Yang return rc;
1374a0443fbbSHendrik Brueckner
1375a0443fbbSHendrik Brueckner reipl_block_ccw_init(reipl_block_nss);
1376fe355b7fSHongjie Yang reipl_capabilities |= IPL_TYPE_NSS;
1377fe355b7fSHongjie Yang return 0;
1378fe355b7fSHongjie Yang }
1379fe355b7fSHongjie Yang
reipl_ccw_init(void)1380ff6b8ea6SMichael Holzheu static int __init reipl_ccw_init(void)
1381ff6b8ea6SMichael Holzheu {
1382ff6b8ea6SMichael Holzheu int rc;
1383ff6b8ea6SMichael Holzheu
1384ff6b8ea6SMichael Holzheu reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
1385ff6b8ea6SMichael Holzheu if (!reipl_block_ccw)
1386ff6b8ea6SMichael Holzheu return -ENOMEM;
1387a0443fbbSHendrik Brueckner
1388a0443fbbSHendrik Brueckner rc = sysfs_create_group(&reipl_kset->kobj,
1389d485235bSVasily Gorbik MACHINE_IS_VM ? &reipl_ccw_attr_group_vm
1390d485235bSVasily Gorbik : &reipl_ccw_attr_group_lpar);
1391a0443fbbSHendrik Brueckner if (rc)
1392a0443fbbSHendrik Brueckner return rc;
1393a0443fbbSHendrik Brueckner
1394a0443fbbSHendrik Brueckner reipl_block_ccw_init(reipl_block_ccw);
1395a0443fbbSHendrik Brueckner if (ipl_info.type == IPL_TYPE_CCW) {
139686c74d86SMartin Schwidefsky reipl_block_ccw->ccw.ssid = ipl_block.ccw.ssid;
139786c74d86SMartin Schwidefsky reipl_block_ccw->ccw.devno = ipl_block.ccw.devno;
1398a0443fbbSHendrik Brueckner reipl_block_ccw_fill_parms(reipl_block_ccw);
1399a0443fbbSHendrik Brueckner }
1400a0443fbbSHendrik Brueckner
1401ff6b8ea6SMichael Holzheu reipl_capabilities |= IPL_TYPE_CCW;
1402ff6b8ea6SMichael Holzheu return 0;
1403ff6b8ea6SMichael Holzheu }
1404ff6b8ea6SMichael Holzheu
reipl_fcp_init(void)1405ff6b8ea6SMichael Holzheu static int __init reipl_fcp_init(void)
1406ff6b8ea6SMichael Holzheu {
1407ff6b8ea6SMichael Holzheu int rc;
1408ff6b8ea6SMichael Holzheu
1409ff6b8ea6SMichael Holzheu reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
1410ff6b8ea6SMichael Holzheu if (!reipl_block_fcp)
1411ff6b8ea6SMichael Holzheu return -ENOMEM;
1412684d2fd4SHendrik Brueckner
1413684d2fd4SHendrik Brueckner /* sysfs: create fcp kset for mixing attr group and bin attrs */
1414684d2fd4SHendrik Brueckner reipl_fcp_kset = kset_create_and_add(IPL_FCP_STR, NULL,
1415684d2fd4SHendrik Brueckner &reipl_kset->kobj);
1416798620fbSJulia Lawall if (!reipl_fcp_kset) {
1417684d2fd4SHendrik Brueckner free_page((unsigned long) reipl_block_fcp);
1418684d2fd4SHendrik Brueckner return -ENOMEM;
1419684d2fd4SHendrik Brueckner }
1420684d2fd4SHendrik Brueckner
1421684d2fd4SHendrik Brueckner rc = sysfs_create_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group);
14221a2ae03bSGerald Schaefer if (rc)
14231a2ae03bSGerald Schaefer goto out1;
14241a2ae03bSGerald Schaefer
14251a2ae03bSGerald Schaefer if (test_facility(141)) {
14261a2ae03bSGerald Schaefer rc = sysfs_create_file(&reipl_fcp_kset->kobj,
14271a2ae03bSGerald Schaefer &sys_reipl_fcp_clear_attr.attr);
14281a2ae03bSGerald Schaefer if (rc)
14291a2ae03bSGerald Schaefer goto out2;
14305627b922SGerald Schaefer } else {
14311a2ae03bSGerald Schaefer reipl_fcp_clear = true;
14325627b922SGerald Schaefer }
1433684d2fd4SHendrik Brueckner
143469928601SMichael Holzheu if (ipl_info.type == IPL_TYPE_FCP) {
1435bdbfe185SVasily Gorbik memcpy(reipl_block_fcp, &ipl_block, sizeof(ipl_block));
143669928601SMichael Holzheu /*
143769928601SMichael Holzheu * Fix loadparm: There are systems where the (SCSI) LOADPARM
143869928601SMichael Holzheu * is invalid in the SCSI IPL parameter block, so take it
143969928601SMichael Holzheu * always from sclp_ipl_info.
144069928601SMichael Holzheu */
14415f1207fbSMartin Schwidefsky memcpy(reipl_block_fcp->fcp.loadparm, sclp_ipl_info.loadparm,
144269928601SMichael Holzheu LOADPARM_LEN);
144369928601SMichael Holzheu } else {
14445f1207fbSMartin Schwidefsky reipl_block_fcp->hdr.len = IPL_BP_FCP_LEN;
1445ff6b8ea6SMichael Holzheu reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
14465f1207fbSMartin Schwidefsky reipl_block_fcp->fcp.len = IPL_BP0_FCP_LEN;
14475f1207fbSMartin Schwidefsky reipl_block_fcp->fcp.pbt = IPL_PBT_FCP;
14485f1207fbSMartin Schwidefsky reipl_block_fcp->fcp.opt = IPL_PB0_FCP_OPT_IPL;
1449ff6b8ea6SMichael Holzheu }
1450ff6b8ea6SMichael Holzheu reipl_capabilities |= IPL_TYPE_FCP;
1451ff6b8ea6SMichael Holzheu return 0;
14521a2ae03bSGerald Schaefer
14531a2ae03bSGerald Schaefer out2:
14541a2ae03bSGerald Schaefer sysfs_remove_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group);
14551a2ae03bSGerald Schaefer out1:
14561a2ae03bSGerald Schaefer kset_unregister(reipl_fcp_kset);
14571a2ae03bSGerald Schaefer free_page((unsigned long) reipl_block_fcp);
14581a2ae03bSGerald Schaefer return rc;
1459ff6b8ea6SMichael Holzheu }
1460ff6b8ea6SMichael Holzheu
reipl_nvme_init(void)146123a457b8SJason J. Herne static int __init reipl_nvme_init(void)
146223a457b8SJason J. Herne {
146323a457b8SJason J. Herne int rc;
146423a457b8SJason J. Herne
146523a457b8SJason J. Herne reipl_block_nvme = (void *) get_zeroed_page(GFP_KERNEL);
146623a457b8SJason J. Herne if (!reipl_block_nvme)
146723a457b8SJason J. Herne return -ENOMEM;
146823a457b8SJason J. Herne
146923a457b8SJason J. Herne /* sysfs: create kset for mixing attr group and bin attrs */
147023a457b8SJason J. Herne reipl_nvme_kset = kset_create_and_add(IPL_NVME_STR, NULL,
147123a457b8SJason J. Herne &reipl_kset->kobj);
147223a457b8SJason J. Herne if (!reipl_nvme_kset) {
147323a457b8SJason J. Herne free_page((unsigned long) reipl_block_nvme);
147423a457b8SJason J. Herne return -ENOMEM;
147523a457b8SJason J. Herne }
147623a457b8SJason J. Herne
147723a457b8SJason J. Herne rc = sysfs_create_group(&reipl_nvme_kset->kobj, &reipl_nvme_attr_group);
14785627b922SGerald Schaefer if (rc)
14795627b922SGerald Schaefer goto out1;
14805627b922SGerald Schaefer
14815627b922SGerald Schaefer if (test_facility(141)) {
14825627b922SGerald Schaefer rc = sysfs_create_file(&reipl_nvme_kset->kobj,
14835627b922SGerald Schaefer &sys_reipl_nvme_clear_attr.attr);
14845627b922SGerald Schaefer if (rc)
14855627b922SGerald Schaefer goto out2;
14865627b922SGerald Schaefer } else {
14875627b922SGerald Schaefer reipl_nvme_clear = true;
148823a457b8SJason J. Herne }
148923a457b8SJason J. Herne
149023a457b8SJason J. Herne if (ipl_info.type == IPL_TYPE_NVME) {
149123a457b8SJason J. Herne memcpy(reipl_block_nvme, &ipl_block, sizeof(ipl_block));
149223a457b8SJason J. Herne /*
149323a457b8SJason J. Herne * Fix loadparm: There are systems where the (SCSI) LOADPARM
149423a457b8SJason J. Herne * is invalid in the IPL parameter block, so take it
149523a457b8SJason J. Herne * always from sclp_ipl_info.
149623a457b8SJason J. Herne */
149723a457b8SJason J. Herne memcpy(reipl_block_nvme->nvme.loadparm, sclp_ipl_info.loadparm,
149823a457b8SJason J. Herne LOADPARM_LEN);
149923a457b8SJason J. Herne } else {
150023a457b8SJason J. Herne reipl_block_nvme->hdr.len = IPL_BP_NVME_LEN;
150123a457b8SJason J. Herne reipl_block_nvme->hdr.version = IPL_PARM_BLOCK_VERSION;
150223a457b8SJason J. Herne reipl_block_nvme->nvme.len = IPL_BP0_NVME_LEN;
150323a457b8SJason J. Herne reipl_block_nvme->nvme.pbt = IPL_PBT_NVME;
150423a457b8SJason J. Herne reipl_block_nvme->nvme.opt = IPL_PB0_NVME_OPT_IPL;
150523a457b8SJason J. Herne }
150623a457b8SJason J. Herne reipl_capabilities |= IPL_TYPE_NVME;
150723a457b8SJason J. Herne return 0;
15085627b922SGerald Schaefer
15095627b922SGerald Schaefer out2:
15105627b922SGerald Schaefer sysfs_remove_group(&reipl_nvme_kset->kobj, &reipl_nvme_attr_group);
15115627b922SGerald Schaefer out1:
15125627b922SGerald Schaefer kset_unregister(reipl_nvme_kset);
15135627b922SGerald Schaefer free_page((unsigned long) reipl_block_nvme);
15145627b922SGerald Schaefer return rc;
151523a457b8SJason J. Herne }
151623a457b8SJason J. Herne
reipl_eckd_init(void)151787fd22e0SSven Schnelle static int __init reipl_eckd_init(void)
151887fd22e0SSven Schnelle {
151987fd22e0SSven Schnelle int rc;
152087fd22e0SSven Schnelle
152187fd22e0SSven Schnelle if (!sclp.has_sipl_eckd)
152287fd22e0SSven Schnelle return 0;
152387fd22e0SSven Schnelle
152487fd22e0SSven Schnelle reipl_block_eckd = (void *)get_zeroed_page(GFP_KERNEL);
152587fd22e0SSven Schnelle if (!reipl_block_eckd)
152687fd22e0SSven Schnelle return -ENOMEM;
152787fd22e0SSven Schnelle
152887fd22e0SSven Schnelle /* sysfs: create kset for mixing attr group and bin attrs */
152987fd22e0SSven Schnelle reipl_eckd_kset = kset_create_and_add(IPL_ECKD_STR, NULL,
153087fd22e0SSven Schnelle &reipl_kset->kobj);
153187fd22e0SSven Schnelle if (!reipl_eckd_kset) {
153287fd22e0SSven Schnelle free_page((unsigned long)reipl_block_eckd);
153387fd22e0SSven Schnelle return -ENOMEM;
153487fd22e0SSven Schnelle }
153587fd22e0SSven Schnelle
153687fd22e0SSven Schnelle rc = sysfs_create_group(&reipl_eckd_kset->kobj, &reipl_eckd_attr_group);
153787fd22e0SSven Schnelle if (rc)
153887fd22e0SSven Schnelle goto out1;
153987fd22e0SSven Schnelle
154087fd22e0SSven Schnelle if (test_facility(141)) {
154187fd22e0SSven Schnelle rc = sysfs_create_file(&reipl_eckd_kset->kobj,
154287fd22e0SSven Schnelle &sys_reipl_eckd_clear_attr.attr);
154387fd22e0SSven Schnelle if (rc)
154487fd22e0SSven Schnelle goto out2;
154587fd22e0SSven Schnelle } else {
154687fd22e0SSven Schnelle reipl_eckd_clear = true;
154787fd22e0SSven Schnelle }
154887fd22e0SSven Schnelle
154987fd22e0SSven Schnelle if (ipl_info.type == IPL_TYPE_ECKD) {
155087fd22e0SSven Schnelle memcpy(reipl_block_eckd, &ipl_block, sizeof(ipl_block));
155187fd22e0SSven Schnelle } else {
155287fd22e0SSven Schnelle reipl_block_eckd->hdr.len = IPL_BP_ECKD_LEN;
155387fd22e0SSven Schnelle reipl_block_eckd->hdr.version = IPL_PARM_BLOCK_VERSION;
155487fd22e0SSven Schnelle reipl_block_eckd->eckd.len = IPL_BP0_ECKD_LEN;
155587fd22e0SSven Schnelle reipl_block_eckd->eckd.pbt = IPL_PBT_ECKD;
155687fd22e0SSven Schnelle reipl_block_eckd->eckd.opt = IPL_PB0_ECKD_OPT_IPL;
155787fd22e0SSven Schnelle }
155887fd22e0SSven Schnelle reipl_capabilities |= IPL_TYPE_ECKD;
155987fd22e0SSven Schnelle return 0;
156087fd22e0SSven Schnelle
156187fd22e0SSven Schnelle out2:
156287fd22e0SSven Schnelle sysfs_remove_group(&reipl_eckd_kset->kobj, &reipl_eckd_attr_group);
156387fd22e0SSven Schnelle out1:
156487fd22e0SSven Schnelle kset_unregister(reipl_eckd_kset);
156587fd22e0SSven Schnelle free_page((unsigned long)reipl_block_eckd);
156687fd22e0SSven Schnelle return rc;
156787fd22e0SSven Schnelle }
156887fd22e0SSven Schnelle
reipl_type_init(void)15694857d4bbSMichael Holzheu static int __init reipl_type_init(void)
15704857d4bbSMichael Holzheu {
15714857d4bbSMichael Holzheu enum ipl_type reipl_type = ipl_info.type;
15724857d4bbSMichael Holzheu struct ipl_parameter_block *reipl_block;
15734857d4bbSMichael Holzheu unsigned long size;
15744857d4bbSMichael Holzheu
15754857d4bbSMichael Holzheu reipl_block = os_info_old_entry(OS_INFO_REIPL_BLOCK, &size);
15764857d4bbSMichael Holzheu if (!reipl_block)
15774857d4bbSMichael Holzheu goto out;
15784857d4bbSMichael Holzheu /*
15794857d4bbSMichael Holzheu * If we have an OS info reipl block, this will be used
15804857d4bbSMichael Holzheu */
15815f1207fbSMartin Schwidefsky if (reipl_block->pb0_hdr.pbt == IPL_PBT_FCP) {
15824857d4bbSMichael Holzheu memcpy(reipl_block_fcp, reipl_block, size);
15834857d4bbSMichael Holzheu reipl_type = IPL_TYPE_FCP;
158423a457b8SJason J. Herne } else if (reipl_block->pb0_hdr.pbt == IPL_PBT_NVME) {
158523a457b8SJason J. Herne memcpy(reipl_block_nvme, reipl_block, size);
158623a457b8SJason J. Herne reipl_type = IPL_TYPE_NVME;
15875f1207fbSMartin Schwidefsky } else if (reipl_block->pb0_hdr.pbt == IPL_PBT_CCW) {
15884857d4bbSMichael Holzheu memcpy(reipl_block_ccw, reipl_block, size);
15894857d4bbSMichael Holzheu reipl_type = IPL_TYPE_CCW;
159087fd22e0SSven Schnelle } else if (reipl_block->pb0_hdr.pbt == IPL_PBT_ECKD) {
159187fd22e0SSven Schnelle memcpy(reipl_block_eckd, reipl_block, size);
159287fd22e0SSven Schnelle reipl_type = IPL_TYPE_ECKD;
15934857d4bbSMichael Holzheu }
15944857d4bbSMichael Holzheu out:
15954857d4bbSMichael Holzheu return reipl_set_type(reipl_type);
15964857d4bbSMichael Holzheu }
15974857d4bbSMichael Holzheu
reipl_init(void)15982bc89b5eSHeiko Carstens static int __init reipl_init(void)
1599ff6b8ea6SMichael Holzheu {
1600ff6b8ea6SMichael Holzheu int rc;
1601ff6b8ea6SMichael Holzheu
1602f62ed9e3SGreg Kroah-Hartman reipl_kset = kset_create_and_add("reipl", NULL, firmware_kobj);
1603d91885beSGreg Kroah-Hartman if (!reipl_kset)
1604d91885beSGreg Kroah-Hartman return -ENOMEM;
1605d91885beSGreg Kroah-Hartman rc = sysfs_create_file(&reipl_kset->kobj, &reipl_type_attr.attr);
1606ff6b8ea6SMichael Holzheu if (rc) {
1607d91885beSGreg Kroah-Hartman kset_unregister(reipl_kset);
1608ff6b8ea6SMichael Holzheu return rc;
1609ff6b8ea6SMichael Holzheu }
1610ff6b8ea6SMichael Holzheu rc = reipl_ccw_init();
1611ff6b8ea6SMichael Holzheu if (rc)
1612ff6b8ea6SMichael Holzheu return rc;
161387fd22e0SSven Schnelle rc = reipl_eckd_init();
161487fd22e0SSven Schnelle if (rc)
161587fd22e0SSven Schnelle return rc;
1616ff6b8ea6SMichael Holzheu rc = reipl_fcp_init();
1617ff6b8ea6SMichael Holzheu if (rc)
1618ff6b8ea6SMichael Holzheu return rc;
161923a457b8SJason J. Herne rc = reipl_nvme_init();
162023a457b8SJason J. Herne if (rc)
162123a457b8SJason J. Herne return rc;
1622fe355b7fSHongjie Yang rc = reipl_nss_init();
1623fe355b7fSHongjie Yang if (rc)
1624fe355b7fSHongjie Yang return rc;
16254857d4bbSMichael Holzheu return reipl_type_init();
1626ff6b8ea6SMichael Holzheu }
1627ff6b8ea6SMichael Holzheu
16282bc89b5eSHeiko Carstens static struct shutdown_action __refdata reipl_action = {
16292bc89b5eSHeiko Carstens .name = SHUTDOWN_ACTION_REIPL_STR,
16302bc89b5eSHeiko Carstens .fn = reipl_run,
16312bc89b5eSHeiko Carstens .init = reipl_init,
16322bc89b5eSHeiko Carstens };
163399ca4e58SMichael Holzheu
163499ca4e58SMichael Holzheu /*
163599ca4e58SMichael Holzheu * dump shutdown action: Dump Linux on shutdown.
163699ca4e58SMichael Holzheu */
163799ca4e58SMichael Holzheu
163899ca4e58SMichael Holzheu /* FCP dump device attributes */
163999ca4e58SMichael Holzheu
1640eda4ddf7SMichael Holzheu DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%llx\n",
164186c74d86SMartin Schwidefsky dump_block_fcp->fcp.wwpn);
1642eda4ddf7SMichael Holzheu DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%llx\n",
164386c74d86SMartin Schwidefsky dump_block_fcp->fcp.lun);
164499ca4e58SMichael Holzheu DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
164586c74d86SMartin Schwidefsky dump_block_fcp->fcp.bootprog);
164699ca4e58SMichael Holzheu DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
164786c74d86SMartin Schwidefsky dump_block_fcp->fcp.br_lba);
164899ca4e58SMichael Holzheu DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
164986c74d86SMartin Schwidefsky dump_block_fcp->fcp.devno);
165099ca4e58SMichael Holzheu
165199ca4e58SMichael Holzheu static struct attribute *dump_fcp_attrs[] = {
165299ca4e58SMichael Holzheu &sys_dump_fcp_device_attr.attr,
165399ca4e58SMichael Holzheu &sys_dump_fcp_wwpn_attr.attr,
165499ca4e58SMichael Holzheu &sys_dump_fcp_lun_attr.attr,
165599ca4e58SMichael Holzheu &sys_dump_fcp_bootprog_attr.attr,
165699ca4e58SMichael Holzheu &sys_dump_fcp_br_lba_attr.attr,
165799ca4e58SMichael Holzheu NULL,
165899ca4e58SMichael Holzheu };
165999ca4e58SMichael Holzheu
166099ca4e58SMichael Holzheu static struct attribute_group dump_fcp_attr_group = {
166199ca4e58SMichael Holzheu .name = IPL_FCP_STR,
166299ca4e58SMichael Holzheu .attrs = dump_fcp_attrs,
166399ca4e58SMichael Holzheu };
166499ca4e58SMichael Holzheu
1665d70e38cbSJason J. Herne /* NVME dump device attributes */
1666d70e38cbSJason J. Herne DEFINE_IPL_ATTR_RW(dump_nvme, fid, "0x%08llx\n", "%llx\n",
1667d70e38cbSJason J. Herne dump_block_nvme->nvme.fid);
1668d70e38cbSJason J. Herne DEFINE_IPL_ATTR_RW(dump_nvme, nsid, "0x%08llx\n", "%llx\n",
1669d70e38cbSJason J. Herne dump_block_nvme->nvme.nsid);
1670d70e38cbSJason J. Herne DEFINE_IPL_ATTR_RW(dump_nvme, bootprog, "%lld\n", "%llx\n",
1671d70e38cbSJason J. Herne dump_block_nvme->nvme.bootprog);
1672d70e38cbSJason J. Herne DEFINE_IPL_ATTR_RW(dump_nvme, br_lba, "%lld\n", "%llx\n",
1673d70e38cbSJason J. Herne dump_block_nvme->nvme.br_lba);
1674d70e38cbSJason J. Herne
1675d70e38cbSJason J. Herne static struct attribute *dump_nvme_attrs[] = {
1676d70e38cbSJason J. Herne &sys_dump_nvme_fid_attr.attr,
1677d70e38cbSJason J. Herne &sys_dump_nvme_nsid_attr.attr,
1678d70e38cbSJason J. Herne &sys_dump_nvme_bootprog_attr.attr,
1679d70e38cbSJason J. Herne &sys_dump_nvme_br_lba_attr.attr,
1680d70e38cbSJason J. Herne NULL,
1681d70e38cbSJason J. Herne };
1682d70e38cbSJason J. Herne
1683d70e38cbSJason J. Herne static struct attribute_group dump_nvme_attr_group = {
1684d70e38cbSJason J. Herne .name = IPL_NVME_STR,
1685d70e38cbSJason J. Herne .attrs = dump_nvme_attrs,
1686d70e38cbSJason J. Herne };
1687d70e38cbSJason J. Herne
1688e2d2a296SSven Schnelle /* ECKD dump device attributes */
1689e2d2a296SSven Schnelle DEFINE_IPL_CCW_ATTR_RW(dump_eckd, device, dump_block_eckd->eckd);
1690e2d2a296SSven Schnelle DEFINE_IPL_ATTR_RW(dump_eckd, bootprog, "%lld\n", "%llx\n",
1691e2d2a296SSven Schnelle dump_block_eckd->eckd.bootprog);
1692e2d2a296SSven Schnelle
1693e2d2a296SSven Schnelle IPL_ATTR_BR_CHR_SHOW_FN(dump, dump_block_eckd->eckd);
1694e2d2a296SSven Schnelle IPL_ATTR_BR_CHR_STORE_FN(dump, dump_block_eckd->eckd);
1695e2d2a296SSven Schnelle
1696e2d2a296SSven Schnelle static struct kobj_attribute sys_dump_eckd_br_chr_attr =
1697a70f7276SSven Schnelle __ATTR(br_chr, 0644, eckd_dump_br_chr_show, eckd_dump_br_chr_store);
1698e2d2a296SSven Schnelle
1699e2d2a296SSven Schnelle static struct attribute *dump_eckd_attrs[] = {
1700e2d2a296SSven Schnelle &sys_dump_eckd_device_attr.attr,
1701e2d2a296SSven Schnelle &sys_dump_eckd_bootprog_attr.attr,
1702e2d2a296SSven Schnelle &sys_dump_eckd_br_chr_attr.attr,
1703e2d2a296SSven Schnelle NULL,
1704e2d2a296SSven Schnelle };
1705e2d2a296SSven Schnelle
1706e2d2a296SSven Schnelle static struct attribute_group dump_eckd_attr_group = {
1707e2d2a296SSven Schnelle .name = IPL_ECKD_STR,
1708e2d2a296SSven Schnelle .attrs = dump_eckd_attrs,
1709e2d2a296SSven Schnelle };
1710e2d2a296SSven Schnelle
171199ca4e58SMichael Holzheu /* CCW dump device attributes */
171286c74d86SMartin Schwidefsky DEFINE_IPL_CCW_ATTR_RW(dump_ccw, device, dump_block_ccw->ccw);
171399ca4e58SMichael Holzheu
171499ca4e58SMichael Holzheu static struct attribute *dump_ccw_attrs[] = {
171599ca4e58SMichael Holzheu &sys_dump_ccw_device_attr.attr,
171699ca4e58SMichael Holzheu NULL,
171799ca4e58SMichael Holzheu };
171899ca4e58SMichael Holzheu
171999ca4e58SMichael Holzheu static struct attribute_group dump_ccw_attr_group = {
172099ca4e58SMichael Holzheu .name = IPL_CCW_STR,
172199ca4e58SMichael Holzheu .attrs = dump_ccw_attrs,
172299ca4e58SMichael Holzheu };
172399ca4e58SMichael Holzheu
172499ca4e58SMichael Holzheu /* dump type */
172599ca4e58SMichael Holzheu
dump_set_type(enum dump_type type)172699ca4e58SMichael Holzheu static int dump_set_type(enum dump_type type)
172799ca4e58SMichael Holzheu {
172899ca4e58SMichael Holzheu if (!(dump_capabilities & type))
172999ca4e58SMichael Holzheu return -EINVAL;
173099ca4e58SMichael Holzheu dump_type = type;
173199ca4e58SMichael Holzheu return 0;
173299ca4e58SMichael Holzheu }
173399ca4e58SMichael Holzheu
dump_type_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)173499ca4e58SMichael Holzheu static ssize_t dump_type_show(struct kobject *kobj,
173599ca4e58SMichael Holzheu struct kobj_attribute *attr, char *page)
173699ca4e58SMichael Holzheu {
173799ca4e58SMichael Holzheu return sprintf(page, "%s\n", dump_type_str(dump_type));
173899ca4e58SMichael Holzheu }
173999ca4e58SMichael Holzheu
dump_type_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t len)174099ca4e58SMichael Holzheu static ssize_t dump_type_store(struct kobject *kobj,
174199ca4e58SMichael Holzheu struct kobj_attribute *attr,
174299ca4e58SMichael Holzheu const char *buf, size_t len)
174399ca4e58SMichael Holzheu {
174499ca4e58SMichael Holzheu int rc = -EINVAL;
174599ca4e58SMichael Holzheu
174699ca4e58SMichael Holzheu if (strncmp(buf, DUMP_NONE_STR, strlen(DUMP_NONE_STR)) == 0)
174799ca4e58SMichael Holzheu rc = dump_set_type(DUMP_TYPE_NONE);
174899ca4e58SMichael Holzheu else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0)
174999ca4e58SMichael Holzheu rc = dump_set_type(DUMP_TYPE_CCW);
1750e2d2a296SSven Schnelle else if (strncmp(buf, DUMP_ECKD_STR, strlen(DUMP_ECKD_STR)) == 0)
1751e2d2a296SSven Schnelle rc = dump_set_type(DUMP_TYPE_ECKD);
175299ca4e58SMichael Holzheu else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
175399ca4e58SMichael Holzheu rc = dump_set_type(DUMP_TYPE_FCP);
1754d70e38cbSJason J. Herne else if (strncmp(buf, DUMP_NVME_STR, strlen(DUMP_NVME_STR)) == 0)
1755d70e38cbSJason J. Herne rc = dump_set_type(DUMP_TYPE_NVME);
175699ca4e58SMichael Holzheu return (rc != 0) ? rc : len;
175799ca4e58SMichael Holzheu }
175899ca4e58SMichael Holzheu
175999ca4e58SMichael Holzheu static struct kobj_attribute dump_type_attr =
176099ca4e58SMichael Holzheu __ATTR(dump_type, 0644, dump_type_show, dump_type_store);
176199ca4e58SMichael Holzheu
176299ca4e58SMichael Holzheu static struct kset *dump_kset;
176399ca4e58SMichael Holzheu
diag308_dump(void * dump_block)17640894b3aeSMichael Holzheu static void diag308_dump(void *dump_block)
17650894b3aeSMichael Holzheu {
17660894b3aeSMichael Holzheu diag308(DIAG308_SET, dump_block);
17670894b3aeSMichael Holzheu while (1) {
17680599eeadSHeiko Carstens if (diag308(DIAG308_LOAD_NORMAL_DUMP, NULL) != 0x302)
17690894b3aeSMichael Holzheu break;
1770e0d62dcbSHeiko Carstens udelay(USEC_PER_SEC);
17710894b3aeSMichael Holzheu }
17720894b3aeSMichael Holzheu }
17730894b3aeSMichael Holzheu
__dump_run(void * unused)17742c2df118SHeiko Carstens static void __dump_run(void *unused)
177599ca4e58SMichael Holzheu {
177696c0cdbcSVasily Gorbik switch (dump_type) {
177796c0cdbcSVasily Gorbik case DUMP_TYPE_CCW:
17780894b3aeSMichael Holzheu diag308_dump(dump_block_ccw);
177999ca4e58SMichael Holzheu break;
1780e2d2a296SSven Schnelle case DUMP_TYPE_ECKD:
1781e2d2a296SSven Schnelle diag308_dump(dump_block_eckd);
1782e2d2a296SSven Schnelle break;
178396c0cdbcSVasily Gorbik case DUMP_TYPE_FCP:
17840894b3aeSMichael Holzheu diag308_dump(dump_block_fcp);
178599ca4e58SMichael Holzheu break;
1786d70e38cbSJason J. Herne case DUMP_TYPE_NVME:
1787d70e38cbSJason J. Herne diag308_dump(dump_block_nvme);
1788d70e38cbSJason J. Herne break;
17892c2df118SHeiko Carstens default:
17902c2df118SHeiko Carstens break;
179199ca4e58SMichael Holzheu }
17922c2df118SHeiko Carstens }
17932c2df118SHeiko Carstens
dump_run(struct shutdown_trigger * trigger)17942c2df118SHeiko Carstens static void dump_run(struct shutdown_trigger *trigger)
17952c2df118SHeiko Carstens {
179696c0cdbcSVasily Gorbik if (dump_type == DUMP_TYPE_NONE)
17972c2df118SHeiko Carstens return;
17982c2df118SHeiko Carstens smp_send_stop();
17998b646bd7SMartin Schwidefsky smp_call_ipl_cpu(__dump_run, NULL);
180099ca4e58SMichael Holzheu }
180199ca4e58SMichael Holzheu
dump_ccw_init(void)1802ff6b8ea6SMichael Holzheu static int __init dump_ccw_init(void)
1803ff6b8ea6SMichael Holzheu {
1804ff6b8ea6SMichael Holzheu int rc;
1805ff6b8ea6SMichael Holzheu
1806ff6b8ea6SMichael Holzheu dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
1807ff6b8ea6SMichael Holzheu if (!dump_block_ccw)
1808ff6b8ea6SMichael Holzheu return -ENOMEM;
1809d91885beSGreg Kroah-Hartman rc = sysfs_create_group(&dump_kset->kobj, &dump_ccw_attr_group);
1810ff6b8ea6SMichael Holzheu if (rc) {
1811ff6b8ea6SMichael Holzheu free_page((unsigned long)dump_block_ccw);
1812ff6b8ea6SMichael Holzheu return rc;
1813ff6b8ea6SMichael Holzheu }
18145f1207fbSMartin Schwidefsky dump_block_ccw->hdr.len = IPL_BP_CCW_LEN;
1815ff6b8ea6SMichael Holzheu dump_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
18165f1207fbSMartin Schwidefsky dump_block_ccw->ccw.len = IPL_BP0_CCW_LEN;
18175f1207fbSMartin Schwidefsky dump_block_ccw->ccw.pbt = IPL_PBT_CCW;
1818411ed322SMichael Holzheu dump_capabilities |= DUMP_TYPE_CCW;
1819ff6b8ea6SMichael Holzheu return 0;
1820ff6b8ea6SMichael Holzheu }
1821ff6b8ea6SMichael Holzheu
dump_fcp_init(void)1822ff6b8ea6SMichael Holzheu static int __init dump_fcp_init(void)
1823ff6b8ea6SMichael Holzheu {
1824ff6b8ea6SMichael Holzheu int rc;
1825ff6b8ea6SMichael Holzheu
182605dd2530SHeiko Carstens if (!sclp_ipl_info.has_dump)
1827ff6b8ea6SMichael Holzheu return 0; /* LDIPL DUMP is not installed */
1828ff6b8ea6SMichael Holzheu dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
1829ff6b8ea6SMichael Holzheu if (!dump_block_fcp)
1830ff6b8ea6SMichael Holzheu return -ENOMEM;
1831d91885beSGreg Kroah-Hartman rc = sysfs_create_group(&dump_kset->kobj, &dump_fcp_attr_group);
1832ff6b8ea6SMichael Holzheu if (rc) {
1833ff6b8ea6SMichael Holzheu free_page((unsigned long)dump_block_fcp);
1834ff6b8ea6SMichael Holzheu return rc;
1835ff6b8ea6SMichael Holzheu }
18365f1207fbSMartin Schwidefsky dump_block_fcp->hdr.len = IPL_BP_FCP_LEN;
1837ff6b8ea6SMichael Holzheu dump_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
18385f1207fbSMartin Schwidefsky dump_block_fcp->fcp.len = IPL_BP0_FCP_LEN;
18395f1207fbSMartin Schwidefsky dump_block_fcp->fcp.pbt = IPL_PBT_FCP;
18405f1207fbSMartin Schwidefsky dump_block_fcp->fcp.opt = IPL_PB0_FCP_OPT_DUMP;
1841411ed322SMichael Holzheu dump_capabilities |= DUMP_TYPE_FCP;
1842ff6b8ea6SMichael Holzheu return 0;
1843ff6b8ea6SMichael Holzheu }
1844ff6b8ea6SMichael Holzheu
dump_nvme_init(void)1845d70e38cbSJason J. Herne static int __init dump_nvme_init(void)
1846d70e38cbSJason J. Herne {
1847d70e38cbSJason J. Herne int rc;
1848d70e38cbSJason J. Herne
1849d70e38cbSJason J. Herne if (!sclp_ipl_info.has_dump)
1850d70e38cbSJason J. Herne return 0; /* LDIPL DUMP is not installed */
1851d70e38cbSJason J. Herne dump_block_nvme = (void *) get_zeroed_page(GFP_KERNEL);
1852d70e38cbSJason J. Herne if (!dump_block_nvme)
1853d70e38cbSJason J. Herne return -ENOMEM;
1854d70e38cbSJason J. Herne rc = sysfs_create_group(&dump_kset->kobj, &dump_nvme_attr_group);
1855d70e38cbSJason J. Herne if (rc) {
1856d70e38cbSJason J. Herne free_page((unsigned long)dump_block_nvme);
1857d70e38cbSJason J. Herne return rc;
1858d70e38cbSJason J. Herne }
1859d70e38cbSJason J. Herne dump_block_nvme->hdr.len = IPL_BP_NVME_LEN;
1860d70e38cbSJason J. Herne dump_block_nvme->hdr.version = IPL_PARM_BLOCK_VERSION;
1861*2102692eSAlexander Egorenkov dump_block_nvme->nvme.len = IPL_BP0_NVME_LEN;
1862*2102692eSAlexander Egorenkov dump_block_nvme->nvme.pbt = IPL_PBT_NVME;
1863*2102692eSAlexander Egorenkov dump_block_nvme->nvme.opt = IPL_PB0_NVME_OPT_DUMP;
1864d70e38cbSJason J. Herne dump_capabilities |= DUMP_TYPE_NVME;
1865d70e38cbSJason J. Herne return 0;
1866d70e38cbSJason J. Herne }
1867d70e38cbSJason J. Herne
dump_eckd_init(void)1868e2d2a296SSven Schnelle static int __init dump_eckd_init(void)
1869e2d2a296SSven Schnelle {
1870e2d2a296SSven Schnelle int rc;
1871e2d2a296SSven Schnelle
1872e2d2a296SSven Schnelle if (!sclp_ipl_info.has_dump || !sclp.has_sipl_eckd)
1873e2d2a296SSven Schnelle return 0; /* LDIPL DUMP is not installed */
1874e2d2a296SSven Schnelle dump_block_eckd = (void *)get_zeroed_page(GFP_KERNEL);
1875e2d2a296SSven Schnelle if (!dump_block_eckd)
1876e2d2a296SSven Schnelle return -ENOMEM;
1877e2d2a296SSven Schnelle rc = sysfs_create_group(&dump_kset->kobj, &dump_eckd_attr_group);
1878e2d2a296SSven Schnelle if (rc) {
1879e2d2a296SSven Schnelle free_page((unsigned long)dump_block_eckd);
1880e2d2a296SSven Schnelle return rc;
1881e2d2a296SSven Schnelle }
1882e2d2a296SSven Schnelle dump_block_eckd->hdr.len = IPL_BP_ECKD_LEN;
1883e2d2a296SSven Schnelle dump_block_eckd->hdr.version = IPL_PARM_BLOCK_VERSION;
1884e2d2a296SSven Schnelle dump_block_eckd->eckd.len = IPL_BP0_ECKD_LEN;
1885e2d2a296SSven Schnelle dump_block_eckd->eckd.pbt = IPL_PBT_ECKD;
1886e2d2a296SSven Schnelle dump_block_eckd->eckd.opt = IPL_PB0_ECKD_OPT_DUMP;
1887e2d2a296SSven Schnelle dump_capabilities |= DUMP_TYPE_ECKD;
1888e2d2a296SSven Schnelle return 0;
1889e2d2a296SSven Schnelle }
1890e2d2a296SSven Schnelle
dump_init(void)18912bc89b5eSHeiko Carstens static int __init dump_init(void)
1892ff6b8ea6SMichael Holzheu {
1893ff6b8ea6SMichael Holzheu int rc;
1894ff6b8ea6SMichael Holzheu
1895f62ed9e3SGreg Kroah-Hartman dump_kset = kset_create_and_add("dump", NULL, firmware_kobj);
1896d91885beSGreg Kroah-Hartman if (!dump_kset)
1897d91885beSGreg Kroah-Hartman return -ENOMEM;
189899ca4e58SMichael Holzheu rc = sysfs_create_file(&dump_kset->kobj, &dump_type_attr.attr);
1899ff6b8ea6SMichael Holzheu if (rc) {
1900d91885beSGreg Kroah-Hartman kset_unregister(dump_kset);
1901ff6b8ea6SMichael Holzheu return rc;
1902ff6b8ea6SMichael Holzheu }
1903ff6b8ea6SMichael Holzheu rc = dump_ccw_init();
1904ff6b8ea6SMichael Holzheu if (rc)
1905ff6b8ea6SMichael Holzheu return rc;
1906e2d2a296SSven Schnelle rc = dump_eckd_init();
1907e2d2a296SSven Schnelle if (rc)
1908e2d2a296SSven Schnelle return rc;
1909ff6b8ea6SMichael Holzheu rc = dump_fcp_init();
1910ff6b8ea6SMichael Holzheu if (rc)
1911ff6b8ea6SMichael Holzheu return rc;
1912d70e38cbSJason J. Herne rc = dump_nvme_init();
1913d70e38cbSJason J. Herne if (rc)
1914d70e38cbSJason J. Herne return rc;
1915411ed322SMichael Holzheu dump_set_type(DUMP_TYPE_NONE);
1916ff6b8ea6SMichael Holzheu return 0;
1917ff6b8ea6SMichael Holzheu }
1918ff6b8ea6SMichael Holzheu
19192bc89b5eSHeiko Carstens static struct shutdown_action __refdata dump_action = {
19202bc89b5eSHeiko Carstens .name = SHUTDOWN_ACTION_DUMP_STR,
19212bc89b5eSHeiko Carstens .fn = dump_run,
19222bc89b5eSHeiko Carstens .init = dump_init,
19232bc89b5eSHeiko Carstens };
1924ff6b8ea6SMichael Holzheu
dump_reipl_run(struct shutdown_trigger * trigger)1925099b7651SFrank Munzert static void dump_reipl_run(struct shutdown_trigger *trigger)
1926099b7651SFrank Munzert {
19274df29d2bSAlexander Gordeev struct lowcore *abs_lc;
1928fbe76568SHeiko Carstens unsigned int csum;
1929b43445ffSMichael Holzheu
193031e9ccc6SMikhail Zaslonko /*
193131e9ccc6SMikhail Zaslonko * Set REIPL_CLEAR flag in os_info flags entry indicating
193231e9ccc6SMikhail Zaslonko * 'clear' sysfs attribute has been set on the panicked system
193331e9ccc6SMikhail Zaslonko * for specified reipl type.
193431e9ccc6SMikhail Zaslonko * Always set for IPL_TYPE_NSS and IPL_TYPE_UNKNOWN.
193531e9ccc6SMikhail Zaslonko */
193631e9ccc6SMikhail Zaslonko if ((reipl_type == IPL_TYPE_CCW && reipl_ccw_clear) ||
193731e9ccc6SMikhail Zaslonko (reipl_type == IPL_TYPE_ECKD && reipl_eckd_clear) ||
193831e9ccc6SMikhail Zaslonko (reipl_type == IPL_TYPE_FCP && reipl_fcp_clear) ||
193931e9ccc6SMikhail Zaslonko (reipl_type == IPL_TYPE_NVME && reipl_nvme_clear) ||
194031e9ccc6SMikhail Zaslonko reipl_type == IPL_TYPE_NSS ||
194131e9ccc6SMikhail Zaslonko reipl_type == IPL_TYPE_UNKNOWN)
194231e9ccc6SMikhail Zaslonko os_info_flags |= OS_INFO_FLAG_REIPL_CLEAR;
194331e9ccc6SMikhail Zaslonko os_info_entry_add(OS_INFO_FLAGS_ENTRY, &os_info_flags, sizeof(os_info_flags));
194490b3baa2SHeiko Carstens csum = (__force unsigned int)
194590b3baa2SHeiko Carstens csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0);
19462154e0b3SAlexander Gordeev abs_lc = get_abs_lowcore();
19472facd5d3SAlexander Gordeev abs_lc->ipib = __pa(reipl_block_actual);
19484df29d2bSAlexander Gordeev abs_lc->ipib_checksum = csum;
19492154e0b3SAlexander Gordeev put_abs_lowcore(abs_lc);
1950099b7651SFrank Munzert dump_run(trigger);
1951099b7651SFrank Munzert }
1952099b7651SFrank Munzert
1953099b7651SFrank Munzert static struct shutdown_action __refdata dump_reipl_action = {
1954099b7651SFrank Munzert .name = SHUTDOWN_ACTION_DUMP_REIPL_STR,
1955099b7651SFrank Munzert .fn = dump_reipl_run,
1956099b7651SFrank Munzert };
1957099b7651SFrank Munzert
195899ca4e58SMichael Holzheu /*
195999ca4e58SMichael Holzheu * vmcmd shutdown action: Trigger vm command on shutdown.
196099ca4e58SMichael Holzheu */
196199ca4e58SMichael Holzheu
196299ca4e58SMichael Holzheu static char vmcmd_on_reboot[128];
196399ca4e58SMichael Holzheu static char vmcmd_on_panic[128];
196499ca4e58SMichael Holzheu static char vmcmd_on_halt[128];
196599ca4e58SMichael Holzheu static char vmcmd_on_poff[128];
19667dd6b334SMichael Holzheu static char vmcmd_on_restart[128];
196799ca4e58SMichael Holzheu
196899ca4e58SMichael Holzheu DEFINE_IPL_ATTR_STR_RW(vmcmd, on_reboot, "%s\n", "%s\n", vmcmd_on_reboot);
196999ca4e58SMichael Holzheu DEFINE_IPL_ATTR_STR_RW(vmcmd, on_panic, "%s\n", "%s\n", vmcmd_on_panic);
197099ca4e58SMichael Holzheu DEFINE_IPL_ATTR_STR_RW(vmcmd, on_halt, "%s\n", "%s\n", vmcmd_on_halt);
197199ca4e58SMichael Holzheu DEFINE_IPL_ATTR_STR_RW(vmcmd, on_poff, "%s\n", "%s\n", vmcmd_on_poff);
19727dd6b334SMichael Holzheu DEFINE_IPL_ATTR_STR_RW(vmcmd, on_restart, "%s\n", "%s\n", vmcmd_on_restart);
197399ca4e58SMichael Holzheu
197499ca4e58SMichael Holzheu static struct attribute *vmcmd_attrs[] = {
197599ca4e58SMichael Holzheu &sys_vmcmd_on_reboot_attr.attr,
197699ca4e58SMichael Holzheu &sys_vmcmd_on_panic_attr.attr,
197799ca4e58SMichael Holzheu &sys_vmcmd_on_halt_attr.attr,
197899ca4e58SMichael Holzheu &sys_vmcmd_on_poff_attr.attr,
19797dd6b334SMichael Holzheu &sys_vmcmd_on_restart_attr.attr,
198099ca4e58SMichael Holzheu NULL,
198199ca4e58SMichael Holzheu };
198299ca4e58SMichael Holzheu
198399ca4e58SMichael Holzheu static struct attribute_group vmcmd_attr_group = {
198499ca4e58SMichael Holzheu .attrs = vmcmd_attrs,
198599ca4e58SMichael Holzheu };
198699ca4e58SMichael Holzheu
198799ca4e58SMichael Holzheu static struct kset *vmcmd_kset;
198899ca4e58SMichael Holzheu
vmcmd_run(struct shutdown_trigger * trigger)198999ca4e58SMichael Holzheu static void vmcmd_run(struct shutdown_trigger *trigger)
199099ca4e58SMichael Holzheu {
19918143adafSMichael Holzheu char *cmd;
199299ca4e58SMichael Holzheu
199399ca4e58SMichael Holzheu if (strcmp(trigger->name, ON_REIPL_STR) == 0)
199499ca4e58SMichael Holzheu cmd = vmcmd_on_reboot;
199599ca4e58SMichael Holzheu else if (strcmp(trigger->name, ON_PANIC_STR) == 0)
199699ca4e58SMichael Holzheu cmd = vmcmd_on_panic;
199799ca4e58SMichael Holzheu else if (strcmp(trigger->name, ON_HALT_STR) == 0)
199899ca4e58SMichael Holzheu cmd = vmcmd_on_halt;
199999ca4e58SMichael Holzheu else if (strcmp(trigger->name, ON_POFF_STR) == 0)
200099ca4e58SMichael Holzheu cmd = vmcmd_on_poff;
20017dd6b334SMichael Holzheu else if (strcmp(trigger->name, ON_RESTART_STR) == 0)
20027dd6b334SMichael Holzheu cmd = vmcmd_on_restart;
200399ca4e58SMichael Holzheu else
200499ca4e58SMichael Holzheu return;
200599ca4e58SMichael Holzheu
200699ca4e58SMichael Holzheu if (strlen(cmd) == 0)
200799ca4e58SMichael Holzheu return;
200899ca4e58SMichael Holzheu __cpcmd(cmd, NULL, 0, NULL);
200999ca4e58SMichael Holzheu }
201099ca4e58SMichael Holzheu
vmcmd_init(void)201199ca4e58SMichael Holzheu static int vmcmd_init(void)
201299ca4e58SMichael Holzheu {
201399ca4e58SMichael Holzheu if (!MACHINE_IS_VM)
2014b8e660b8SHeiko Carstens return -EOPNOTSUPP;
201599ca4e58SMichael Holzheu vmcmd_kset = kset_create_and_add("vmcmd", NULL, firmware_kobj);
201699ca4e58SMichael Holzheu if (!vmcmd_kset)
201799ca4e58SMichael Holzheu return -ENOMEM;
201899ca4e58SMichael Holzheu return sysfs_create_group(&vmcmd_kset->kobj, &vmcmd_attr_group);
201999ca4e58SMichael Holzheu }
202099ca4e58SMichael Holzheu
202199ca4e58SMichael Holzheu static struct shutdown_action vmcmd_action = {SHUTDOWN_ACTION_VMCMD_STR,
202299ca4e58SMichael Holzheu vmcmd_run, vmcmd_init};
202399ca4e58SMichael Holzheu
202499ca4e58SMichael Holzheu /*
202599ca4e58SMichael Holzheu * stop shutdown action: Stop Linux on shutdown.
202699ca4e58SMichael Holzheu */
202799ca4e58SMichael Holzheu
stop_run(struct shutdown_trigger * trigger)202899ca4e58SMichael Holzheu static void stop_run(struct shutdown_trigger *trigger)
202999ca4e58SMichael Holzheu {
2030e1202edaSMichael Holzheu if (strcmp(trigger->name, ON_PANIC_STR) == 0 ||
2031e1202edaSMichael Holzheu strcmp(trigger->name, ON_RESTART_STR) == 0)
203298587c2dSMartin Schwidefsky disabled_wait();
20338b646bd7SMartin Schwidefsky smp_stop_cpu();
203499ca4e58SMichael Holzheu }
203599ca4e58SMichael Holzheu
203699ca4e58SMichael Holzheu static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR,
203799ca4e58SMichael Holzheu stop_run, NULL};
203899ca4e58SMichael Holzheu
203999ca4e58SMichael Holzheu /* action list */
204099ca4e58SMichael Holzheu
204199ca4e58SMichael Holzheu static struct shutdown_action *shutdown_actions_list[] = {
2042099b7651SFrank Munzert &ipl_action, &reipl_action, &dump_reipl_action, &dump_action,
2043099b7651SFrank Munzert &vmcmd_action, &stop_action};
204499ca4e58SMichael Holzheu #define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *))
204599ca4e58SMichael Holzheu
204699ca4e58SMichael Holzheu /*
204799ca4e58SMichael Holzheu * Trigger section
204899ca4e58SMichael Holzheu */
204999ca4e58SMichael Holzheu
205099ca4e58SMichael Holzheu static struct kset *shutdown_actions_kset;
205199ca4e58SMichael Holzheu
set_trigger(const char * buf,struct shutdown_trigger * trigger,size_t len)205299ca4e58SMichael Holzheu static int set_trigger(const char *buf, struct shutdown_trigger *trigger,
205399ca4e58SMichael Holzheu size_t len)
205499ca4e58SMichael Holzheu {
205599ca4e58SMichael Holzheu int i;
2056099b7651SFrank Munzert
205799ca4e58SMichael Holzheu for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
2058099b7651SFrank Munzert if (sysfs_streq(buf, shutdown_actions_list[i]->name)) {
205981088819SFrank Munzert if (shutdown_actions_list[i]->init_rc) {
206081088819SFrank Munzert return shutdown_actions_list[i]->init_rc;
206181088819SFrank Munzert } else {
206299ca4e58SMichael Holzheu trigger->action = shutdown_actions_list[i];
206399ca4e58SMichael Holzheu return len;
206499ca4e58SMichael Holzheu }
206599ca4e58SMichael Holzheu }
206681088819SFrank Munzert }
206799ca4e58SMichael Holzheu return -EINVAL;
206899ca4e58SMichael Holzheu }
206999ca4e58SMichael Holzheu
207099ca4e58SMichael Holzheu /* on reipl */
207199ca4e58SMichael Holzheu
207299ca4e58SMichael Holzheu static struct shutdown_trigger on_reboot_trigger = {ON_REIPL_STR,
207399ca4e58SMichael Holzheu &reipl_action};
207499ca4e58SMichael Holzheu
on_reboot_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)207599ca4e58SMichael Holzheu static ssize_t on_reboot_show(struct kobject *kobj,
207699ca4e58SMichael Holzheu struct kobj_attribute *attr, char *page)
207799ca4e58SMichael Holzheu {
207899ca4e58SMichael Holzheu return sprintf(page, "%s\n", on_reboot_trigger.action->name);
207999ca4e58SMichael Holzheu }
208099ca4e58SMichael Holzheu
on_reboot_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t len)208199ca4e58SMichael Holzheu static ssize_t on_reboot_store(struct kobject *kobj,
208299ca4e58SMichael Holzheu struct kobj_attribute *attr,
208399ca4e58SMichael Holzheu const char *buf, size_t len)
208499ca4e58SMichael Holzheu {
208599ca4e58SMichael Holzheu return set_trigger(buf, &on_reboot_trigger, len);
208699ca4e58SMichael Holzheu }
20870f024379SSebastian Ott static struct kobj_attribute on_reboot_attr = __ATTR_RW(on_reboot);
208899ca4e58SMichael Holzheu
do_machine_restart(char * __unused)208999ca4e58SMichael Holzheu static void do_machine_restart(char *__unused)
209099ca4e58SMichael Holzheu {
209199ca4e58SMichael Holzheu smp_send_stop();
209299ca4e58SMichael Holzheu on_reboot_trigger.action->fn(&on_reboot_trigger);
209399ca4e58SMichael Holzheu reipl_run(NULL);
209499ca4e58SMichael Holzheu }
209599ca4e58SMichael Holzheu void (*_machine_restart)(char *command) = do_machine_restart;
209699ca4e58SMichael Holzheu
209799ca4e58SMichael Holzheu /* on panic */
209899ca4e58SMichael Holzheu
209999ca4e58SMichael Holzheu static struct shutdown_trigger on_panic_trigger = {ON_PANIC_STR, &stop_action};
210099ca4e58SMichael Holzheu
on_panic_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)210199ca4e58SMichael Holzheu static ssize_t on_panic_show(struct kobject *kobj,
210299ca4e58SMichael Holzheu struct kobj_attribute *attr, char *page)
210399ca4e58SMichael Holzheu {
210499ca4e58SMichael Holzheu return sprintf(page, "%s\n", on_panic_trigger.action->name);
210599ca4e58SMichael Holzheu }
210699ca4e58SMichael Holzheu
on_panic_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t len)210799ca4e58SMichael Holzheu static ssize_t on_panic_store(struct kobject *kobj,
210899ca4e58SMichael Holzheu struct kobj_attribute *attr,
210999ca4e58SMichael Holzheu const char *buf, size_t len)
211099ca4e58SMichael Holzheu {
211199ca4e58SMichael Holzheu return set_trigger(buf, &on_panic_trigger, len);
211299ca4e58SMichael Holzheu }
21130f024379SSebastian Ott static struct kobj_attribute on_panic_attr = __ATTR_RW(on_panic);
211499ca4e58SMichael Holzheu
do_panic(void)211599ca4e58SMichael Holzheu static void do_panic(void)
211699ca4e58SMichael Holzheu {
21173ab121abSMichael Holzheu lgr_info_log();
211899ca4e58SMichael Holzheu on_panic_trigger.action->fn(&on_panic_trigger);
211999ca4e58SMichael Holzheu stop_run(&on_panic_trigger);
212099ca4e58SMichael Holzheu }
212199ca4e58SMichael Holzheu
21227dd6b334SMichael Holzheu /* on restart */
21237dd6b334SMichael Holzheu
21247dd6b334SMichael Holzheu static struct shutdown_trigger on_restart_trigger = {ON_RESTART_STR,
2125e1202edaSMichael Holzheu &stop_action};
21267dd6b334SMichael Holzheu
on_restart_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)21277dd6b334SMichael Holzheu static ssize_t on_restart_show(struct kobject *kobj,
21287dd6b334SMichael Holzheu struct kobj_attribute *attr, char *page)
21297dd6b334SMichael Holzheu {
21307dd6b334SMichael Holzheu return sprintf(page, "%s\n", on_restart_trigger.action->name);
21317dd6b334SMichael Holzheu }
21327dd6b334SMichael Holzheu
on_restart_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t len)21337dd6b334SMichael Holzheu static ssize_t on_restart_store(struct kobject *kobj,
21347dd6b334SMichael Holzheu struct kobj_attribute *attr,
21357dd6b334SMichael Holzheu const char *buf, size_t len)
21367dd6b334SMichael Holzheu {
21377dd6b334SMichael Holzheu return set_trigger(buf, &on_restart_trigger, len);
21387dd6b334SMichael Holzheu }
21390f024379SSebastian Ott static struct kobj_attribute on_restart_attr = __ATTR_RW(on_restart);
21407dd6b334SMichael Holzheu
__do_restart(void * ignore)21418b646bd7SMartin Schwidefsky static void __do_restart(void *ignore)
21427dd6b334SMichael Holzheu {
21437dd6b334SMichael Holzheu smp_send_stop();
214460a0c68dSMichael Holzheu #ifdef CONFIG_CRASH_DUMP
214560a0c68dSMichael Holzheu crash_kexec(NULL);
214660a0c68dSMichael Holzheu #endif
21477dd6b334SMichael Holzheu on_restart_trigger.action->fn(&on_restart_trigger);
21487dd6b334SMichael Holzheu stop_run(&on_restart_trigger);
21497dd6b334SMichael Holzheu }
21507dd6b334SMichael Holzheu
do_restart(void * arg)2151b44913fcSAlexander Gordeev void do_restart(void *arg)
21528b646bd7SMartin Schwidefsky {
21533ab121abSMichael Holzheu tracing_off();
21543ab121abSMichael Holzheu debug_locks_off();
21553ab121abSMichael Holzheu lgr_info_log();
2156b44913fcSAlexander Gordeev smp_call_online_cpu(__do_restart, arg);
21578b646bd7SMartin Schwidefsky }
21588b646bd7SMartin Schwidefsky
215999ca4e58SMichael Holzheu /* on halt */
216099ca4e58SMichael Holzheu
216199ca4e58SMichael Holzheu static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action};
216299ca4e58SMichael Holzheu
on_halt_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)216399ca4e58SMichael Holzheu static ssize_t on_halt_show(struct kobject *kobj,
216499ca4e58SMichael Holzheu struct kobj_attribute *attr, char *page)
216599ca4e58SMichael Holzheu {
216699ca4e58SMichael Holzheu return sprintf(page, "%s\n", on_halt_trigger.action->name);
216799ca4e58SMichael Holzheu }
216899ca4e58SMichael Holzheu
on_halt_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t len)216999ca4e58SMichael Holzheu static ssize_t on_halt_store(struct kobject *kobj,
217099ca4e58SMichael Holzheu struct kobj_attribute *attr,
217199ca4e58SMichael Holzheu const char *buf, size_t len)
217299ca4e58SMichael Holzheu {
217399ca4e58SMichael Holzheu return set_trigger(buf, &on_halt_trigger, len);
217499ca4e58SMichael Holzheu }
21750f024379SSebastian Ott static struct kobj_attribute on_halt_attr = __ATTR_RW(on_halt);
217699ca4e58SMichael Holzheu
do_machine_halt(void)217799ca4e58SMichael Holzheu static void do_machine_halt(void)
217899ca4e58SMichael Holzheu {
217999ca4e58SMichael Holzheu smp_send_stop();
218099ca4e58SMichael Holzheu on_halt_trigger.action->fn(&on_halt_trigger);
218199ca4e58SMichael Holzheu stop_run(&on_halt_trigger);
218299ca4e58SMichael Holzheu }
218399ca4e58SMichael Holzheu void (*_machine_halt)(void) = do_machine_halt;
218499ca4e58SMichael Holzheu
218599ca4e58SMichael Holzheu /* on power off */
218699ca4e58SMichael Holzheu
218799ca4e58SMichael Holzheu static struct shutdown_trigger on_poff_trigger = {ON_POFF_STR, &stop_action};
218899ca4e58SMichael Holzheu
on_poff_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)218999ca4e58SMichael Holzheu static ssize_t on_poff_show(struct kobject *kobj,
219099ca4e58SMichael Holzheu struct kobj_attribute *attr, char *page)
219199ca4e58SMichael Holzheu {
219299ca4e58SMichael Holzheu return sprintf(page, "%s\n", on_poff_trigger.action->name);
219399ca4e58SMichael Holzheu }
219499ca4e58SMichael Holzheu
on_poff_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t len)219599ca4e58SMichael Holzheu static ssize_t on_poff_store(struct kobject *kobj,
219699ca4e58SMichael Holzheu struct kobj_attribute *attr,
219799ca4e58SMichael Holzheu const char *buf, size_t len)
219899ca4e58SMichael Holzheu {
219999ca4e58SMichael Holzheu return set_trigger(buf, &on_poff_trigger, len);
220099ca4e58SMichael Holzheu }
22010f024379SSebastian Ott static struct kobj_attribute on_poff_attr = __ATTR_RW(on_poff);
220299ca4e58SMichael Holzheu
do_machine_power_off(void)220399ca4e58SMichael Holzheu static void do_machine_power_off(void)
220499ca4e58SMichael Holzheu {
220599ca4e58SMichael Holzheu smp_send_stop();
220699ca4e58SMichael Holzheu on_poff_trigger.action->fn(&on_poff_trigger);
220799ca4e58SMichael Holzheu stop_run(&on_poff_trigger);
220899ca4e58SMichael Holzheu }
220999ca4e58SMichael Holzheu void (*_machine_power_off)(void) = do_machine_power_off;
221099ca4e58SMichael Holzheu
22110f024379SSebastian Ott static struct attribute *shutdown_action_attrs[] = {
22120f024379SSebastian Ott &on_restart_attr.attr,
22130f024379SSebastian Ott &on_reboot_attr.attr,
22140f024379SSebastian Ott &on_panic_attr.attr,
22150f024379SSebastian Ott &on_halt_attr.attr,
22160f024379SSebastian Ott &on_poff_attr.attr,
22170f024379SSebastian Ott NULL,
22180f024379SSebastian Ott };
22190f024379SSebastian Ott
22200f024379SSebastian Ott static struct attribute_group shutdown_action_attr_group = {
22210f024379SSebastian Ott .attrs = shutdown_action_attrs,
22220f024379SSebastian Ott };
22230f024379SSebastian Ott
shutdown_triggers_init(void)222499ca4e58SMichael Holzheu static void __init shutdown_triggers_init(void)
222599ca4e58SMichael Holzheu {
2226d91885beSGreg Kroah-Hartman shutdown_actions_kset = kset_create_and_add("shutdown_actions", NULL,
2227f62ed9e3SGreg Kroah-Hartman firmware_kobj);
2228d91885beSGreg Kroah-Hartman if (!shutdown_actions_kset)
222999ca4e58SMichael Holzheu goto fail;
22300f024379SSebastian Ott if (sysfs_create_group(&shutdown_actions_kset->kobj,
22310f024379SSebastian Ott &shutdown_action_attr_group))
22327dd6b334SMichael Holzheu goto fail;
223399ca4e58SMichael Holzheu return;
223499ca4e58SMichael Holzheu fail:
223599ca4e58SMichael Holzheu panic("shutdown_triggers_init failed\n");
2236ff6b8ea6SMichael Holzheu }
223799ca4e58SMichael Holzheu
shutdown_actions_init(void)223899ca4e58SMichael Holzheu static void __init shutdown_actions_init(void)
223999ca4e58SMichael Holzheu {
224099ca4e58SMichael Holzheu int i;
224199ca4e58SMichael Holzheu
224299ca4e58SMichael Holzheu for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
224399ca4e58SMichael Holzheu if (!shutdown_actions_list[i]->init)
224499ca4e58SMichael Holzheu continue;
224581088819SFrank Munzert shutdown_actions_list[i]->init_rc =
224681088819SFrank Munzert shutdown_actions_list[i]->init();
224799ca4e58SMichael Holzheu }
2248ff6b8ea6SMichael Holzheu }
2249ff6b8ea6SMichael Holzheu
s390_ipl_init(void)2250ff6b8ea6SMichael Holzheu static int __init s390_ipl_init(void)
2251ff6b8ea6SMichael Holzheu {
225269928601SMichael Holzheu char str[8] = {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40};
225369928601SMichael Holzheu
2254d5ab7a34SHeiko Carstens sclp_early_get_ipl_info(&sclp_ipl_info);
225569928601SMichael Holzheu /*
225669928601SMichael Holzheu * Fix loadparm: There are systems where the (SCSI) LOADPARM
225769928601SMichael Holzheu * returned by read SCP info is invalid (contains EBCDIC blanks)
225869928601SMichael Holzheu * when the system has been booted via diag308. In that case we use
225969928601SMichael Holzheu * the value from diag308, if available.
226069928601SMichael Holzheu *
226169928601SMichael Holzheu * There are also systems where diag308 store does not work in
226269928601SMichael Holzheu * case the system is booted from HMC. Fortunately in this case
226369928601SMichael Holzheu * READ SCP info provides the correct value.
226469928601SMichael Holzheu */
2265a0832b3aSVasily Gorbik if (memcmp(sclp_ipl_info.loadparm, str, sizeof(str)) == 0 && ipl_block_valid)
22665f1207fbSMartin Schwidefsky memcpy(sclp_ipl_info.loadparm, ipl_block.ccw.loadparm, LOADPARM_LEN);
226799ca4e58SMichael Holzheu shutdown_actions_init();
226899ca4e58SMichael Holzheu shutdown_triggers_init();
2269ff6b8ea6SMichael Holzheu return 0;
2270ff6b8ea6SMichael Holzheu }
2271ff6b8ea6SMichael Holzheu
2272ff6b8ea6SMichael Holzheu __initcall(s390_ipl_init);
227315e9b586SHeiko Carstens
strncpy_skip_quote(char * dst,char * src,int n)227499ca4e58SMichael Holzheu static void __init strncpy_skip_quote(char *dst, char *src, int n)
227599ca4e58SMichael Holzheu {
227699ca4e58SMichael Holzheu int sx, dx;
227799ca4e58SMichael Holzheu
227899ca4e58SMichael Holzheu dx = 0;
227999ca4e58SMichael Holzheu for (sx = 0; src[sx] != 0; sx++) {
228099ca4e58SMichael Holzheu if (src[sx] == '"')
228199ca4e58SMichael Holzheu continue;
228299ca4e58SMichael Holzheu dst[dx++] = src[sx];
228399ca4e58SMichael Holzheu if (dx >= n)
228499ca4e58SMichael Holzheu break;
228599ca4e58SMichael Holzheu }
228699ca4e58SMichael Holzheu }
228799ca4e58SMichael Holzheu
vmcmd_on_reboot_setup(char * str)228899ca4e58SMichael Holzheu static int __init vmcmd_on_reboot_setup(char *str)
228999ca4e58SMichael Holzheu {
229099ca4e58SMichael Holzheu if (!MACHINE_IS_VM)
229199ca4e58SMichael Holzheu return 1;
229299ca4e58SMichael Holzheu strncpy_skip_quote(vmcmd_on_reboot, str, 127);
229399ca4e58SMichael Holzheu vmcmd_on_reboot[127] = 0;
229499ca4e58SMichael Holzheu on_reboot_trigger.action = &vmcmd_action;
229599ca4e58SMichael Holzheu return 1;
229699ca4e58SMichael Holzheu }
229799ca4e58SMichael Holzheu __setup("vmreboot=", vmcmd_on_reboot_setup);
229899ca4e58SMichael Holzheu
vmcmd_on_panic_setup(char * str)229999ca4e58SMichael Holzheu static int __init vmcmd_on_panic_setup(char *str)
230099ca4e58SMichael Holzheu {
230199ca4e58SMichael Holzheu if (!MACHINE_IS_VM)
230299ca4e58SMichael Holzheu return 1;
230399ca4e58SMichael Holzheu strncpy_skip_quote(vmcmd_on_panic, str, 127);
230499ca4e58SMichael Holzheu vmcmd_on_panic[127] = 0;
230599ca4e58SMichael Holzheu on_panic_trigger.action = &vmcmd_action;
230699ca4e58SMichael Holzheu return 1;
230799ca4e58SMichael Holzheu }
230899ca4e58SMichael Holzheu __setup("vmpanic=", vmcmd_on_panic_setup);
230999ca4e58SMichael Holzheu
vmcmd_on_halt_setup(char * str)231099ca4e58SMichael Holzheu static int __init vmcmd_on_halt_setup(char *str)
231199ca4e58SMichael Holzheu {
231299ca4e58SMichael Holzheu if (!MACHINE_IS_VM)
231399ca4e58SMichael Holzheu return 1;
231499ca4e58SMichael Holzheu strncpy_skip_quote(vmcmd_on_halt, str, 127);
231599ca4e58SMichael Holzheu vmcmd_on_halt[127] = 0;
231699ca4e58SMichael Holzheu on_halt_trigger.action = &vmcmd_action;
231799ca4e58SMichael Holzheu return 1;
231899ca4e58SMichael Holzheu }
231999ca4e58SMichael Holzheu __setup("vmhalt=", vmcmd_on_halt_setup);
232099ca4e58SMichael Holzheu
vmcmd_on_poff_setup(char * str)232199ca4e58SMichael Holzheu static int __init vmcmd_on_poff_setup(char *str)
232299ca4e58SMichael Holzheu {
232399ca4e58SMichael Holzheu if (!MACHINE_IS_VM)
232499ca4e58SMichael Holzheu return 1;
232599ca4e58SMichael Holzheu strncpy_skip_quote(vmcmd_on_poff, str, 127);
232699ca4e58SMichael Holzheu vmcmd_on_poff[127] = 0;
232799ca4e58SMichael Holzheu on_poff_trigger.action = &vmcmd_action;
232899ca4e58SMichael Holzheu return 1;
232999ca4e58SMichael Holzheu }
233099ca4e58SMichael Holzheu __setup("vmpoff=", vmcmd_on_poff_setup);
233199ca4e58SMichael Holzheu
on_panic_notify(struct notifier_block * self,unsigned long event,void * data)233299ca4e58SMichael Holzheu static int on_panic_notify(struct notifier_block *self,
233399ca4e58SMichael Holzheu unsigned long event, void *data)
233499ca4e58SMichael Holzheu {
233599ca4e58SMichael Holzheu do_panic();
233699ca4e58SMichael Holzheu return NOTIFY_OK;
233799ca4e58SMichael Holzheu }
233899ca4e58SMichael Holzheu
233999ca4e58SMichael Holzheu static struct notifier_block on_panic_nb = {
234099ca4e58SMichael Holzheu .notifier_call = on_panic_notify,
23417e9b580eSMichael Holzheu .priority = INT_MIN,
234299ca4e58SMichael Holzheu };
234399ca4e58SMichael Holzheu
setup_ipl(void)234499ca4e58SMichael Holzheu void __init setup_ipl(void)
234599ca4e58SMichael Holzheu {
2346bdbfe185SVasily Gorbik BUILD_BUG_ON(sizeof(struct ipl_parameter_block) != PAGE_SIZE);
2347bdbfe185SVasily Gorbik
234899ca4e58SMichael Holzheu ipl_info.type = get_ipl_type();
234999ca4e58SMichael Holzheu switch (ipl_info.type) {
235099ca4e58SMichael Holzheu case IPL_TYPE_CCW:
235186c74d86SMartin Schwidefsky ipl_info.data.ccw.dev_id.ssid = ipl_block.ccw.ssid;
235286c74d86SMartin Schwidefsky ipl_info.data.ccw.dev_id.devno = ipl_block.ccw.devno;
235399ca4e58SMichael Holzheu break;
235487fd22e0SSven Schnelle case IPL_TYPE_ECKD:
2355e2d2a296SSven Schnelle case IPL_TYPE_ECKD_DUMP:
235687fd22e0SSven Schnelle ipl_info.data.eckd.dev_id.ssid = ipl_block.eckd.ssid;
235787fd22e0SSven Schnelle ipl_info.data.eckd.dev_id.devno = ipl_block.eckd.devno;
235887fd22e0SSven Schnelle break;
235999ca4e58SMichael Holzheu case IPL_TYPE_FCP:
236099ca4e58SMichael Holzheu case IPL_TYPE_FCP_DUMP:
236118e22a17SSebastian Ott ipl_info.data.fcp.dev_id.ssid = 0;
236286c74d86SMartin Schwidefsky ipl_info.data.fcp.dev_id.devno = ipl_block.fcp.devno;
236386c74d86SMartin Schwidefsky ipl_info.data.fcp.wwpn = ipl_block.fcp.wwpn;
236486c74d86SMartin Schwidefsky ipl_info.data.fcp.lun = ipl_block.fcp.lun;
236599ca4e58SMichael Holzheu break;
23663737e8eeSJason J. Herne case IPL_TYPE_NVME:
2367d70e38cbSJason J. Herne case IPL_TYPE_NVME_DUMP:
23683737e8eeSJason J. Herne ipl_info.data.nvme.fid = ipl_block.nvme.fid;
23693737e8eeSJason J. Herne ipl_info.data.nvme.nsid = ipl_block.nvme.nsid;
23703737e8eeSJason J. Herne break;
237199ca4e58SMichael Holzheu case IPL_TYPE_NSS:
237299ca4e58SMichael Holzheu case IPL_TYPE_UNKNOWN:
237399ca4e58SMichael Holzheu /* We have no info to copy */
237499ca4e58SMichael Holzheu break;
237599ca4e58SMichael Holzheu }
237699ca4e58SMichael Holzheu atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
237799ca4e58SMichael Holzheu }
237899ca4e58SMichael Holzheu
s390_reset_system(void)23791a36a39eSMartin Schwidefsky void s390_reset_system(void)
238015e9b586SHeiko Carstens {
238115e9b586SHeiko Carstens /* Disable prefixing */
238215e9b586SHeiko Carstens set_prefix(0);
238315e9b586SHeiko Carstens
238415e9b586SHeiko Carstens /* Disable lowcore protection */
238515e9b586SHeiko Carstens __ctl_clear_bit(0, 28);
2386c78d0c74SHeiko Carstens diag_amode31_ops.diag308_reset();
238760a0c68dSMichael Holzheu }
2388937347acSMartin Schwidefsky
2389937347acSMartin Schwidefsky #ifdef CONFIG_KEXEC_FILE
2390937347acSMartin Schwidefsky
ipl_report_add_component(struct ipl_report * report,struct kexec_buf * kbuf,unsigned char flags,unsigned short cert)2391937347acSMartin Schwidefsky int ipl_report_add_component(struct ipl_report *report, struct kexec_buf *kbuf,
2392937347acSMartin Schwidefsky unsigned char flags, unsigned short cert)
2393937347acSMartin Schwidefsky {
2394937347acSMartin Schwidefsky struct ipl_report_component *comp;
2395937347acSMartin Schwidefsky
2396937347acSMartin Schwidefsky comp = vzalloc(sizeof(*comp));
2397937347acSMartin Schwidefsky if (!comp)
2398937347acSMartin Schwidefsky return -ENOMEM;
2399937347acSMartin Schwidefsky list_add_tail(&comp->list, &report->components);
2400937347acSMartin Schwidefsky
2401937347acSMartin Schwidefsky comp->entry.addr = kbuf->mem;
2402937347acSMartin Schwidefsky comp->entry.len = kbuf->memsz;
2403937347acSMartin Schwidefsky comp->entry.flags = flags;
2404937347acSMartin Schwidefsky comp->entry.certificate_index = cert;
2405937347acSMartin Schwidefsky
2406937347acSMartin Schwidefsky report->size += sizeof(comp->entry);
2407937347acSMartin Schwidefsky
2408937347acSMartin Schwidefsky return 0;
2409937347acSMartin Schwidefsky }
2410937347acSMartin Schwidefsky
ipl_report_add_certificate(struct ipl_report * report,void * key,unsigned long addr,unsigned long len)2411937347acSMartin Schwidefsky int ipl_report_add_certificate(struct ipl_report *report, void *key,
2412937347acSMartin Schwidefsky unsigned long addr, unsigned long len)
2413937347acSMartin Schwidefsky {
2414937347acSMartin Schwidefsky struct ipl_report_certificate *cert;
2415937347acSMartin Schwidefsky
2416937347acSMartin Schwidefsky cert = vzalloc(sizeof(*cert));
2417937347acSMartin Schwidefsky if (!cert)
2418937347acSMartin Schwidefsky return -ENOMEM;
2419937347acSMartin Schwidefsky list_add_tail(&cert->list, &report->certificates);
2420937347acSMartin Schwidefsky
2421937347acSMartin Schwidefsky cert->entry.addr = addr;
2422937347acSMartin Schwidefsky cert->entry.len = len;
2423937347acSMartin Schwidefsky cert->key = key;
2424937347acSMartin Schwidefsky
2425937347acSMartin Schwidefsky report->size += sizeof(cert->entry);
2426937347acSMartin Schwidefsky report->size += cert->entry.len;
2427937347acSMartin Schwidefsky
2428937347acSMartin Schwidefsky return 0;
2429937347acSMartin Schwidefsky }
2430937347acSMartin Schwidefsky
ipl_report_init(struct ipl_parameter_block * ipib)2431937347acSMartin Schwidefsky struct ipl_report *ipl_report_init(struct ipl_parameter_block *ipib)
2432937347acSMartin Schwidefsky {
2433937347acSMartin Schwidefsky struct ipl_report *report;
2434937347acSMartin Schwidefsky
2435937347acSMartin Schwidefsky report = vzalloc(sizeof(*report));
2436937347acSMartin Schwidefsky if (!report)
2437937347acSMartin Schwidefsky return ERR_PTR(-ENOMEM);
2438937347acSMartin Schwidefsky
2439937347acSMartin Schwidefsky report->ipib = ipib;
2440937347acSMartin Schwidefsky INIT_LIST_HEAD(&report->components);
2441937347acSMartin Schwidefsky INIT_LIST_HEAD(&report->certificates);
2442937347acSMartin Schwidefsky
2443937347acSMartin Schwidefsky report->size = ALIGN(ipib->hdr.len, 8);
2444937347acSMartin Schwidefsky report->size += sizeof(struct ipl_rl_hdr);
2445937347acSMartin Schwidefsky report->size += sizeof(struct ipl_rb_components);
2446937347acSMartin Schwidefsky report->size += sizeof(struct ipl_rb_certificates);
2447937347acSMartin Schwidefsky
2448937347acSMartin Schwidefsky return report;
2449937347acSMartin Schwidefsky }
2450937347acSMartin Schwidefsky
ipl_report_finish(struct ipl_report * report)2451937347acSMartin Schwidefsky void *ipl_report_finish(struct ipl_report *report)
2452937347acSMartin Schwidefsky {
2453937347acSMartin Schwidefsky struct ipl_report_certificate *cert;
2454937347acSMartin Schwidefsky struct ipl_report_component *comp;
2455937347acSMartin Schwidefsky struct ipl_rb_certificates *certs;
2456937347acSMartin Schwidefsky struct ipl_parameter_block *ipib;
2457937347acSMartin Schwidefsky struct ipl_rb_components *comps;
2458937347acSMartin Schwidefsky struct ipl_rl_hdr *rl_hdr;
2459937347acSMartin Schwidefsky void *buf, *ptr;
2460937347acSMartin Schwidefsky
2461937347acSMartin Schwidefsky buf = vzalloc(report->size);
2462937347acSMartin Schwidefsky if (!buf)
246320c76e24SHeiko Carstens goto out;
2464937347acSMartin Schwidefsky ptr = buf;
2465937347acSMartin Schwidefsky
2466937347acSMartin Schwidefsky memcpy(ptr, report->ipib, report->ipib->hdr.len);
2467937347acSMartin Schwidefsky ipib = ptr;
2468937347acSMartin Schwidefsky if (ipl_secure_flag)
2469937347acSMartin Schwidefsky ipib->hdr.flags |= IPL_PL_FLAG_SIPL;
2470937347acSMartin Schwidefsky ipib->hdr.flags |= IPL_PL_FLAG_IPLSR;
2471937347acSMartin Schwidefsky ptr += report->ipib->hdr.len;
2472937347acSMartin Schwidefsky ptr = PTR_ALIGN(ptr, 8);
2473937347acSMartin Schwidefsky
2474937347acSMartin Schwidefsky rl_hdr = ptr;
2475937347acSMartin Schwidefsky ptr += sizeof(*rl_hdr);
2476937347acSMartin Schwidefsky
2477937347acSMartin Schwidefsky comps = ptr;
2478937347acSMartin Schwidefsky comps->rbt = IPL_RBT_COMPONENTS;
2479937347acSMartin Schwidefsky ptr += sizeof(*comps);
2480937347acSMartin Schwidefsky list_for_each_entry(comp, &report->components, list) {
2481937347acSMartin Schwidefsky memcpy(ptr, &comp->entry, sizeof(comp->entry));
2482937347acSMartin Schwidefsky ptr += sizeof(comp->entry);
2483937347acSMartin Schwidefsky }
2484937347acSMartin Schwidefsky comps->len = ptr - (void *)comps;
2485937347acSMartin Schwidefsky
2486937347acSMartin Schwidefsky certs = ptr;
2487937347acSMartin Schwidefsky certs->rbt = IPL_RBT_CERTIFICATES;
2488937347acSMartin Schwidefsky ptr += sizeof(*certs);
2489937347acSMartin Schwidefsky list_for_each_entry(cert, &report->certificates, list) {
2490937347acSMartin Schwidefsky memcpy(ptr, &cert->entry, sizeof(cert->entry));
2491937347acSMartin Schwidefsky ptr += sizeof(cert->entry);
2492937347acSMartin Schwidefsky }
2493937347acSMartin Schwidefsky certs->len = ptr - (void *)certs;
2494937347acSMartin Schwidefsky rl_hdr->len = ptr - (void *)rl_hdr;
2495937347acSMartin Schwidefsky
2496937347acSMartin Schwidefsky list_for_each_entry(cert, &report->certificates, list) {
2497937347acSMartin Schwidefsky memcpy(ptr, cert->key, cert->entry.len);
2498937347acSMartin Schwidefsky ptr += cert->entry.len;
2499937347acSMartin Schwidefsky }
2500937347acSMartin Schwidefsky
2501937347acSMartin Schwidefsky BUG_ON(ptr > buf + report->size);
250220c76e24SHeiko Carstens out:
2503937347acSMartin Schwidefsky return buf;
2504937347acSMartin Schwidefsky }
2505937347acSMartin Schwidefsky
ipl_report_free(struct ipl_report * report)2506937347acSMartin Schwidefsky int ipl_report_free(struct ipl_report *report)
2507937347acSMartin Schwidefsky {
2508937347acSMartin Schwidefsky struct ipl_report_component *comp, *ncomp;
2509937347acSMartin Schwidefsky struct ipl_report_certificate *cert, *ncert;
2510937347acSMartin Schwidefsky
2511937347acSMartin Schwidefsky list_for_each_entry_safe(comp, ncomp, &report->components, list)
2512937347acSMartin Schwidefsky vfree(comp);
2513937347acSMartin Schwidefsky
2514937347acSMartin Schwidefsky list_for_each_entry_safe(cert, ncert, &report->certificates, list)
2515937347acSMartin Schwidefsky vfree(cert);
2516937347acSMartin Schwidefsky
2517937347acSMartin Schwidefsky vfree(report);
2518937347acSMartin Schwidefsky
2519937347acSMartin Schwidefsky return 0;
2520937347acSMartin Schwidefsky }
2521937347acSMartin Schwidefsky
2522937347acSMartin Schwidefsky #endif
2523