s390/ipl: add support to control memory clearing for FCP and CCW re-IPL
authorGerald Schaefer <gerald.schaefer@de.ibm.com>
Thu, 20 Feb 2020 15:22:30 +0000 (16:22 +0100)
committerVasily Gorbik <gor@linux.ibm.com>
Mon, 23 Mar 2020 12:41:54 +0000 (13:41 +0100)
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: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
arch/s390/include/asm/ipl.h
arch/s390/kernel/ipl.c

index 084e71b..b63bd66 100644 (file)
@@ -119,6 +119,7 @@ enum diag308_subcode  {
        DIAG308_LOAD_NORMAL_DUMP = 4,
        DIAG308_SET = 5,
        DIAG308_STORE = 6,
+       DIAG308_LOAD_NORMAL = 7,
 };
 
 enum diag308_rc {
index 6837aff..4a71061 100644 (file)
@@ -144,6 +144,9 @@ static struct ipl_parameter_block *dump_block_ccw;
 
 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)
 {
        register unsigned long _addr asm("0") = (unsigned long) addr;
@@ -691,6 +694,21 @@ static struct kobj_attribute sys_reipl_fcp_loadparm_attr =
        __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_fcp_loadparm_show,
                                            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[] = {
        &sys_reipl_fcp_device_attr.attr,
        &sys_reipl_fcp_wwpn_attr.attr,
@@ -706,6 +724,9 @@ static struct attribute_group reipl_fcp_attr_group = {
        .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 */
 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 =
        __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show,
                                            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[] = {
        &sys_reipl_ccw_device_attr.attr,
        &sys_reipl_ccw_loadparm_attr.attr,
        &sys_reipl_ccw_vmparm_attr.attr,
+       &sys_reipl_ccw_clear_attr.attr,
        NULL,
 };
 
 static struct attribute *reipl_ccw_attrs_lpar[] = {
        &sys_reipl_ccw_device_attr.attr,
        &sys_reipl_ccw_loadparm_attr.attr,
+       &sys_reipl_ccw_clear_attr.attr,
        NULL,
 };
 
@@ -892,11 +933,17 @@ static void __reipl_run(void *unused)
        switch (reipl_type) {
        case IPL_TYPE_CCW:
                diag308(DIAG308_SET, reipl_block_ccw);
-               diag308(DIAG308_LOAD_CLEAR, NULL);
+               if (reipl_ccw_clear)
+                       diag308(DIAG308_LOAD_CLEAR, NULL);
+               else
+                       diag308(DIAG308_LOAD_NORMAL_DUMP, NULL);
                break;
        case IPL_TYPE_FCP:
                diag308(DIAG308_SET, reipl_block_fcp);
-               diag308(DIAG308_LOAD_CLEAR, NULL);
+               if (reipl_fcp_clear)
+                       diag308(DIAG308_LOAD_CLEAR, NULL);
+               else
+                       diag308(DIAG308_LOAD_NORMAL, NULL);
                break;
        case IPL_TYPE_NSS:
                diag308(DIAG308_SET, reipl_block_nss);
@@ -1008,11 +1055,16 @@ static int __init reipl_fcp_init(void)
        }
 
        rc = sysfs_create_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group);
-       if (rc) {
-               kset_unregister(reipl_fcp_kset);
-               free_page((unsigned long) reipl_block_fcp);
-               return rc;
-       }
+       if (rc)
+               goto out1;
+
+       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) {
                memcpy(reipl_block_fcp, &ipl_block, sizeof(ipl_block));
@@ -1032,6 +1084,13 @@ static int __init reipl_fcp_init(void)
        }
        reipl_capabilities |= IPL_TYPE_FCP;
        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)