|
|
|
|
@ -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;
|
|
|
|
|
|