s390/ipl: add eckd support
authorSven Schnelle <svens@linux.ibm.com>
Wed, 5 Oct 2022 08:17:40 +0000 (10:17 +0200)
committerAlexander Gordeev <agordeev@linux.ibm.com>
Tue, 6 Dec 2022 15:18:21 +0000 (16:18 +0100)
This adds support to IPL from ECKD DASDs to linux.
It introduces a few sysfs files in /sys/firmware/reipl/eckd:

bootprog: the boot program selector
clear:    whether to issue a diag308 LOAD_NORMAL or LOAD_CLEAR
device:   the device to ipl from
br_chr:   Cylinder/Head/Record number to read the bootrecord from.
          Might be '0' or 'auto' if it should be read from the
  volume label.
scpdata:  data to be passed to the ipl'd program.

The new ipl type is called 'eckd'.

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/asm/sclp.h
arch/s390/include/uapi/asm/ipl.h
arch/s390/kernel/ipl.c
drivers/s390/char/sclp_early.c

index ca78d6162245a6d1a2324e24ac51fe95bd81aef2..c358f51ed3e549a2875e317ed316921dbf22ffc7 100644 (file)
@@ -108,6 +108,11 @@ static size_t ipl_block_get_ascii_scpdata(char *dest, size_t size,
                scp_data_len = ipb->nvme.scp_data_len;
                scp_data = ipb->nvme.scp_data;
                break;
+       case IPL_PBT_ECKD:
+               scp_data_len = ipb->eckd.scp_data_len;
+               scp_data = ipb->eckd.scp_data;
+               break;
+
        default:
                goto out;
        }
@@ -153,6 +158,7 @@ static void append_ipl_block_parm(void)
                break;
        case IPL_PBT_FCP:
        case IPL_PBT_NVME:
+       case IPL_PBT_ECKD:
                rc = ipl_block_get_ascii_scpdata(
                        parm, COMMAND_LINE_SIZE - len - 1, &ipl_block);
                break;
index a405b6bb89fbecdb8267fa5febb083c35e3d66e3..1396ed05c6aa10c32562a04c5147feb21242223e 100644 (file)
@@ -22,6 +22,7 @@ struct ipl_parameter_block {
                struct ipl_pb0_common common;
                struct ipl_pb0_fcp fcp;
                struct ipl_pb0_ccw ccw;
+               struct ipl_pb0_eckd eckd;
                struct ipl_pb0_nvme nvme;
                char raw[PAGE_SIZE - sizeof(struct ipl_pl_hdr)];
        };
@@ -41,6 +42,10 @@ struct ipl_parameter_block {
                              sizeof(struct ipl_pb0_ccw))
 #define IPL_BP0_CCW_LEN (sizeof(struct ipl_pb0_ccw))
 
+#define IPL_BP_ECKD_LEN (sizeof(struct ipl_pl_hdr) + \
+                             sizeof(struct ipl_pb0_eckd))
+#define IPL_BP0_ECKD_LEN (sizeof(struct ipl_pb0_eckd))
+
 #define IPL_MAX_SUPPORTED_VERSION (0)
 
 #define IPL_RB_CERT_UNKNOWN ((unsigned short)-1)
@@ -68,6 +73,7 @@ enum ipl_type {
        IPL_TYPE_NSS            = 16,
        IPL_TYPE_NVME           = 32,
        IPL_TYPE_NVME_DUMP      = 64,
+       IPL_TYPE_ECKD           = 128,
 };
 
 struct ipl_info
@@ -77,6 +83,9 @@ struct ipl_info
                struct {
                        struct ccw_dev_id dev_id;
                } ccw;
+               struct {
+                       struct ccw_dev_id dev_id;
+               } eckd;
                struct {
                        struct ccw_dev_id dev_id;
                        u64 wwpn;
index 9d4c7f71e070f1092b05fb2a8d3dde66e7726f02..67a24dda17b6b8fd23ebea546ef89d37c6c6ff65 100644 (file)
@@ -87,6 +87,7 @@ struct sclp_info {
        unsigned char has_gisaf : 1;
        unsigned char has_diag318 : 1;
        unsigned char has_sipl : 1;
+       unsigned char has_sipl_eckd : 1;
        unsigned char has_dirq : 1;
        unsigned char has_iplcc : 1;
        unsigned char has_zpci_lsi : 1;
index d1ecd5d722a0a3ecb4308f5904e810f6e3584b05..3eb71a594590b229d71696c897ffae9f2f9d6e8f 100644 (file)
@@ -27,6 +27,7 @@ enum ipl_pbt {
        IPL_PBT_FCP = 0,
        IPL_PBT_SCP_DATA = 1,
        IPL_PBT_CCW = 2,
+       IPL_PBT_ECKD = 3,
        IPL_PBT_NVME = 4,
 };
 
@@ -111,6 +112,33 @@ struct ipl_pb0_ccw {
        __u8  reserved5[8];
 } __packed;
 
+/* IPL Parameter Block 0 for ECKD */
+struct ipl_pb0_eckd {
+       __u32 len;
+       __u8  pbt;
+       __u8  reserved1[3];
+       __u32 reserved2[78];
+       __u8  opt;
+       __u8  reserved4[4];
+       __u8  reserved5:5;
+       __u8  ssid:3;
+       __u16 devno;
+       __u32 reserved6[5];
+       __u32 bootprog;
+       __u8  reserved7[12];
+       struct {
+               __u16 cyl;
+               __u8 head;
+               __u8 record;
+               __u32 reserved;
+       } br_chr __packed;
+       __u32 scp_data_len;
+       __u8  reserved8[260];
+       __u8  scp_data[];
+} __packed;
+
+#define IPL_PB0_ECKD_OPT_IPL   0x10
+
 #define IPL_PB0_CCW_VM_FLAG_NSS                0x80
 #define IPL_PB0_CCW_VM_FLAG_VP         0x40
 
index cdd575d7a91abb98c373347078c800050aa001b7..7d8ddd8b79d5fcd0e8c16e496fb673b55559c9fe 100644 (file)
@@ -40,6 +40,7 @@
 
 #define IPL_UNKNOWN_STR                "unknown"
 #define IPL_CCW_STR            "ccw"
+#define IPL_ECKD_STR           "eckd"
 #define IPL_FCP_STR            "fcp"
 #define IPL_FCP_DUMP_STR       "fcp_dump"
 #define IPL_NVME_STR           "nvme"
@@ -93,6 +94,8 @@ static char *ipl_type_str(enum ipl_type type)
        switch (type) {
        case IPL_TYPE_CCW:
                return IPL_CCW_STR;
+       case IPL_TYPE_ECKD:
+               return IPL_ECKD_STR;
        case IPL_TYPE_FCP:
                return IPL_FCP_STR;
        case IPL_TYPE_FCP_DUMP:
@@ -148,6 +151,7 @@ static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
 static struct ipl_parameter_block *reipl_block_fcp;
 static struct ipl_parameter_block *reipl_block_nvme;
 static struct ipl_parameter_block *reipl_block_ccw;
+static struct ipl_parameter_block *reipl_block_eckd;
 static struct ipl_parameter_block *reipl_block_nss;
 static struct ipl_parameter_block *reipl_block_actual;
 
@@ -162,6 +166,7 @@ static struct sclp_ipl_info sclp_ipl_info;
 static bool reipl_nvme_clear;
 static bool reipl_fcp_clear;
 static bool reipl_ccw_clear;
+static bool reipl_eckd_clear;
 
 static inline int __diag308(unsigned long subcode, void *addr)
 {
@@ -282,6 +287,8 @@ static __init enum ipl_type get_ipl_type(void)
                        return IPL_TYPE_NVME_DUMP;
                else
                        return IPL_TYPE_NVME;
+       case IPL_PBT_ECKD:
+               return IPL_TYPE_ECKD;
        }
        return IPL_TYPE_UNKNOWN;
 }
@@ -335,6 +342,9 @@ static ssize_t sys_ipl_device_show(struct kobject *kobj,
        case IPL_TYPE_CCW:
                return sprintf(page, "0.%x.%04x\n", ipl_block.ccw.ssid,
                               ipl_block.ccw.devno);
+       case IPL_TYPE_ECKD:
+               return sprintf(page, "0.%x.%04x\n", ipl_block.eckd.ssid,
+                              ipl_block.eckd.devno);
        case IPL_TYPE_FCP:
        case IPL_TYPE_FCP_DUMP:
                return sprintf(page, "0.0.%04x\n", ipl_block.fcp.devno);
@@ -380,12 +390,25 @@ static ssize_t ipl_nvme_scp_data_read(struct file *filp, struct kobject *kobj,
        return memory_read_from_buffer(buf, count, &off, scp_data, size);
 }
 
+static ssize_t ipl_eckd_scp_data_read(struct file *filp, struct kobject *kobj,
+                                     struct bin_attribute *attr, char *buf,
+                                     loff_t off, size_t count)
+{
+       unsigned int size = ipl_block.eckd.scp_data_len;
+       void *scp_data = &ipl_block.eckd.scp_data;
+
+       return memory_read_from_buffer(buf, count, &off, scp_data, size);
+}
+
 static struct bin_attribute ipl_scp_data_attr =
        __BIN_ATTR(scp_data, S_IRUGO, ipl_scp_data_read, NULL, PAGE_SIZE);
 
 static struct bin_attribute ipl_nvme_scp_data_attr =
        __BIN_ATTR(scp_data, S_IRUGO, ipl_nvme_scp_data_read, NULL, PAGE_SIZE);
 
+static struct bin_attribute ipl_eckd_scp_data_attr =
+       __BIN_ATTR(scp_data, S_IRUGO, ipl_eckd_scp_data_read, NULL, PAGE_SIZE);
+
 static struct bin_attribute *ipl_fcp_bin_attrs[] = {
        &ipl_parameter_attr,
        &ipl_scp_data_attr,
@@ -398,6 +421,12 @@ static struct bin_attribute *ipl_nvme_bin_attrs[] = {
        NULL,
 };
 
+static struct bin_attribute *ipl_eckd_bin_attrs[] = {
+       &ipl_parameter_attr,
+       &ipl_eckd_scp_data_attr,
+       NULL,
+};
+
 /* FCP ipl device attributes */
 
 DEFINE_IPL_ATTR_RO(ipl_fcp, wwpn, "0x%016llx\n",
@@ -419,6 +448,88 @@ DEFINE_IPL_ATTR_RO(ipl_nvme, bootprog, "%lld\n",
 DEFINE_IPL_ATTR_RO(ipl_nvme, br_lba, "%lld\n",
                   (unsigned long long)ipl_block.nvme.br_lba);
 
+/* ECKD ipl device attributes */
+DEFINE_IPL_ATTR_RO(ipl_eckd, bootprog, "%lld\n",
+                  (unsigned long long)ipl_block.eckd.bootprog);
+
+#define IPL_ATTR_BR_CHR_SHOW_FN(_name, _ipb)                           \
+static ssize_t eckd_##_name##_br_chr_show(struct kobject *kobj,                \
+                                         struct kobj_attribute *attr,  \
+                                         char *buf)                    \
+{                                                                      \
+       struct ipl_pb0_eckd *ipb = &(_ipb);                             \
+                                                                       \
+       if (!ipb->br_chr.cyl &&                                         \
+           !ipb->br_chr.head &&                                        \
+           !ipb->br_chr.record)                                        \
+               return sprintf(buf, "auto\n");                          \
+                                                                       \
+       return sprintf(buf, "0x%x,0x%x,0x%x\n",                         \
+                       ipb->br_chr.cyl,                                \
+                       ipb->br_chr.head,                               \
+                       ipb->br_chr.record);                            \
+}
+
+#define IPL_ATTR_BR_CHR_STORE_FN(_name, _ipb)                          \
+static ssize_t eckd_##_name##_br_chr_store(struct kobject *kobj,       \
+                                          struct kobj_attribute *attr, \
+                                          const char *buf, size_t len) \
+{                                                                      \
+       struct ipl_pb0_eckd *ipb = &(_ipb);                             \
+       unsigned long args[3] = { 0 };                                  \
+       char *p, *p1, *tmp = NULL;                                      \
+       int i, rc;                                                      \
+                                                                       \
+       if (!strncmp(buf, "auto", 4))                                   \
+               goto out;                                               \
+                                                                       \
+       tmp = kstrdup(buf, GFP_KERNEL);                                 \
+       p = tmp;                                                        \
+       for (i = 0; i < 3; i++) {                                       \
+               p1 = strsep(&p, ", ");                                  \
+               if (!p1) {                                              \
+                       rc = -EINVAL;                                   \
+                       goto err;                                       \
+               }                                                       \
+               rc = kstrtoul(p1, 0, args + i);                         \
+               if (rc)                                                 \
+                       goto err;                                       \
+       }                                                               \
+                                                                       \
+       rc = -EINVAL;                                                   \
+       if (i != 3)                                                     \
+               goto err;                                               \
+                                                                       \
+       if ((args[0] || args[1]) && !args[2])                           \
+               goto err;                                               \
+                                                                       \
+       if (args[0] > UINT_MAX || args[1] > 255 || args[2] > 255)       \
+               goto err;                                               \
+                                                                       \
+out:                                                                   \
+       ipb->br_chr.cyl = args[0];                                      \
+       ipb->br_chr.head = args[1];                                     \
+       ipb->br_chr.record = args[2];                                   \
+       rc = len;                                                       \
+err:                                                                   \
+       kfree(tmp);                                                     \
+       return rc;                                                      \
+}
+
+IPL_ATTR_BR_CHR_SHOW_FN(ipl, ipl_block.eckd);
+static struct kobj_attribute sys_ipl_eckd_br_chr_attr =
+       __ATTR(br_chr, (S_IRUGO | S_IWUSR),
+              eckd_ipl_br_chr_show,
+              NULL);
+
+IPL_ATTR_BR_CHR_SHOW_FN(reipl, reipl_block_eckd->eckd);
+IPL_ATTR_BR_CHR_STORE_FN(reipl, reipl_block_eckd->eckd);
+
+static struct kobj_attribute sys_reipl_eckd_br_chr_attr =
+       __ATTR(br_chr, (S_IRUGO | S_IWUSR),
+              eckd_reipl_br_chr_show,
+              eckd_reipl_br_chr_store);
+
 static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
                                     struct kobj_attribute *attr, char *page)
 {
@@ -470,6 +581,20 @@ static struct attribute_group ipl_nvme_attr_group = {
        .bin_attrs = ipl_nvme_bin_attrs,
 };
 
+static struct attribute *ipl_eckd_attrs[] = {
+       &sys_ipl_type_attr.attr,
+       &sys_ipl_eckd_bootprog_attr.attr,
+       &sys_ipl_eckd_br_chr_attr.attr,
+       &sys_ipl_device_attr.attr,
+       &sys_ipl_secure_attr.attr,
+       &sys_ipl_has_secure_attr.attr,
+       NULL,
+};
+
+static struct attribute_group ipl_eckd_attr_group = {
+       .attrs = ipl_eckd_attrs,
+       .bin_attrs = ipl_eckd_bin_attrs,
+};
 
 /* CCW ipl device attributes */
 
@@ -542,6 +667,9 @@ static int __init ipl_init(void)
                        rc = sysfs_create_group(&ipl_kset->kobj,
                                                &ipl_ccw_attr_group_lpar);
                break;
+       case IPL_TYPE_ECKD:
+               rc = sysfs_create_group(&ipl_kset->kobj, &ipl_eckd_attr_group);
+               break;
        case IPL_TYPE_FCP:
        case IPL_TYPE_FCP_DUMP:
                rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
@@ -986,6 +1114,85 @@ static struct attribute_group reipl_ccw_attr_group_lpar = {
        .attrs = reipl_ccw_attrs_lpar,
 };
 
+/* ECKD reipl device attributes */
+
+static ssize_t reipl_eckd_scpdata_read(struct file *filp, struct kobject *kobj,
+                                      struct bin_attribute *attr,
+                                      char *buf, loff_t off, size_t count)
+{
+       size_t size = reipl_block_eckd->eckd.scp_data_len;
+       void *scp_data = reipl_block_eckd->eckd.scp_data;
+
+       return memory_read_from_buffer(buf, count, &off, scp_data, size);
+}
+
+static ssize_t reipl_eckd_scpdata_write(struct file *filp, struct kobject *kobj,
+                                       struct bin_attribute *attr,
+                                       char *buf, loff_t off, size_t count)
+{
+       size_t scpdata_len = count;
+       size_t padding;
+
+       if (off)
+               return -EINVAL;
+
+       memcpy(reipl_block_eckd->eckd.scp_data, buf, count);
+       if (scpdata_len % 8) {
+               padding = 8 - (scpdata_len % 8);
+               memset(reipl_block_eckd->eckd.scp_data + scpdata_len,
+                      0, padding);
+               scpdata_len += padding;
+       }
+
+       reipl_block_eckd->hdr.len = IPL_BP_ECKD_LEN + scpdata_len;
+       reipl_block_eckd->eckd.len = IPL_BP0_ECKD_LEN + scpdata_len;
+       reipl_block_eckd->eckd.scp_data_len = scpdata_len;
+
+       return count;
+}
+
+static struct bin_attribute sys_reipl_eckd_scp_data_attr =
+       __BIN_ATTR(scp_data, (S_IRUGO | S_IWUSR), reipl_eckd_scpdata_read,
+                  reipl_eckd_scpdata_write, DIAG308_SCPDATA_SIZE);
+
+static struct bin_attribute *reipl_eckd_bin_attrs[] = {
+       &sys_reipl_eckd_scp_data_attr,
+       NULL,
+};
+
+DEFINE_IPL_CCW_ATTR_RW(reipl_eckd, device, reipl_block_eckd->eckd);
+DEFINE_IPL_ATTR_RW(reipl_eckd, bootprog, "%lld\n", "%lld\n",
+                  reipl_block_eckd->eckd.bootprog);
+
+static struct attribute *reipl_eckd_attrs[] = {
+       &sys_reipl_eckd_device_attr.attr,
+       &sys_reipl_eckd_bootprog_attr.attr,
+       &sys_reipl_eckd_br_chr_attr.attr,
+       NULL,
+};
+
+static struct attribute_group reipl_eckd_attr_group = {
+       .attrs = reipl_eckd_attrs,
+       .bin_attrs = reipl_eckd_bin_attrs
+};
+
+static ssize_t reipl_eckd_clear_show(struct kobject *kobj,
+                                    struct kobj_attribute *attr, char *page)
+{
+       return sprintf(page, "%u\n", reipl_eckd_clear);
+}
+
+static ssize_t reipl_eckd_clear_store(struct kobject *kobj,
+                                     struct kobj_attribute *attr,
+                                     const char *buf, size_t len)
+{
+       if (strtobool(buf, &reipl_eckd_clear) < 0)
+               return -EINVAL;
+       return len;
+}
+
+static struct kobj_attribute sys_reipl_eckd_clear_attr =
+       __ATTR(clear, 0644, reipl_eckd_clear_show, reipl_eckd_clear_store);
 
 /* NSS reipl device attributes */
 static void reipl_get_ascii_nss_name(char *dst,
@@ -1069,6 +1276,9 @@ static int reipl_set_type(enum ipl_type type)
        case IPL_TYPE_CCW:
                reipl_block_actual = reipl_block_ccw;
                break;
+       case IPL_TYPE_ECKD:
+               reipl_block_actual = reipl_block_eckd;
+               break;
        case IPL_TYPE_FCP:
                reipl_block_actual = reipl_block_fcp;
                break;
@@ -1099,6 +1309,8 @@ static ssize_t reipl_type_store(struct kobject *kobj,
 
        if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
                rc = reipl_set_type(IPL_TYPE_CCW);
+       else if (strncmp(buf, IPL_ECKD_STR, strlen(IPL_ECKD_STR)) == 0)
+               rc = reipl_set_type(IPL_TYPE_ECKD);
        else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
                rc = reipl_set_type(IPL_TYPE_FCP);
        else if (strncmp(buf, IPL_NVME_STR, strlen(IPL_NVME_STR)) == 0)
@@ -1114,6 +1326,7 @@ static struct kobj_attribute reipl_type_attr =
 static struct kset *reipl_kset;
 static struct kset *reipl_fcp_kset;
 static struct kset *reipl_nvme_kset;
+static struct kset *reipl_eckd_kset;
 
 static void __reipl_run(void *unused)
 {
@@ -1125,6 +1338,13 @@ static void __reipl_run(void *unused)
                else
                        diag308(DIAG308_LOAD_NORMAL_DUMP, NULL);
                break;
+       case IPL_TYPE_ECKD:
+               diag308(DIAG308_SET, reipl_block_eckd);
+               if (reipl_eckd_clear)
+                       diag308(DIAG308_LOAD_CLEAR, NULL);
+               else
+                       diag308(DIAG308_LOAD_NORMAL, NULL);
+               break;
        case IPL_TYPE_FCP:
                diag308(DIAG308_SET, reipl_block_fcp);
                if (reipl_fcp_clear)
@@ -1345,6 +1565,58 @@ out1:
        return rc;
 }
 
+static int __init reipl_eckd_init(void)
+{
+       int rc;
+
+       if (!sclp.has_sipl_eckd)
+               return 0;
+
+       reipl_block_eckd = (void *)get_zeroed_page(GFP_KERNEL);
+       if (!reipl_block_eckd)
+               return -ENOMEM;
+
+       /* sysfs: create kset for mixing attr group and bin attrs */
+       reipl_eckd_kset = kset_create_and_add(IPL_ECKD_STR, NULL,
+                                             &reipl_kset->kobj);
+       if (!reipl_eckd_kset) {
+               free_page((unsigned long)reipl_block_eckd);
+               return -ENOMEM;
+       }
+
+       rc = sysfs_create_group(&reipl_eckd_kset->kobj, &reipl_eckd_attr_group);
+       if (rc)
+               goto out1;
+
+       if (test_facility(141)) {
+               rc = sysfs_create_file(&reipl_eckd_kset->kobj,
+                                      &sys_reipl_eckd_clear_attr.attr);
+               if (rc)
+                       goto out2;
+       } else {
+               reipl_eckd_clear = true;
+       }
+
+       if (ipl_info.type == IPL_TYPE_ECKD) {
+               memcpy(reipl_block_eckd, &ipl_block, sizeof(ipl_block));
+       } else {
+               reipl_block_eckd->hdr.len = IPL_BP_ECKD_LEN;
+               reipl_block_eckd->hdr.version = IPL_PARM_BLOCK_VERSION;
+               reipl_block_eckd->eckd.len = IPL_BP0_ECKD_LEN;
+               reipl_block_eckd->eckd.pbt = IPL_PBT_ECKD;
+               reipl_block_eckd->eckd.opt = IPL_PB0_ECKD_OPT_IPL;
+       }
+       reipl_capabilities |= IPL_TYPE_ECKD;
+       return 0;
+
+out2:
+       sysfs_remove_group(&reipl_eckd_kset->kobj, &reipl_eckd_attr_group);
+out1:
+       kset_unregister(reipl_eckd_kset);
+       free_page((unsigned long)reipl_block_eckd);
+       return rc;
+}
+
 static int __init reipl_type_init(void)
 {
        enum ipl_type reipl_type = ipl_info.type;
@@ -1366,6 +1638,9 @@ static int __init reipl_type_init(void)
        } else if (reipl_block->pb0_hdr.pbt == IPL_PBT_CCW) {
                memcpy(reipl_block_ccw, reipl_block, size);
                reipl_type = IPL_TYPE_CCW;
+       } else if (reipl_block->pb0_hdr.pbt == IPL_PBT_ECKD) {
+               memcpy(reipl_block_eckd, reipl_block, size);
+               reipl_type = IPL_TYPE_ECKD;
        }
 out:
        return reipl_set_type(reipl_type);
@@ -1384,6 +1659,9 @@ static int __init reipl_init(void)
                return rc;
        }
        rc = reipl_ccw_init();
+       if (rc)
+               return rc;
+       rc = reipl_eckd_init();
        if (rc)
                return rc;
        rc = reipl_fcp_init();
@@ -2058,6 +2336,10 @@ void __init setup_ipl(void)
                ipl_info.data.ccw.dev_id.ssid = ipl_block.ccw.ssid;
                ipl_info.data.ccw.dev_id.devno = ipl_block.ccw.devno;
                break;
+       case IPL_TYPE_ECKD:
+               ipl_info.data.eckd.dev_id.ssid = ipl_block.eckd.ssid;
+               ipl_info.data.eckd.dev_id.devno = ipl_block.eckd.devno;
+               break;
        case IPL_TYPE_FCP:
        case IPL_TYPE_FCP_DUMP:
                ipl_info.data.fcp.dev_id.ssid = 0;
index d15b0d541de36cedd31708f3723c5c95a87469ec..c1c70a161c0e21c03532a14508783f8a91e7468c 100644 (file)
@@ -57,8 +57,10 @@ static void __init sclp_early_facilities_detect(void)
                sclp.has_diag318 = !!(sccb->byte_134 & 0x80);
                sclp.has_iplcc = !!(sccb->byte_134 & 0x02);
        }
-       if (sccb->cpuoff > 137)
+       if (sccb->cpuoff > 137) {
                sclp.has_sipl = !!(sccb->cbl & 0x4000);
+               sclp.has_sipl_eckd = !!(sccb->cbl & 0x2000);
+       }
        sclp.rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
        sclp.rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
        sclp.rzm <<= 20;