s390/ipl: add eckd dump support
authorSven Schnelle <svens@linux.ibm.com>
Wed, 5 Oct 2022 08:17:41 +0000 (10:17 +0200)
committerAlexander Gordeev <agordeev@linux.ibm.com>
Tue, 6 Dec 2022 15:18:22 +0000 (16:18 +0100)
This adds support to use ECKD disks as dump device
to linux. The new dump type is called 'eckd_dump', parameters
are the same as for eckd ipl.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
arch/s390/boot/ipl_parm.c
arch/s390/include/asm/ipl.h
arch/s390/include/uapi/asm/ipl.h
arch/s390/kernel/ipl.c
drivers/s390/char/zcore.c

index c358f51..c1f8f79 100644 (file)
@@ -77,6 +77,9 @@ bool is_ipl_block_dump(void)
        if (ipl_block.pb0_hdr.pbt == IPL_PBT_NVME &&
            ipl_block.nvme.opt == IPL_PB0_NVME_OPT_DUMP)
                return true;
+       if (ipl_block.pb0_hdr.pbt == IPL_PBT_ECKD &&
+           ipl_block.eckd.opt == IPL_PB0_ECKD_OPT_DUMP)
+               return true;
        return false;
 }
 
index 1396ed0..b0d0003 100644 (file)
@@ -74,6 +74,7 @@ enum ipl_type {
        IPL_TYPE_NVME           = 32,
        IPL_TYPE_NVME_DUMP      = 64,
        IPL_TYPE_ECKD           = 128,
+       IPL_TYPE_ECKD_DUMP      = 256,
 };
 
 struct ipl_info
@@ -108,6 +109,7 @@ extern void set_os_info_reipl_block(void);
 static inline bool is_ipl_type_dump(void)
 {
        return (ipl_info.type == IPL_TYPE_FCP_DUMP) ||
+               (ipl_info.type == IPL_TYPE_ECKD_DUMP) ||
                (ipl_info.type == IPL_TYPE_NVME_DUMP);
 }
 
index 3eb71a5..2cd28af 100644 (file)
@@ -138,6 +138,7 @@ struct ipl_pb0_eckd {
 } __packed;
 
 #define IPL_PB0_ECKD_OPT_IPL   0x10
+#define IPL_PB0_ECKD_OPT_DUMP  0x20
 
 #define IPL_PB0_CCW_VM_FLAG_NSS                0x80
 #define IPL_PB0_CCW_VM_FLAG_VP         0x40
index 7d8ddd8..b8d4f07 100644 (file)
@@ -41,6 +41,7 @@
 #define IPL_UNKNOWN_STR                "unknown"
 #define IPL_CCW_STR            "ccw"
 #define IPL_ECKD_STR           "eckd"
+#define IPL_ECKD_DUMP_STR      "eckd_dump"
 #define IPL_FCP_STR            "fcp"
 #define IPL_FCP_DUMP_STR       "fcp_dump"
 #define IPL_NVME_STR           "nvme"
@@ -48,6 +49,7 @@
 #define IPL_NSS_STR            "nss"
 
 #define DUMP_CCW_STR           "ccw"
+#define DUMP_ECKD_STR          "eckd"
 #define DUMP_FCP_STR           "fcp"
 #define DUMP_NVME_STR          "nvme"
 #define DUMP_NONE_STR          "none"
@@ -96,6 +98,8 @@ static char *ipl_type_str(enum ipl_type type)
                return IPL_CCW_STR;
        case IPL_TYPE_ECKD:
                return IPL_ECKD_STR;
+       case IPL_TYPE_ECKD_DUMP:
+               return IPL_ECKD_DUMP_STR;
        case IPL_TYPE_FCP:
                return IPL_FCP_STR;
        case IPL_TYPE_FCP_DUMP:
@@ -117,6 +121,7 @@ enum dump_type {
        DUMP_TYPE_CCW   = 2,
        DUMP_TYPE_FCP   = 4,
        DUMP_TYPE_NVME  = 8,
+       DUMP_TYPE_ECKD  = 16,
 };
 
 static char *dump_type_str(enum dump_type type)
@@ -126,6 +131,8 @@ static char *dump_type_str(enum dump_type type)
                return DUMP_NONE_STR;
        case DUMP_TYPE_CCW:
                return DUMP_CCW_STR;
+       case DUMP_TYPE_ECKD:
+               return DUMP_ECKD_STR;
        case DUMP_TYPE_FCP:
                return DUMP_FCP_STR;
        case DUMP_TYPE_NVME:
@@ -160,6 +167,7 @@ static enum dump_type dump_type = DUMP_TYPE_NONE;
 static struct ipl_parameter_block *dump_block_fcp;
 static struct ipl_parameter_block *dump_block_nvme;
 static struct ipl_parameter_block *dump_block_ccw;
+static struct ipl_parameter_block *dump_block_eckd;
 
 static struct sclp_ipl_info sclp_ipl_info;
 
@@ -288,7 +296,10 @@ static __init enum ipl_type get_ipl_type(void)
                else
                        return IPL_TYPE_NVME;
        case IPL_PBT_ECKD:
-               return IPL_TYPE_ECKD;
+               if (ipl_block.eckd.opt == IPL_PB0_ECKD_OPT_DUMP)
+                       return IPL_TYPE_ECKD_DUMP;
+               else
+                       return IPL_TYPE_ECKD;
        }
        return IPL_TYPE_UNKNOWN;
 }
@@ -343,6 +354,7 @@ static ssize_t sys_ipl_device_show(struct kobject *kobj,
                return sprintf(page, "0.%x.%04x\n", ipl_block.ccw.ssid,
                               ipl_block.ccw.devno);
        case IPL_TYPE_ECKD:
+       case IPL_TYPE_ECKD_DUMP:
                return sprintf(page, "0.%x.%04x\n", ipl_block.eckd.ssid,
                               ipl_block.eckd.devno);
        case IPL_TYPE_FCP:
@@ -1368,6 +1380,7 @@ static void __reipl_run(void *unused)
                break;
        case IPL_TYPE_FCP_DUMP:
        case IPL_TYPE_NVME_DUMP:
+       case IPL_TYPE_ECKD_DUMP:
                break;
        }
        disabled_wait();
@@ -1736,6 +1749,31 @@ static struct attribute_group dump_nvme_attr_group = {
        .attrs = dump_nvme_attrs,
 };
 
+/* ECKD dump device attributes */
+DEFINE_IPL_CCW_ATTR_RW(dump_eckd, device, dump_block_eckd->eckd);
+DEFINE_IPL_ATTR_RW(dump_eckd, bootprog, "%lld\n", "%llx\n",
+                  dump_block_eckd->eckd.bootprog);
+
+IPL_ATTR_BR_CHR_SHOW_FN(dump, dump_block_eckd->eckd);
+IPL_ATTR_BR_CHR_STORE_FN(dump, dump_block_eckd->eckd);
+
+static struct kobj_attribute sys_dump_eckd_br_chr_attr =
+       __ATTR(br_chr, (S_IRUGO | S_IWUSR),
+              eckd_dump_br_chr_show,
+              eckd_dump_br_chr_store);
+
+static struct attribute *dump_eckd_attrs[] = {
+       &sys_dump_eckd_device_attr.attr,
+       &sys_dump_eckd_bootprog_attr.attr,
+       &sys_dump_eckd_br_chr_attr.attr,
+       NULL,
+};
+
+static struct attribute_group dump_eckd_attr_group = {
+       .name  = IPL_ECKD_STR,
+       .attrs = dump_eckd_attrs,
+};
+
 /* CCW dump device attributes */
 DEFINE_IPL_CCW_ATTR_RW(dump_ccw, device, dump_block_ccw->ccw);
 
@@ -1775,6 +1813,8 @@ static ssize_t dump_type_store(struct kobject *kobj,
                rc = dump_set_type(DUMP_TYPE_NONE);
        else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0)
                rc = dump_set_type(DUMP_TYPE_CCW);
+       else if (strncmp(buf, DUMP_ECKD_STR, strlen(DUMP_ECKD_STR)) == 0)
+               rc = dump_set_type(DUMP_TYPE_ECKD);
        else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
                rc = dump_set_type(DUMP_TYPE_FCP);
        else if (strncmp(buf, DUMP_NVME_STR, strlen(DUMP_NVME_STR)) == 0)
@@ -1803,6 +1843,9 @@ static void __dump_run(void *unused)
        case DUMP_TYPE_CCW:
                diag308_dump(dump_block_ccw);
                break;
+       case DUMP_TYPE_ECKD:
+               diag308_dump(dump_block_eckd);
+               break;
        case DUMP_TYPE_FCP:
                diag308_dump(dump_block_fcp);
                break;
@@ -1888,6 +1931,29 @@ static int __init dump_nvme_init(void)
        return 0;
 }
 
+static int __init dump_eckd_init(void)
+{
+       int rc;
+
+       if (!sclp_ipl_info.has_dump || !sclp.has_sipl_eckd)
+               return 0; /* LDIPL DUMP is not installed */
+       dump_block_eckd = (void *)get_zeroed_page(GFP_KERNEL);
+       if (!dump_block_eckd)
+               return -ENOMEM;
+       rc = sysfs_create_group(&dump_kset->kobj, &dump_eckd_attr_group);
+       if (rc) {
+               free_page((unsigned long)dump_block_eckd);
+               return rc;
+       }
+       dump_block_eckd->hdr.len = IPL_BP_ECKD_LEN;
+       dump_block_eckd->hdr.version = IPL_PARM_BLOCK_VERSION;
+       dump_block_eckd->eckd.len = IPL_BP0_ECKD_LEN;
+       dump_block_eckd->eckd.pbt = IPL_PBT_ECKD;
+       dump_block_eckd->eckd.opt = IPL_PB0_ECKD_OPT_DUMP;
+       dump_capabilities |= DUMP_TYPE_ECKD;
+       return 0;
+}
+
 static int __init dump_init(void)
 {
        int rc;
@@ -1903,6 +1969,9 @@ static int __init dump_init(void)
        rc = dump_ccw_init();
        if (rc)
                return rc;
+       rc = dump_eckd_init();
+       if (rc)
+               return rc;
        rc = dump_fcp_init();
        if (rc)
                return rc;
@@ -2337,6 +2406,7 @@ void __init setup_ipl(void)
                ipl_info.data.ccw.dev_id.devno = ipl_block.ccw.devno;
                break;
        case IPL_TYPE_ECKD:
+       case IPL_TYPE_ECKD_DUMP:
                ipl_info.data.eckd.dev_id.ssid = ipl_block.eckd.ssid;
                ipl_info.data.eckd.dev_id.devno = ipl_block.eckd.devno;
                break;
index 6165e6a..b30670c 100644 (file)
@@ -282,6 +282,10 @@ static int __init zcore_init(void)
                TRACE("type:   nvme\n");
                TRACE("fid:    %x\n", ipl_info.data.nvme.fid);
                TRACE("nsid:   %x\n", ipl_info.data.nvme.nsid);
+       } else if (ipl_info.type == IPL_TYPE_ECKD_DUMP) {
+               TRACE("type:   eckd\n");
+               TRACE("devno:  %x\n", ipl_info.data.eckd.dev_id.devno);
+               TRACE("ssid:   %x\n", ipl_info.data.eckd.dev_id.ssid);
        }
 
        rc = sclp_sdias_init();