Commit a0443fbb authored by Hendrik Brueckner's avatar Hendrik Brueckner Committed by Heiko Carstens
Browse files

[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: default avatarHendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
parent fe137230
......@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/pfn.h>
#include <linux/uaccess.h>
#include <asm/ebcdic.h>
#include <asm/ipl.h>
#include <asm/lowcore.h>
#include <asm/processor.h>
......@@ -26,12 +27,40 @@
/*
* 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
char kernel_nss_name[NSS_NAME_SIZE + 1];
static void __init setup_boot_command_line(void);
#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)
{
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;
#endif
int response;
size_t len;
char *savesys_ptr;
char upper_command_line[COMMAND_LINE_SIZE];
char defsys_cmd[DEFSYS_CMD_SIZE];
......@@ -49,8 +79,8 @@ static noinline __init void create_kernel_nss(void)
return;
/* Convert COMMAND_LINE to upper case */
for (i = 0; i < strlen(COMMAND_LINE); i++)
upper_command_line[i] = toupper(COMMAND_LINE[i]);
for (i = 0; i < strlen(boot_command_line); i++)
upper_command_line[i] = toupper(boot_command_line[i]);
savesys_ptr = strstr(upper_command_line, "SAVESYS=");
......@@ -83,7 +113,8 @@ static noinline __init void create_kernel_nss(void)
}
#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",
kernel_nss_name, kernel_nss_name);
......@@ -94,13 +125,24 @@ static noinline __init void create_kernel_nss(void)
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';
return;
}
/* re-setup boot command line with new ipl vm parms */
ipl_update_parameters();
setup_boot_command_line();
ipl_flags = IPL_NSS_VALID;
}
......@@ -397,6 +439,26 @@ static __init void rescue_initrd(void)
#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
* 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();
lockdep_init();
lockdep_off();
detect_machine_type();
create_kernel_nss();
sort_main_extable();
setup_lowcore_early();
detect_machine_type();
ipl_update_parameters();
setup_boot_command_line();
create_kernel_nss();
detect_mvpg();
detect_ieee();
detect_csp();
......
......@@ -22,6 +22,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 +122,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 +136,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 +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);
/* 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)
{
......@@ -370,15 +423,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 *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 = {
.attrs = ipl_ccw_attrs,
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 +453,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 +517,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 +553,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 +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",
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 +700,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_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[] = {
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 = {
static struct attribute_group reipl_ccw_attr_group_vm = {
.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 */
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] = {};
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--;
DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name);
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 +858,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 +899,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 +939,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 +956,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 +976,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;