diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2008-07-25 10:40:14 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2008-07-25 10:40:14 -0400 |
commit | ff877ea80efa2015b6263766f78ee42c2a1b32f9 (patch) | |
tree | 85205005c611ab774702148558321c6fb92f1ccd /arch/s390/kernel/ipl.c | |
parent | 30821fee4f0cb3e6d241d9f7ddc37742212e3eb7 (diff) | |
parent | d37e6bf68fc1eb34a4ad21d9ae8890ed37ea80e7 (diff) |
Merge branch 'linux-next' of git://git.infradead.org/~dedekind/ubi-2.6
Diffstat (limited to 'arch/s390/kernel/ipl.c')
-rw-r--r-- | arch/s390/kernel/ipl.c | 462 |
1 files changed, 383 insertions, 79 deletions
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 532542447d6..54b2779b5e2 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -14,6 +14,7 @@ #include <linux/delay.h> #include <linux/reboot.h> #include <linux/ctype.h> +#include <linux/fs.h> #include <asm/ipl.h> #include <asm/smp.h> #include <asm/setup.h> @@ -22,6 +23,7 @@ #include <asm/ebcdic.h> #include <asm/reset.h> #include <asm/sclp.h> +#include <asm/setup.h> #define IPL_PARM_BLOCK_VERSION 0 @@ -121,6 +123,7 @@ enum ipl_method { REIPL_METHOD_FCP_RO_VM, REIPL_METHOD_FCP_DUMP, REIPL_METHOD_NSS, + REIPL_METHOD_NSS_DIAG, REIPL_METHOD_DEFAULT, }; @@ -134,14 +137,15 @@ enum dump_method { static int diag308_set_works = 0; +static struct ipl_parameter_block ipl_block; + static int reipl_capabilities = IPL_TYPE_UNKNOWN; static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN; static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT; static struct ipl_parameter_block *reipl_block_fcp; static struct ipl_parameter_block *reipl_block_ccw; - -static char reipl_nss_name[NSS_NAME_SIZE + 1]; +static struct ipl_parameter_block *reipl_block_nss; static int dump_capabilities = DUMP_TYPE_NONE; static enum dump_type dump_type = DUMP_TYPE_NONE; @@ -263,6 +267,56 @@ static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr, static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); +/* VM IPL PARM routines */ +static void reipl_get_ascii_vmparm(char *dest, + const struct ipl_parameter_block *ipb) +{ + int i; + int len = 0; + char has_lowercase = 0; + + if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) && + (ipb->ipl_info.ccw.vm_parm_len > 0)) { + + len = ipb->ipl_info.ccw.vm_parm_len; + memcpy(dest, ipb->ipl_info.ccw.vm_parm, len); + /* If at least one character is lowercase, we assume mixed + * case; otherwise we convert everything to lowercase. + */ + for (i = 0; i < len; i++) + if ((dest[i] > 0x80 && dest[i] < 0x8a) || /* a-i */ + (dest[i] > 0x90 && dest[i] < 0x9a) || /* j-r */ + (dest[i] > 0xa1 && dest[i] < 0xaa)) { /* s-z */ + has_lowercase = 1; + break; + } + if (!has_lowercase) + EBC_TOLOWER(dest, len); + EBCASC(dest, len); + } + dest[len] = 0; +} + +void get_ipl_vmparm(char *dest) +{ + if (diag308_set_works && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW)) + reipl_get_ascii_vmparm(dest, &ipl_block); + else + dest[0] = 0; +} + +static ssize_t ipl_vm_parm_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + char parm[DIAG308_VMPARM_SIZE + 1] = {}; + + get_ipl_vmparm(parm); + return sprintf(page, "%s\n", parm); +} + +static struct kobj_attribute sys_ipl_vm_parm_attr = + __ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL); + static ssize_t sys_ipl_device_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { @@ -285,14 +339,8 @@ static struct kobj_attribute sys_ipl_device_attr = static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { - unsigned int size = IPL_PARMBLOCK_SIZE; - - if (off > size) - return 0; - if (off + count > size) - count = size - off; - memcpy(buf, (void *)IPL_PARMBLOCK_START + off, count); - return count; + return memory_read_from_buffer(buf, count, &off, IPL_PARMBLOCK_START, + IPL_PARMBLOCK_SIZE); } static struct bin_attribute ipl_parameter_attr = { @@ -310,12 +358,7 @@ static ssize_t ipl_scp_data_read(struct kobject *kobj, struct bin_attribute *att unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len; void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data; - if (off > size) - return 0; - if (off + count > size) - count = size - off; - memcpy(buf, scp_data + off, count); - return count; + return memory_read_from_buffer(buf, count, &off, scp_data, size); } static struct bin_attribute ipl_scp_data_attr = { @@ -370,15 +413,27 @@ static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj, static struct kobj_attribute sys_ipl_ccw_loadparm_attr = __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL); -static struct attribute *ipl_ccw_attrs[] = { +static struct attribute *ipl_ccw_attrs_vm[] = { &sys_ipl_type_attr.attr, &sys_ipl_device_attr.attr, &sys_ipl_ccw_loadparm_attr.attr, + &sys_ipl_vm_parm_attr.attr, NULL, }; -static struct attribute_group ipl_ccw_attr_group = { - .attrs = ipl_ccw_attrs, +static struct attribute *ipl_ccw_attrs_lpar[] = { + &sys_ipl_type_attr.attr, + &sys_ipl_device_attr.attr, + &sys_ipl_ccw_loadparm_attr.attr, + NULL, +}; + +static struct attribute_group ipl_ccw_attr_group_vm = { + .attrs = ipl_ccw_attrs_vm, +}; + +static struct attribute_group ipl_ccw_attr_group_lpar = { + .attrs = ipl_ccw_attrs_lpar }; /* NSS ipl device attributes */ @@ -388,6 +443,8 @@ DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name); static struct attribute *ipl_nss_attrs[] = { &sys_ipl_type_attr.attr, &sys_ipl_nss_name_attr.attr, + &sys_ipl_ccw_loadparm_attr.attr, + &sys_ipl_vm_parm_attr.attr, NULL, }; @@ -450,7 +507,12 @@ static int __init ipl_init(void) } switch (ipl_info.type) { case IPL_TYPE_CCW: - rc = sysfs_create_group(&ipl_kset->kobj, &ipl_ccw_attr_group); + if (MACHINE_IS_VM) + rc = sysfs_create_group(&ipl_kset->kobj, + &ipl_ccw_attr_group_vm); + else + rc = sysfs_create_group(&ipl_kset->kobj, + &ipl_ccw_attr_group_lpar); break; case IPL_TYPE_FCP: case IPL_TYPE_FCP_DUMP: @@ -481,6 +543,83 @@ static struct shutdown_action __refdata ipl_action = { * reipl shutdown action: Reboot Linux on shutdown. */ +/* VM IPL PARM attributes */ +static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb, + char *page) +{ + char vmparm[DIAG308_VMPARM_SIZE + 1] = {}; + + reipl_get_ascii_vmparm(vmparm, ipb); + return sprintf(page, "%s\n", vmparm); +} + +static ssize_t reipl_generic_vmparm_store(struct ipl_parameter_block *ipb, + size_t vmparm_max, + const char *buf, size_t len) +{ + int i, ip_len; + + /* ignore trailing newline */ + ip_len = len; + if ((len > 0) && (buf[len - 1] == '\n')) + ip_len--; + + if (ip_len > vmparm_max) + return -EINVAL; + + /* parm is used to store kernel options, check for common chars */ + for (i = 0; i < ip_len; i++) + if (!(isalnum(buf[i]) || isascii(buf[i]) || isprint(buf[i]))) + return -EINVAL; + + memset(ipb->ipl_info.ccw.vm_parm, 0, DIAG308_VMPARM_SIZE); + ipb->ipl_info.ccw.vm_parm_len = ip_len; + if (ip_len > 0) { + ipb->ipl_info.ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID; + memcpy(ipb->ipl_info.ccw.vm_parm, buf, ip_len); + ASCEBC(ipb->ipl_info.ccw.vm_parm, ip_len); + } else { + ipb->ipl_info.ccw.vm_flags &= ~DIAG308_VM_FLAGS_VP_VALID; + } + + return len; +} + +/* NSS wrapper */ +static ssize_t reipl_nss_vmparm_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + return reipl_generic_vmparm_show(reipl_block_nss, page); +} + +static ssize_t reipl_nss_vmparm_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t len) +{ + return reipl_generic_vmparm_store(reipl_block_nss, 56, buf, len); +} + +/* CCW wrapper */ +static ssize_t reipl_ccw_vmparm_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + return reipl_generic_vmparm_show(reipl_block_ccw, page); +} + +static ssize_t reipl_ccw_vmparm_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t len) +{ + return reipl_generic_vmparm_store(reipl_block_ccw, 64, buf, len); +} + +static struct kobj_attribute sys_reipl_nss_vmparm_attr = + __ATTR(parm, S_IRUGO | S_IWUSR, reipl_nss_vmparm_show, + reipl_nss_vmparm_store); +static struct kobj_attribute sys_reipl_ccw_vmparm_attr = + __ATTR(parm, S_IRUGO | S_IWUSR, reipl_ccw_vmparm_show, + reipl_ccw_vmparm_store); + /* FCP reipl device attributes */ DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n", @@ -513,27 +652,26 @@ static struct attribute_group reipl_fcp_attr_group = { DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", reipl_block_ccw->ipl_info.ccw.devno); -static void reipl_get_ascii_loadparm(char *loadparm) +static void reipl_get_ascii_loadparm(char *loadparm, + struct ipl_parameter_block *ibp) { - memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param, - LOADPARM_LEN); + memcpy(loadparm, ibp->ipl_info.ccw.load_parm, LOADPARM_LEN); EBCASC(loadparm, LOADPARM_LEN); loadparm[LOADPARM_LEN] = 0; strstrip(loadparm); } -static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj, - struct kobj_attribute *attr, char *page) +static ssize_t reipl_generic_loadparm_show(struct ipl_parameter_block *ipb, + char *page) { char buf[LOADPARM_LEN + 1]; - reipl_get_ascii_loadparm(buf); + reipl_get_ascii_loadparm(buf, ipb); return sprintf(page, "%s\n", buf); } -static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t len) +static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb, + const char *buf, size_t len) { int i, lp_len; @@ -552,35 +690,128 @@ static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj, return -EINVAL; } /* initialize loadparm with blanks */ - memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', LOADPARM_LEN); + memset(ipb->ipl_info.ccw.load_parm, ' ', LOADPARM_LEN); /* copy and convert to ebcdic */ - memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len); - ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN); + memcpy(ipb->ipl_info.ccw.load_parm, buf, lp_len); + ASCEBC(ipb->ipl_info.ccw.load_parm, LOADPARM_LEN); return len; } +/* NSS wrapper */ +static ssize_t reipl_nss_loadparm_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + return reipl_generic_loadparm_show(reipl_block_nss, page); +} + +static ssize_t reipl_nss_loadparm_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t len) +{ + return reipl_generic_loadparm_store(reipl_block_nss, buf, len); +} + +/* CCW wrapper */ +static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + return reipl_generic_loadparm_show(reipl_block_ccw, page); +} + +static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t len) +{ + return reipl_generic_loadparm_store(reipl_block_ccw, buf, len); +} + static struct kobj_attribute sys_reipl_ccw_loadparm_attr = - __ATTR(loadparm, 0644, reipl_ccw_loadparm_show, - reipl_ccw_loadparm_store); + __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show, + reipl_ccw_loadparm_store); -static struct attribute *reipl_ccw_attrs[] = { +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, NULL, }; -static struct attribute_group reipl_ccw_attr_group = { +static struct attribute *reipl_ccw_attrs_lpar[] = { + &sys_reipl_ccw_device_attr.attr, + &sys_reipl_ccw_loadparm_attr.attr, + NULL, +}; + +static struct attribute_group reipl_ccw_attr_group_vm = { + .name = IPL_CCW_STR, + .attrs = reipl_ccw_attrs_vm, +}; + +static struct attribute_group reipl_ccw_attr_group_lpar = { .name = IPL_CCW_STR, - .attrs = reipl_ccw_attrs, + .attrs = reipl_ccw_attrs_lpar, }; /* NSS reipl device attributes */ +static void reipl_get_ascii_nss_name(char *dst, + struct ipl_parameter_block *ipb) +{ + memcpy(dst, ipb->ipl_info.ccw.nss_name, NSS_NAME_SIZE); + EBCASC(dst, NSS_NAME_SIZE); + dst[NSS_NAME_SIZE] = 0; +} + +static ssize_t reipl_nss_name_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + char nss_name[NSS_NAME_SIZE + 1] = {}; -DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name); + reipl_get_ascii_nss_name(nss_name, reipl_block_nss); + return sprintf(page, "%s\n", nss_name); +} + +static ssize_t reipl_nss_name_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t len) +{ + int nss_len; + + /* ignore trailing newline */ + nss_len = len; + if ((len > 0) && (buf[len - 1] == '\n')) + nss_len--; + + if (nss_len > NSS_NAME_SIZE) + return -EINVAL; + + memset(reipl_block_nss->ipl_info.ccw.nss_name, 0x40, NSS_NAME_SIZE); + if (nss_len > 0) { + reipl_block_nss->ipl_info.ccw.vm_flags |= + DIAG308_VM_FLAGS_NSS_VALID; + memcpy(reipl_block_nss->ipl_info.ccw.nss_name, buf, nss_len); + ASCEBC(reipl_block_nss->ipl_info.ccw.nss_name, nss_len); + EBC_TOUPPER(reipl_block_nss->ipl_info.ccw.nss_name, nss_len); + } else { + reipl_block_nss->ipl_info.ccw.vm_flags &= + ~DIAG308_VM_FLAGS_NSS_VALID; + } + + return len; +} + +static struct kobj_attribute sys_reipl_nss_name_attr = + __ATTR(name, S_IRUGO | S_IWUSR, reipl_nss_name_show, + reipl_nss_name_store); + +static struct kobj_attribute sys_reipl_nss_loadparm_attr = + __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_nss_loadparm_show, + reipl_nss_loadparm_store); static struct attribute *reipl_nss_attrs[] = { &sys_reipl_nss_name_attr.attr, + &sys_reipl_nss_loadparm_attr.attr, + &sys_reipl_nss_vmparm_attr.attr, NULL, }; @@ -617,7 +848,10 @@ static int reipl_set_type(enum ipl_type type) reipl_method = REIPL_METHOD_FCP_DUMP; break; case IPL_TYPE_NSS: - reipl_method = REIPL_METHOD_NSS; + if (diag308_set_works) + reipl_method = REIPL_METHOD_NSS_DIAG; + else + reipl_method = REIPL_METHOD_NSS; break; case IPL_TYPE_UNKNOWN: reipl_method = REIPL_METHOD_DEFAULT; @@ -655,11 +889,38 @@ static struct kobj_attribute reipl_type_attr = static struct kset *reipl_kset; +static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb, + const enum ipl_method m) +{ + char loadparm[LOADPARM_LEN + 1] = {}; + char vmparm[DIAG308_VMPARM_SIZE + 1] = {}; + char nss_name[NSS_NAME_SIZE + 1] = {}; + size_t pos = 0; + + reipl_get_ascii_loadparm(loadparm, ipb); + reipl_get_ascii_nss_name(nss_name, ipb); + reipl_get_ascii_vmparm(vmparm, ipb); + + switch (m) { + case REIPL_METHOD_CCW_VM: + pos = sprintf(dst, "IPL %X CLEAR", ipb->ipl_info.ccw.devno); + break; + case REIPL_METHOD_NSS: + pos = sprintf(dst, "IPL %s", nss_name); + break; + default: + break; + } + if (strlen(loadparm) > 0) + pos += sprintf(dst + pos, " LOADPARM '%s'", loadparm); + if (strlen(vmparm) > 0) + sprintf(dst + pos, " PARM %s", vmparm); +} + static void reipl_run(struct shutdown_trigger *trigger) { struct ccw_dev_id devid; - static char buf[100]; - char loadparm[LOADPARM_LEN + 1]; + static char buf[128]; switch (reipl_method) { case REIPL_METHOD_CCW_CIO: @@ -668,13 +929,7 @@ static void reipl_run(struct shutdown_trigger *trigger) reipl_ccw_dev(&devid); break; case REIPL_METHOD_CCW_VM: - reipl_get_ascii_loadparm(loadparm); - if (strlen(loadparm) == 0) - sprintf(buf, "IPL %X CLEAR", - reipl_block_ccw->ipl_info.ccw.devno); - else - sprintf(buf, "IPL %X CLEAR LOADPARM '%s'", - reipl_block_ccw->ipl_info.ccw.devno, loadparm); + get_ipl_string(buf, reipl_block_ccw, REIPL_METHOD_CCW_VM); __cpcmd(buf, NULL, 0, NULL); break; case REIPL_METHOD_CCW_DIAG: @@ -691,8 +946,12 @@ static void reipl_run(struct shutdown_trigger *trigger) case REIPL_METHOD_FCP_RO_VM: __cpcmd("IPL", NULL, 0, NULL); break; + case REIPL_METHOD_NSS_DIAG: + diag308(DIAG308_SET, reipl_block_nss); + diag308(DIAG308_IPL, NULL); + break; case REIPL_METHOD_NSS: - sprintf(buf, "IPL %s", reipl_nss_name); + get_ipl_string(buf, reipl_block_nss, REIPL_METHOD_NSS); __cpcmd(buf, NULL, 0, NULL); break; case REIPL_METHOD_DEFAULT: @@ -707,16 +966,36 @@ static void reipl_run(struct shutdown_trigger *trigger) disabled_wait((unsigned long) __builtin_return_address(0)); } -static void __init reipl_probe(void) +static void reipl_block_ccw_init(struct ipl_parameter_block *ipb) { - void *buffer; + ipb->hdr.len = IPL_PARM_BLK_CCW_LEN; + ipb->hdr.version = IPL_PARM_BLOCK_VERSION; + ipb->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN; + ipb->hdr.pbt = DIAG308_IPL_TYPE_CCW; +} - buffer = (void *) get_zeroed_page(GFP_KERNEL); - if (!buffer) - return; - if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK) - diag308_set_works = 1; - free_page((unsigned long)buffer); +static void reipl_block_ccw_fill_parms(struct ipl_parameter_block *ipb) +{ + /* LOADPARM */ + /* check if read scp info worked and set loadparm */ + if (sclp_ipl_info.is_valid) + memcpy(ipb->ipl_info.ccw.load_parm, + &sclp_ipl_info.loadparm, LOADPARM_LEN); + else + /* read scp info failed: set empty loadparm (EBCDIC blanks) */ + memset(ipb->ipl_info.ccw.load_parm, 0x40, LOADPARM_LEN); + ipb->hdr.flags = DIAG308_FLAGS_LP_VALID; + + /* VM PARM */ + if (MACHINE_IS_VM && diag308_set_works && + (ipl_block.ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID)) { + + ipb->ipl_info.ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID; + ipb->ipl_info.ccw.vm_parm_len = + ipl_block.ipl_info.ccw.vm_parm_len; + memcpy(ipb->ipl_info.ccw.vm_parm, + ipl_block.ipl_info.ccw.vm_parm, DIAG308_VMPARM_SIZE); + } } static int __init reipl_nss_init(void) @@ -725,10 +1004,31 @@ static int __init reipl_nss_init(void) if (!MACHINE_IS_VM) return 0; + + reipl_block_nss = (void *) get_zeroed_page(GFP_KERNEL); + if (!reipl_block_nss) + return -ENOMEM; + + if (!diag308_set_works) + sys_reipl_nss_vmparm_attr.attr.mode = S_IRUGO; + rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group); if (rc) return rc; - strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1); + + reipl_block_ccw_init(reipl_block_nss); + if (ipl_info.type == IPL_TYPE_NSS) { + memset(reipl_block_nss->ipl_info.ccw.nss_name, + ' ', NSS_NAME_SIZE); + memcpy(reipl_block_nss->ipl_info.ccw.nss_name, + kernel_nss_name, strlen(kernel_nss_name)); + ASCEBC(reipl_block_nss->ipl_info.ccw.nss_name, NSS_NAME_SIZE); + reipl_block_nss->ipl_info.ccw.vm_flags |= + DIAG308_VM_FLAGS_NSS_VALID; + + reipl_block_ccw_fill_parms(reipl_block_nss); + } + reipl_capabilities |= IPL_TYPE_NSS; return 0; } @@ -740,28 +1040,27 @@ static int __init reipl_ccw_init(void) reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL); if (!reipl_block_ccw) return -ENOMEM; - rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group); - if (rc) { - free_page((unsigned long)reipl_block_ccw); - return rc; + + if (MACHINE_IS_VM) { + if (!diag308_set_works) + sys_reipl_ccw_vmparm_attr.attr.mode = S_IRUGO; + rc = sysfs_create_group(&reipl_kset->kobj, + &reipl_ccw_attr_group_vm); + } else { + if(!diag308_set_works) + sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO; + rc = sysfs_create_group(&reipl_kset->kobj, + &reipl_ccw_attr_group_lpar); } - reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN; - reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; - reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN; - reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; - reipl_block_ccw->hdr.flags = DIAG308_FLAGS_LP_VALID; - /* check if read scp info worked and set loadparm */ - if (sclp_ipl_info.is_valid) - memcpy(reipl_block_ccw->ipl_info.ccw.load_param, - &sclp_ipl_info.loadparm, LOADPARM_LEN); - else - /* read scp info failed: set empty loadparm (EBCDIC blanks) */ - memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40, - LOADPARM_LEN); - if (!MACHINE_IS_VM && !diag308_set_works) - sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO; - if (ipl_info.type == IPL_TYPE_CCW) + if (rc) + return rc; + + reipl_block_ccw_init(reipl_block_ccw); + if (ipl_info.type == IPL_TYPE_CCW) { reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; + reipl_block_ccw_fill_parms(reipl_block_ccw); + } + reipl_capabilities |= IPL_TYPE_CCW; return 0; } @@ -1298,7 +1597,6 @@ static void __init shutdown_actions_init(void) static int __init s390_ipl_init(void) { - reipl_probe(); sclp_get_ipl_info(&sclp_ipl_info); shutdown_actions_init(); shutdown_triggers_init(); @@ -1405,6 +1703,12 @@ void __init setup_ipl(void) atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb); } +void __init ipl_update_parameters(void) +{ + if (diag308(DIAG308_STORE, &ipl_block) == DIAG308_RC_OK) + diag308_set_works = 1; +} + void __init ipl_save_parameters(void) { struct cio_iplinfo iplinfo; |