xref: /openbmc/linux/arch/s390/kernel/ipl.c (revision b181f7029bd71238ac2754ce7052dffd69432085)
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