Commit 1a2ae03b authored by Gerald Schaefer's avatar Gerald Schaefer Committed by Vasily Gorbik

s390/ipl: add support to control memory clearing for FCP and CCW re-IPL

Re-IPL for both CCW and FCP is currently done by using diag 308 with the
"Load Clear" subcode, which means that all memory will be cleared.
This can increase re-IPL duration considerably on very large machines.

For CCW devices, there is also a "Load Normal" subcode that was only used
for dump kernels so far. For FCP devices, a similar "Load Normal" subcode
was introduced with z14. The "Load Normal" diag 308 subcode allows to
re-IPL without clearing memory.

This patch adds a new "clear" sysfs attribute to /sys/firmware/reipl for
both the ccw and fcp subdirectories, which can be set to either "0" or "1"
to disable or enable re-IPL with memory clearing. The default value is "0",
which disables memory clearing.
Signed-off-by: default avatarGerald Schaefer <gerald.schaefer@de.ibm.com>
Reviewed-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent 40501c70
...@@ -119,6 +119,7 @@ enum diag308_subcode { ...@@ -119,6 +119,7 @@ enum diag308_subcode {
DIAG308_LOAD_NORMAL_DUMP = 4, DIAG308_LOAD_NORMAL_DUMP = 4,
DIAG308_SET = 5, DIAG308_SET = 5,
DIAG308_STORE = 6, DIAG308_STORE = 6,
DIAG308_LOAD_NORMAL = 7,
}; };
enum diag308_rc { enum diag308_rc {
......
...@@ -144,6 +144,9 @@ static struct ipl_parameter_block *dump_block_ccw; ...@@ -144,6 +144,9 @@ static struct ipl_parameter_block *dump_block_ccw;
static struct sclp_ipl_info sclp_ipl_info; static struct sclp_ipl_info sclp_ipl_info;
static bool reipl_fcp_clear;
static bool reipl_ccw_clear;
static inline int __diag308(unsigned long subcode, void *addr) static inline int __diag308(unsigned long subcode, void *addr)
{ {
register unsigned long _addr asm("0") = (unsigned long) addr; register unsigned long _addr asm("0") = (unsigned long) addr;
...@@ -691,6 +694,21 @@ static struct kobj_attribute sys_reipl_fcp_loadparm_attr = ...@@ -691,6 +694,21 @@ static struct kobj_attribute sys_reipl_fcp_loadparm_attr =
__ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_fcp_loadparm_show, __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_fcp_loadparm_show,
reipl_fcp_loadparm_store); reipl_fcp_loadparm_store);
static ssize_t reipl_fcp_clear_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
{
return sprintf(page, "%u\n", reipl_fcp_clear);
}
static ssize_t reipl_fcp_clear_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t len)
{
if (strtobool(buf, &reipl_fcp_clear) < 0)
return -EINVAL;
return len;
}
static struct attribute *reipl_fcp_attrs[] = { static struct attribute *reipl_fcp_attrs[] = {
&sys_reipl_fcp_device_attr.attr, &sys_reipl_fcp_device_attr.attr,
&sys_reipl_fcp_wwpn_attr.attr, &sys_reipl_fcp_wwpn_attr.attr,
...@@ -706,6 +724,9 @@ static struct attribute_group reipl_fcp_attr_group = { ...@@ -706,6 +724,9 @@ static struct attribute_group reipl_fcp_attr_group = {
.bin_attrs = reipl_fcp_bin_attrs, .bin_attrs = reipl_fcp_bin_attrs,
}; };
static struct kobj_attribute sys_reipl_fcp_clear_attr =
__ATTR(clear, 0644, reipl_fcp_clear_show, reipl_fcp_clear_store);
/* CCW reipl device attributes */ /* CCW reipl device attributes */
DEFINE_IPL_CCW_ATTR_RW(reipl_ccw, device, reipl_block_ccw->ccw); DEFINE_IPL_CCW_ATTR_RW(reipl_ccw, device, reipl_block_ccw->ccw);
...@@ -741,16 +762,36 @@ static struct kobj_attribute sys_reipl_ccw_loadparm_attr = ...@@ -741,16 +762,36 @@ static struct kobj_attribute sys_reipl_ccw_loadparm_attr =
__ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show, __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show,
reipl_ccw_loadparm_store); reipl_ccw_loadparm_store);
static ssize_t reipl_ccw_clear_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
{
return sprintf(page, "%u\n", reipl_ccw_clear);
}
static ssize_t reipl_ccw_clear_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t len)
{
if (strtobool(buf, &reipl_ccw_clear) < 0)
return -EINVAL;
return len;
}
static struct kobj_attribute sys_reipl_ccw_clear_attr =
__ATTR(clear, 0644, reipl_ccw_clear_show, reipl_ccw_clear_store);
static struct attribute *reipl_ccw_attrs_vm[] = { static struct attribute *reipl_ccw_attrs_vm[] = {
&sys_reipl_ccw_device_attr.attr, &sys_reipl_ccw_device_attr.attr,
&sys_reipl_ccw_loadparm_attr.attr, &sys_reipl_ccw_loadparm_attr.attr,
&sys_reipl_ccw_vmparm_attr.attr, &sys_reipl_ccw_vmparm_attr.attr,
&sys_reipl_ccw_clear_attr.attr,
NULL, NULL,
}; };
static struct attribute *reipl_ccw_attrs_lpar[] = { static struct attribute *reipl_ccw_attrs_lpar[] = {
&sys_reipl_ccw_device_attr.attr, &sys_reipl_ccw_device_attr.attr,
&sys_reipl_ccw_loadparm_attr.attr, &sys_reipl_ccw_loadparm_attr.attr,
&sys_reipl_ccw_clear_attr.attr,
NULL, NULL,
}; };
...@@ -892,11 +933,17 @@ static void __reipl_run(void *unused) ...@@ -892,11 +933,17 @@ static void __reipl_run(void *unused)
switch (reipl_type) { switch (reipl_type) {
case IPL_TYPE_CCW: case IPL_TYPE_CCW:
diag308(DIAG308_SET, reipl_block_ccw); diag308(DIAG308_SET, reipl_block_ccw);
if (reipl_ccw_clear)
diag308(DIAG308_LOAD_CLEAR, NULL); diag308(DIAG308_LOAD_CLEAR, NULL);
else
diag308(DIAG308_LOAD_NORMAL_DUMP, NULL);
break; break;
case IPL_TYPE_FCP: case IPL_TYPE_FCP:
diag308(DIAG308_SET, reipl_block_fcp); diag308(DIAG308_SET, reipl_block_fcp);
if (reipl_fcp_clear)
diag308(DIAG308_LOAD_CLEAR, NULL); diag308(DIAG308_LOAD_CLEAR, NULL);
else
diag308(DIAG308_LOAD_NORMAL, NULL);
break; break;
case IPL_TYPE_NSS: case IPL_TYPE_NSS:
diag308(DIAG308_SET, reipl_block_nss); diag308(DIAG308_SET, reipl_block_nss);
...@@ -1008,11 +1055,16 @@ static int __init reipl_fcp_init(void) ...@@ -1008,11 +1055,16 @@ static int __init reipl_fcp_init(void)
} }
rc = sysfs_create_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group); rc = sysfs_create_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group);
if (rc) { if (rc)
kset_unregister(reipl_fcp_kset); goto out1;
free_page((unsigned long) reipl_block_fcp);
return rc; if (test_facility(141)) {
} rc = sysfs_create_file(&reipl_fcp_kset->kobj,
&sys_reipl_fcp_clear_attr.attr);
if (rc)
goto out2;
} else
reipl_fcp_clear = true;
if (ipl_info.type == IPL_TYPE_FCP) { if (ipl_info.type == IPL_TYPE_FCP) {
memcpy(reipl_block_fcp, &ipl_block, sizeof(ipl_block)); memcpy(reipl_block_fcp, &ipl_block, sizeof(ipl_block));
...@@ -1032,6 +1084,13 @@ static int __init reipl_fcp_init(void) ...@@ -1032,6 +1084,13 @@ static int __init reipl_fcp_init(void)
} }
reipl_capabilities |= IPL_TYPE_FCP; reipl_capabilities |= IPL_TYPE_FCP;
return 0; return 0;
out2:
sysfs_remove_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group);
out1:
kset_unregister(reipl_fcp_kset);
free_page((unsigned long) reipl_block_fcp);
return rc;
} }
static int __init reipl_type_init(void) static int __init reipl_type_init(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment