[S390] Extra Kernel Parameters via VMPARM
Now it is possible to specify additional kernel parameters on the IPL command line using the IPL PARM option. If the Linux system is already running, the new reipl sysfs attribute 'parm' can be used to change kernel parameters for the next reboot. Examples: IPL C PARM dasd=1234 root=/dev/dasda1 IPL 1234 PARM savesys=mylnxnss echo "init=/bin/bash" > /sys/firmware/reipl/ccw/parm Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
This commit is contained in:
parent
fe13723061
commit
a0443fbb46
5 changed files with 476 additions and 88 deletions
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/pfn.h>
|
#include <linux/pfn.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
#include <asm/ebcdic.h>
|
||||||
#include <asm/ipl.h>
|
#include <asm/ipl.h>
|
||||||
#include <asm/lowcore.h>
|
#include <asm/lowcore.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
|
@ -26,12 +27,40 @@
|
||||||
/*
|
/*
|
||||||
* Create a Kernel NSS if the SAVESYS= parameter is defined
|
* Create a Kernel NSS if the SAVESYS= parameter is defined
|
||||||
*/
|
*/
|
||||||
#define DEFSYS_CMD_SIZE 96
|
#define DEFSYS_CMD_SIZE 128
|
||||||
#define SAVESYS_CMD_SIZE 32
|
#define SAVESYS_CMD_SIZE 32
|
||||||
|
|
||||||
char kernel_nss_name[NSS_NAME_SIZE + 1];
|
char kernel_nss_name[NSS_NAME_SIZE + 1];
|
||||||
|
|
||||||
|
static void __init setup_boot_command_line(void);
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_SHARED_KERNEL
|
#ifdef CONFIG_SHARED_KERNEL
|
||||||
|
int __init savesys_ipl_nss(char *cmd, const int cmdlen);
|
||||||
|
|
||||||
|
asm(
|
||||||
|
" .section .init.text,\"ax\",@progbits\n"
|
||||||
|
" .align 4\n"
|
||||||
|
" .type savesys_ipl_nss, @function\n"
|
||||||
|
"savesys_ipl_nss:\n"
|
||||||
|
#ifdef CONFIG_64BIT
|
||||||
|
" stmg 6,15,48(15)\n"
|
||||||
|
" lgr 14,3\n"
|
||||||
|
" sam31\n"
|
||||||
|
" diag 2,14,0x8\n"
|
||||||
|
" sam64\n"
|
||||||
|
" lgr 2,14\n"
|
||||||
|
" lmg 6,15,48(15)\n"
|
||||||
|
#else
|
||||||
|
" stm 6,15,24(15)\n"
|
||||||
|
" lr 14,3\n"
|
||||||
|
" diag 2,14,0x8\n"
|
||||||
|
" lr 2,14\n"
|
||||||
|
" lm 6,15,24(15)\n"
|
||||||
|
#endif
|
||||||
|
" br 14\n"
|
||||||
|
" .size savesys_ipl_nss, .-savesys_ipl_nss\n");
|
||||||
|
|
||||||
static noinline __init void create_kernel_nss(void)
|
static noinline __init void create_kernel_nss(void)
|
||||||
{
|
{
|
||||||
unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
|
unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
|
||||||
|
@ -39,6 +68,7 @@ static noinline __init void create_kernel_nss(void)
|
||||||
unsigned int sinitrd_pfn, einitrd_pfn;
|
unsigned int sinitrd_pfn, einitrd_pfn;
|
||||||
#endif
|
#endif
|
||||||
int response;
|
int response;
|
||||||
|
size_t len;
|
||||||
char *savesys_ptr;
|
char *savesys_ptr;
|
||||||
char upper_command_line[COMMAND_LINE_SIZE];
|
char upper_command_line[COMMAND_LINE_SIZE];
|
||||||
char defsys_cmd[DEFSYS_CMD_SIZE];
|
char defsys_cmd[DEFSYS_CMD_SIZE];
|
||||||
|
@ -49,8 +79,8 @@ static noinline __init void create_kernel_nss(void)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Convert COMMAND_LINE to upper case */
|
/* Convert COMMAND_LINE to upper case */
|
||||||
for (i = 0; i < strlen(COMMAND_LINE); i++)
|
for (i = 0; i < strlen(boot_command_line); i++)
|
||||||
upper_command_line[i] = toupper(COMMAND_LINE[i]);
|
upper_command_line[i] = toupper(boot_command_line[i]);
|
||||||
|
|
||||||
savesys_ptr = strstr(upper_command_line, "SAVESYS=");
|
savesys_ptr = strstr(upper_command_line, "SAVESYS=");
|
||||||
|
|
||||||
|
@ -83,7 +113,8 @@ static noinline __init void create_kernel_nss(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size);
|
sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK PARMREGS=0-13",
|
||||||
|
defsys_cmd, min_size);
|
||||||
sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
|
sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
|
||||||
kernel_nss_name, kernel_nss_name);
|
kernel_nss_name, kernel_nss_name);
|
||||||
|
|
||||||
|
@ -94,13 +125,24 @@ static noinline __init void create_kernel_nss(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
__cpcmd(savesys_cmd, NULL, 0, &response);
|
len = strlen(savesys_cmd);
|
||||||
|
ASCEBC(savesys_cmd, len);
|
||||||
|
response = savesys_ipl_nss(savesys_cmd, len);
|
||||||
|
|
||||||
if (response != strlen(savesys_cmd)) {
|
/* On success: response is equal to the command size,
|
||||||
|
* max SAVESYS_CMD_SIZE
|
||||||
|
* On error: response contains the numeric portion of cp error message.
|
||||||
|
* for SAVESYS it will be >= 263
|
||||||
|
*/
|
||||||
|
if (response > SAVESYS_CMD_SIZE) {
|
||||||
kernel_nss_name[0] = '\0';
|
kernel_nss_name[0] = '\0';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* re-setup boot command line with new ipl vm parms */
|
||||||
|
ipl_update_parameters();
|
||||||
|
setup_boot_command_line();
|
||||||
|
|
||||||
ipl_flags = IPL_NSS_VALID;
|
ipl_flags = IPL_NSS_VALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,6 +439,26 @@ static __init void rescue_initrd(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set up boot command line */
|
||||||
|
static void __init setup_boot_command_line(void)
|
||||||
|
{
|
||||||
|
char *parm = NULL;
|
||||||
|
|
||||||
|
/* copy arch command line */
|
||||||
|
strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE);
|
||||||
|
boot_command_line[ARCH_COMMAND_LINE_SIZE - 1] = 0;
|
||||||
|
|
||||||
|
/* append IPL PARM data to the boot command line */
|
||||||
|
if (MACHINE_IS_VM) {
|
||||||
|
parm = boot_command_line + strlen(boot_command_line);
|
||||||
|
*parm++ = ' ';
|
||||||
|
get_ipl_vmparm(parm);
|
||||||
|
if (parm[0] == '=')
|
||||||
|
memmove(boot_command_line, parm + 1, strlen(parm));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save ipl parameters, clear bss memory, initialize storage keys
|
* Save ipl parameters, clear bss memory, initialize storage keys
|
||||||
* and create a kernel NSS at startup if the SAVESYS= parm is defined
|
* and create a kernel NSS at startup if the SAVESYS= parm is defined
|
||||||
|
@ -411,10 +473,12 @@ void __init startup_init(void)
|
||||||
init_kernel_storage_key();
|
init_kernel_storage_key();
|
||||||
lockdep_init();
|
lockdep_init();
|
||||||
lockdep_off();
|
lockdep_off();
|
||||||
detect_machine_type();
|
|
||||||
create_kernel_nss();
|
|
||||||
sort_main_extable();
|
sort_main_extable();
|
||||||
setup_lowcore_early();
|
setup_lowcore_early();
|
||||||
|
detect_machine_type();
|
||||||
|
ipl_update_parameters();
|
||||||
|
setup_boot_command_line();
|
||||||
|
create_kernel_nss();
|
||||||
detect_mvpg();
|
detect_mvpg();
|
||||||
detect_ieee();
|
detect_ieee();
|
||||||
detect_csp();
|
detect_csp();
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <asm/ebcdic.h>
|
#include <asm/ebcdic.h>
|
||||||
#include <asm/reset.h>
|
#include <asm/reset.h>
|
||||||
#include <asm/sclp.h>
|
#include <asm/sclp.h>
|
||||||
|
#include <asm/setup.h>
|
||||||
|
|
||||||
#define IPL_PARM_BLOCK_VERSION 0
|
#define IPL_PARM_BLOCK_VERSION 0
|
||||||
|
|
||||||
|
@ -121,6 +122,7 @@ enum ipl_method {
|
||||||
REIPL_METHOD_FCP_RO_VM,
|
REIPL_METHOD_FCP_RO_VM,
|
||||||
REIPL_METHOD_FCP_DUMP,
|
REIPL_METHOD_FCP_DUMP,
|
||||||
REIPL_METHOD_NSS,
|
REIPL_METHOD_NSS,
|
||||||
|
REIPL_METHOD_NSS_DIAG,
|
||||||
REIPL_METHOD_DEFAULT,
|
REIPL_METHOD_DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -134,14 +136,15 @@ enum dump_method {
|
||||||
|
|
||||||
static int diag308_set_works = 0;
|
static int diag308_set_works = 0;
|
||||||
|
|
||||||
|
static struct ipl_parameter_block ipl_block;
|
||||||
|
|
||||||
static int reipl_capabilities = IPL_TYPE_UNKNOWN;
|
static int reipl_capabilities = IPL_TYPE_UNKNOWN;
|
||||||
|
|
||||||
static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
|
static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
|
||||||
static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT;
|
static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT;
|
||||||
static struct ipl_parameter_block *reipl_block_fcp;
|
static struct ipl_parameter_block *reipl_block_fcp;
|
||||||
static struct ipl_parameter_block *reipl_block_ccw;
|
static struct ipl_parameter_block *reipl_block_ccw;
|
||||||
|
static struct ipl_parameter_block *reipl_block_nss;
|
||||||
static char reipl_nss_name[NSS_NAME_SIZE + 1];
|
|
||||||
|
|
||||||
static int dump_capabilities = DUMP_TYPE_NONE;
|
static int dump_capabilities = DUMP_TYPE_NONE;
|
||||||
static enum dump_type dump_type = DUMP_TYPE_NONE;
|
static enum dump_type dump_type = DUMP_TYPE_NONE;
|
||||||
|
@ -263,6 +266,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);
|
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,
|
static ssize_t sys_ipl_device_show(struct kobject *kobj,
|
||||||
struct kobj_attribute *attr, char *page)
|
struct kobj_attribute *attr, char *page)
|
||||||
{
|
{
|
||||||
|
@ -370,15 +423,27 @@ static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
|
||||||
static struct kobj_attribute sys_ipl_ccw_loadparm_attr =
|
static struct kobj_attribute sys_ipl_ccw_loadparm_attr =
|
||||||
__ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
|
__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 *ipl_ccw_attrs_lpar[] = {
|
||||||
&sys_ipl_type_attr.attr,
|
&sys_ipl_type_attr.attr,
|
||||||
&sys_ipl_device_attr.attr,
|
&sys_ipl_device_attr.attr,
|
||||||
&sys_ipl_ccw_loadparm_attr.attr,
|
&sys_ipl_ccw_loadparm_attr.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group ipl_ccw_attr_group = {
|
static struct attribute_group ipl_ccw_attr_group_vm = {
|
||||||
.attrs = ipl_ccw_attrs,
|
.attrs = ipl_ccw_attrs_vm,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group ipl_ccw_attr_group_lpar = {
|
||||||
|
.attrs = ipl_ccw_attrs_lpar
|
||||||
};
|
};
|
||||||
|
|
||||||
/* NSS ipl device attributes */
|
/* NSS ipl device attributes */
|
||||||
|
@ -388,6 +453,8 @@ DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
|
||||||
static struct attribute *ipl_nss_attrs[] = {
|
static struct attribute *ipl_nss_attrs[] = {
|
||||||
&sys_ipl_type_attr.attr,
|
&sys_ipl_type_attr.attr,
|
||||||
&sys_ipl_nss_name_attr.attr,
|
&sys_ipl_nss_name_attr.attr,
|
||||||
|
&sys_ipl_ccw_loadparm_attr.attr,
|
||||||
|
&sys_ipl_vm_parm_attr.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -450,7 +517,12 @@ static int __init ipl_init(void)
|
||||||
}
|
}
|
||||||
switch (ipl_info.type) {
|
switch (ipl_info.type) {
|
||||||
case IPL_TYPE_CCW:
|
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;
|
break;
|
||||||
case IPL_TYPE_FCP:
|
case IPL_TYPE_FCP:
|
||||||
case IPL_TYPE_FCP_DUMP:
|
case IPL_TYPE_FCP_DUMP:
|
||||||
|
@ -481,6 +553,83 @@ static struct shutdown_action __refdata ipl_action = {
|
||||||
* reipl shutdown action: Reboot Linux on shutdown.
|
* 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 */
|
/* FCP reipl device attributes */
|
||||||
|
|
||||||
DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
|
DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
|
||||||
|
@ -513,27 +662,26 @@ static struct attribute_group reipl_fcp_attr_group = {
|
||||||
DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
|
DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
|
||||||
reipl_block_ccw->ipl_info.ccw.devno);
|
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,
|
memcpy(loadparm, ibp->ipl_info.ccw.load_parm, LOADPARM_LEN);
|
||||||
LOADPARM_LEN);
|
|
||||||
EBCASC(loadparm, LOADPARM_LEN);
|
EBCASC(loadparm, LOADPARM_LEN);
|
||||||
loadparm[LOADPARM_LEN] = 0;
|
loadparm[LOADPARM_LEN] = 0;
|
||||||
strstrip(loadparm);
|
strstrip(loadparm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj,
|
static ssize_t reipl_generic_loadparm_show(struct ipl_parameter_block *ipb,
|
||||||
struct kobj_attribute *attr, char *page)
|
char *page)
|
||||||
{
|
{
|
||||||
char buf[LOADPARM_LEN + 1];
|
char buf[LOADPARM_LEN + 1];
|
||||||
|
|
||||||
reipl_get_ascii_loadparm(buf);
|
reipl_get_ascii_loadparm(buf, ipb);
|
||||||
return sprintf(page, "%s\n", buf);
|
return sprintf(page, "%s\n", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
|
static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb,
|
||||||
struct kobj_attribute *attr,
|
const char *buf, size_t len)
|
||||||
const char *buf, size_t len)
|
|
||||||
{
|
{
|
||||||
int i, lp_len;
|
int i, lp_len;
|
||||||
|
|
||||||
|
@ -552,35 +700,128 @@ static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
/* initialize loadparm with blanks */
|
/* 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 */
|
/* copy and convert to ebcdic */
|
||||||
memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len);
|
memcpy(ipb->ipl_info.ccw.load_parm, buf, lp_len);
|
||||||
ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN);
|
ASCEBC(ipb->ipl_info.ccw.load_parm, LOADPARM_LEN);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct kobj_attribute sys_reipl_ccw_loadparm_attr =
|
/* NSS wrapper */
|
||||||
__ATTR(loadparm, 0644, reipl_ccw_loadparm_show,
|
static ssize_t reipl_nss_loadparm_show(struct kobject *kobj,
|
||||||
reipl_ccw_loadparm_store);
|
struct kobj_attribute *attr, char *page)
|
||||||
|
{
|
||||||
|
return reipl_generic_loadparm_show(reipl_block_nss, page);
|
||||||
|
}
|
||||||
|
|
||||||
static struct attribute *reipl_ccw_attrs[] = {
|
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, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show,
|
||||||
|
reipl_ccw_loadparm_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,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute *reipl_ccw_attrs_lpar[] = {
|
||||||
&sys_reipl_ccw_device_attr.attr,
|
&sys_reipl_ccw_device_attr.attr,
|
||||||
&sys_reipl_ccw_loadparm_attr.attr,
|
&sys_reipl_ccw_loadparm_attr.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group reipl_ccw_attr_group = {
|
static struct attribute_group reipl_ccw_attr_group_vm = {
|
||||||
.name = IPL_CCW_STR,
|
.name = IPL_CCW_STR,
|
||||||
.attrs = reipl_ccw_attrs,
|
.attrs = reipl_ccw_attrs_vm,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group reipl_ccw_attr_group_lpar = {
|
||||||
|
.name = IPL_CCW_STR,
|
||||||
|
.attrs = reipl_ccw_attrs_lpar,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* NSS reipl device attributes */
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name);
|
static ssize_t reipl_nss_name_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr, char *page)
|
||||||
|
{
|
||||||
|
char nss_name[NSS_NAME_SIZE + 1] = {};
|
||||||
|
|
||||||
|
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[] = {
|
static struct attribute *reipl_nss_attrs[] = {
|
||||||
&sys_reipl_nss_name_attr.attr,
|
&sys_reipl_nss_name_attr.attr,
|
||||||
|
&sys_reipl_nss_loadparm_attr.attr,
|
||||||
|
&sys_reipl_nss_vmparm_attr.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -617,7 +858,10 @@ static int reipl_set_type(enum ipl_type type)
|
||||||
reipl_method = REIPL_METHOD_FCP_DUMP;
|
reipl_method = REIPL_METHOD_FCP_DUMP;
|
||||||
break;
|
break;
|
||||||
case IPL_TYPE_NSS:
|
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;
|
break;
|
||||||
case IPL_TYPE_UNKNOWN:
|
case IPL_TYPE_UNKNOWN:
|
||||||
reipl_method = REIPL_METHOD_DEFAULT;
|
reipl_method = REIPL_METHOD_DEFAULT;
|
||||||
|
@ -655,11 +899,38 @@ static struct kobj_attribute reipl_type_attr =
|
||||||
|
|
||||||
static struct kset *reipl_kset;
|
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)
|
static void reipl_run(struct shutdown_trigger *trigger)
|
||||||
{
|
{
|
||||||
struct ccw_dev_id devid;
|
struct ccw_dev_id devid;
|
||||||
static char buf[100];
|
static char buf[128];
|
||||||
char loadparm[LOADPARM_LEN + 1];
|
|
||||||
|
|
||||||
switch (reipl_method) {
|
switch (reipl_method) {
|
||||||
case REIPL_METHOD_CCW_CIO:
|
case REIPL_METHOD_CCW_CIO:
|
||||||
|
@ -668,13 +939,7 @@ static void reipl_run(struct shutdown_trigger *trigger)
|
||||||
reipl_ccw_dev(&devid);
|
reipl_ccw_dev(&devid);
|
||||||
break;
|
break;
|
||||||
case REIPL_METHOD_CCW_VM:
|
case REIPL_METHOD_CCW_VM:
|
||||||
reipl_get_ascii_loadparm(loadparm);
|
get_ipl_string(buf, reipl_block_ccw, REIPL_METHOD_CCW_VM);
|
||||||
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);
|
|
||||||
__cpcmd(buf, NULL, 0, NULL);
|
__cpcmd(buf, NULL, 0, NULL);
|
||||||
break;
|
break;
|
||||||
case REIPL_METHOD_CCW_DIAG:
|
case REIPL_METHOD_CCW_DIAG:
|
||||||
|
@ -691,8 +956,12 @@ static void reipl_run(struct shutdown_trigger *trigger)
|
||||||
case REIPL_METHOD_FCP_RO_VM:
|
case REIPL_METHOD_FCP_RO_VM:
|
||||||
__cpcmd("IPL", NULL, 0, NULL);
|
__cpcmd("IPL", NULL, 0, NULL);
|
||||||
break;
|
break;
|
||||||
|
case REIPL_METHOD_NSS_DIAG:
|
||||||
|
diag308(DIAG308_SET, reipl_block_nss);
|
||||||
|
diag308(DIAG308_IPL, NULL);
|
||||||
|
break;
|
||||||
case REIPL_METHOD_NSS:
|
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);
|
__cpcmd(buf, NULL, 0, NULL);
|
||||||
break;
|
break;
|
||||||
case REIPL_METHOD_DEFAULT:
|
case REIPL_METHOD_DEFAULT:
|
||||||
|
@ -707,16 +976,36 @@ static void reipl_run(struct shutdown_trigger *trigger)
|
||||||
disabled_wait((unsigned long) __builtin_return_address(0));
|
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);
|
static void reipl_block_ccw_fill_parms(struct ipl_parameter_block *ipb)
|
||||||
if (!buffer)
|
{
|
||||||
return;
|
/* LOADPARM */
|
||||||
if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK)
|
/* check if read scp info worked and set loadparm */
|
||||||
diag308_set_works = 1;
|
if (sclp_ipl_info.is_valid)
|
||||||
free_page((unsigned long)buffer);
|
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)
|
static int __init reipl_nss_init(void)
|
||||||
|
@ -725,10 +1014,31 @@ static int __init reipl_nss_init(void)
|
||||||
|
|
||||||
if (!MACHINE_IS_VM)
|
if (!MACHINE_IS_VM)
|
||||||
return 0;
|
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);
|
rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group);
|
||||||
if (rc)
|
if (rc)
|
||||||
return 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;
|
reipl_capabilities |= IPL_TYPE_NSS;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -740,28 +1050,27 @@ static int __init reipl_ccw_init(void)
|
||||||
reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
|
reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
|
||||||
if (!reipl_block_ccw)
|
if (!reipl_block_ccw)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group);
|
|
||||||
if (rc) {
|
if (MACHINE_IS_VM) {
|
||||||
free_page((unsigned long)reipl_block_ccw);
|
if (!diag308_set_works)
|
||||||
return rc;
|
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;
|
if (rc)
|
||||||
reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
|
return rc;
|
||||||
reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
|
|
||||||
reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
|
reipl_block_ccw_init(reipl_block_ccw);
|
||||||
reipl_block_ccw->hdr.flags = DIAG308_FLAGS_LP_VALID;
|
if (ipl_info.type == IPL_TYPE_CCW) {
|
||||||
/* 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)
|
|
||||||
reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
|
reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
|
||||||
|
reipl_block_ccw_fill_parms(reipl_block_ccw);
|
||||||
|
}
|
||||||
|
|
||||||
reipl_capabilities |= IPL_TYPE_CCW;
|
reipl_capabilities |= IPL_TYPE_CCW;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1298,7 +1607,6 @@ static void __init shutdown_actions_init(void)
|
||||||
|
|
||||||
static int __init s390_ipl_init(void)
|
static int __init s390_ipl_init(void)
|
||||||
{
|
{
|
||||||
reipl_probe();
|
|
||||||
sclp_get_ipl_info(&sclp_ipl_info);
|
sclp_get_ipl_info(&sclp_ipl_info);
|
||||||
shutdown_actions_init();
|
shutdown_actions_init();
|
||||||
shutdown_triggers_init();
|
shutdown_triggers_init();
|
||||||
|
@ -1405,6 +1713,12 @@ void __init setup_ipl(void)
|
||||||
atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
|
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)
|
void __init ipl_save_parameters(void)
|
||||||
{
|
{
|
||||||
struct cio_iplinfo iplinfo;
|
struct cio_iplinfo iplinfo;
|
||||||
|
|
|
@ -221,18 +221,17 @@ static void __init conmode_default(void)
|
||||||
#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
|
#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
|
||||||
static void __init setup_zfcpdump(unsigned int console_devno)
|
static void __init setup_zfcpdump(unsigned int console_devno)
|
||||||
{
|
{
|
||||||
static char str[64];
|
static char str[41];
|
||||||
|
|
||||||
if (ipl_info.type != IPL_TYPE_FCP_DUMP)
|
if (ipl_info.type != IPL_TYPE_FCP_DUMP)
|
||||||
return;
|
return;
|
||||||
if (console_devno != -1)
|
if (console_devno != -1)
|
||||||
sprintf(str, "cio_ignore=all,!0.0.%04x,!0.0.%04x",
|
sprintf(str, " cio_ignore=all,!0.0.%04x,!0.0.%04x",
|
||||||
ipl_info.data.fcp.dev_id.devno, console_devno);
|
ipl_info.data.fcp.dev_id.devno, console_devno);
|
||||||
else
|
else
|
||||||
sprintf(str, "cio_ignore=all,!0.0.%04x",
|
sprintf(str, " cio_ignore=all,!0.0.%04x",
|
||||||
ipl_info.data.fcp.dev_id.devno);
|
ipl_info.data.fcp.dev_id.devno);
|
||||||
strcat(COMMAND_LINE, " ");
|
strcat(boot_command_line, str);
|
||||||
strcat(COMMAND_LINE, str);
|
|
||||||
console_loglevel = 2;
|
console_loglevel = 2;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -778,11 +777,9 @@ setup_arch(char **cmdline_p)
|
||||||
printk("We are running native (64 bit mode)\n");
|
printk("We are running native (64 bit mode)\n");
|
||||||
#endif /* CONFIG_64BIT */
|
#endif /* CONFIG_64BIT */
|
||||||
|
|
||||||
/* Save unparsed command line copy for /proc/cmdline */
|
/* Have one command line that is parsed and saved in /proc/cmdline */
|
||||||
strlcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
|
/* boot_command_line has been already set up in early.c */
|
||||||
|
*cmdline_p = boot_command_line;
|
||||||
*cmdline_p = COMMAND_LINE;
|
|
||||||
*(*cmdline_p + COMMAND_LINE_SIZE - 1) = '\0';
|
|
||||||
|
|
||||||
ROOT_DEV = Root_RAM0;
|
ROOT_DEV = Root_RAM0;
|
||||||
|
|
||||||
|
|
|
@ -56,15 +56,19 @@ struct ipl_block_fcp {
|
||||||
u8 scp_data[];
|
u8 scp_data[];
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define DIAG308_VMPARM_SIZE 64
|
||||||
|
|
||||||
struct ipl_block_ccw {
|
struct ipl_block_ccw {
|
||||||
u8 load_param[8];
|
u8 load_parm[8];
|
||||||
u8 reserved1[84];
|
u8 reserved1[84];
|
||||||
u8 reserved2[2];
|
u8 reserved2[2];
|
||||||
u16 devno;
|
u16 devno;
|
||||||
u8 vm_flags;
|
u8 vm_flags;
|
||||||
u8 reserved3[3];
|
u8 reserved3[3];
|
||||||
u32 vm_parm_len;
|
u32 vm_parm_len;
|
||||||
u8 reserved4[80];
|
u8 nss_name[8];
|
||||||
|
u8 vm_parm[DIAG308_VMPARM_SIZE];
|
||||||
|
u8 reserved4[8];
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct ipl_parameter_block {
|
struct ipl_parameter_block {
|
||||||
|
@ -73,7 +77,7 @@ struct ipl_parameter_block {
|
||||||
struct ipl_block_fcp fcp;
|
struct ipl_block_fcp fcp;
|
||||||
struct ipl_block_ccw ccw;
|
struct ipl_block_ccw ccw;
|
||||||
} ipl_info;
|
} ipl_info;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed,aligned(4096)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IPL validity flags
|
* IPL validity flags
|
||||||
|
@ -86,6 +90,8 @@ extern void do_reipl(void);
|
||||||
extern void do_halt(void);
|
extern void do_halt(void);
|
||||||
extern void do_poff(void);
|
extern void do_poff(void);
|
||||||
extern void ipl_save_parameters(void);
|
extern void ipl_save_parameters(void);
|
||||||
|
extern void ipl_update_parameters(void);
|
||||||
|
extern void get_ipl_vmparm(char *);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
IPL_DEVNO_VALID = 1,
|
IPL_DEVNO_VALID = 1,
|
||||||
|
@ -147,6 +153,11 @@ enum diag308_flags {
|
||||||
DIAG308_FLAGS_LP_VALID = 0x80,
|
DIAG308_FLAGS_LP_VALID = 0x80,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum diag308_vm_flags {
|
||||||
|
DIAG308_VM_FLAGS_NSS_VALID = 0x80,
|
||||||
|
DIAG308_VM_FLAGS_VP_VALID = 0x40,
|
||||||
|
};
|
||||||
|
|
||||||
enum diag308_rc {
|
enum diag308_rc {
|
||||||
DIAG308_RC_OK = 1,
|
DIAG308_RC_OK = 1,
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
#ifndef _ASM_S390_SETUP_H
|
#ifndef _ASM_S390_SETUP_H
|
||||||
#define _ASM_S390_SETUP_H
|
#define _ASM_S390_SETUP_H
|
||||||
|
|
||||||
#define COMMAND_LINE_SIZE 896
|
#define COMMAND_LINE_SIZE 1024
|
||||||
|
|
||||||
|
#define ARCH_COMMAND_LINE_SIZE 896
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
|
|
Reference in a new issue