Skip to content

Commit

Permalink
[S390] Add ipl/reipl loadparm attribute.
Browse files Browse the repository at this point in the history
If multiple kernel images are installed on one DASD, the loadparm can be used
to select the boot configuration. This patch introduces the following two new
sysfs attributes:

/sys/firmware/ipl/loadparm: shows loadparm of current system (ro)
/sys/firmware/reipl/ccw/loadparm: loadparm used for next reboot (rw)

Signed-off-by: Michael Holzheu <holzheu@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
  • Loading branch information
Michael Holzheu authored and Martin Schwidefsky committed Dec 4, 2006
1 parent f7675ad commit 03a4d20
Showing 1 changed file with 94 additions and 4 deletions.
98 changes: 94 additions & 4 deletions arch/s390/kernel/ipl.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,20 @@
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/reboot.h>
#include <linux/ctype.h>
#include <asm/smp.h>
#include <asm/setup.h>
#include <asm/cpcmd.h>
#include <asm/cio.h>
#include <asm/ebcdic.h>

#define IPL_PARM_BLOCK_VERSION 0
#define LOADPARM_LEN 8

extern char s390_readinfo_sccb[];
#define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010)
#define SCCB_LOADPARM (&s390_readinfo_sccb[24])
#define SCCB_FLAG (s390_readinfo_sccb[91])

enum ipl_type {
IPL_TYPE_NONE = 1,
Expand Down Expand Up @@ -289,9 +297,25 @@ static struct attribute_group ipl_fcp_attr_group = {

/* CCW ipl device attributes */

static ssize_t ipl_ccw_loadparm_show(struct subsystem *subsys, char *page)
{
char loadparm[LOADPARM_LEN + 1] = {};

if (!SCCB_VALID)
return sprintf(page, "#unknown#\n");
memcpy(loadparm, SCCB_LOADPARM, LOADPARM_LEN);
EBCASC(loadparm, LOADPARM_LEN);
strstrip(loadparm);
return sprintf(page, "%s\n", loadparm);
}

static struct subsys_attribute sys_ipl_ccw_loadparm_attr =
__ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);

static struct attribute *ipl_ccw_attrs[] = {
&sys_ipl_type_attr.attr,
&sys_ipl_device_attr.attr,
&sys_ipl_ccw_loadparm_attr.attr,
NULL,
};

Expand Down Expand Up @@ -348,8 +372,57 @@ 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)
{
memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param,
LOADPARM_LEN);
EBCASC(loadparm, LOADPARM_LEN);
loadparm[LOADPARM_LEN] = 0;
strstrip(loadparm);
}

static ssize_t reipl_ccw_loadparm_show(struct subsystem *subsys, char *page)
{
char buf[LOADPARM_LEN + 1];

reipl_get_ascii_loadparm(buf);
return sprintf(page, "%s\n", buf);
}

static ssize_t reipl_ccw_loadparm_store(struct subsystem *subsys,
const char *buf, size_t len)
{
int i, lp_len;

/* ignore trailing newline */
lp_len = len;
if ((len > 0) && (buf[len - 1] == '\n'))
lp_len--;
/* loadparm can have max 8 characters and must not start with a blank */
if ((lp_len > LOADPARM_LEN) || ((lp_len > 0) && (buf[0] == ' ')))
return -EINVAL;
/* loadparm can only contain "a-z,A-Z,0-9,SP,." */
for (i = 0; i < lp_len; i++) {
if (isalpha(buf[i]) || isdigit(buf[i]) || (buf[i] == ' ') ||
(buf[i] == '.'))
continue;
return -EINVAL;
}
/* initialize loadparm with blanks */
memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', 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);
return len;
}

static struct subsys_attribute sys_reipl_ccw_loadparm_attr =
__ATTR(loadparm, 0644, reipl_ccw_loadparm_show,
reipl_ccw_loadparm_store);

static struct attribute *reipl_ccw_attrs[] = {
&sys_reipl_ccw_device_attr.attr,
&sys_reipl_ccw_loadparm_attr.attr,
NULL,
};

Expand Down Expand Up @@ -571,11 +644,14 @@ void do_reipl(void)
{
struct ccw_dev_id devid;
static char buf[100];
char loadparm[LOADPARM_LEN + 1];

switch (reipl_type) {
case IPL_TYPE_CCW:
reipl_get_ascii_loadparm(loadparm);
printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n",
reipl_block_ccw->ipl_info.ccw.devno);
printk(KERN_EMERG "loadparm = '%s'\n", loadparm);
break;
case IPL_TYPE_FCP:
printk(KERN_EMERG "reboot on fcp device:\n");
Expand All @@ -592,7 +668,12 @@ void do_reipl(void)
reipl_ccw_dev(&devid);
break;
case IPL_METHOD_CCW_VM:
sprintf(buf, "IPL %X", reipl_block_ccw->ipl_info.ccw.devno);
if (strlen(loadparm) == 0)
sprintf(buf, "IPL %X",
reipl_block_ccw->ipl_info.ccw.devno);
else
sprintf(buf, "IPL %X LOADPARM '%s'",
reipl_block_ccw->ipl_info.ccw.devno, loadparm);
cpcmd(buf, NULL, 0, NULL);
break;
case IPL_METHOD_CCW_DIAG:
Expand Down Expand Up @@ -746,6 +827,17 @@ static int __init reipl_ccw_init(void)
reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw);
reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
/* check if read scp info worked and set loadparm */
if (SCCB_VALID)
memcpy(reipl_block_ccw->ipl_info.ccw.load_param,
SCCB_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);
/* FIXME: check for diag308_set_works when enabling diag ccw reipl */
if (!MACHINE_IS_VM)
sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
if (ipl_get_type() == IPL_TYPE_CCW)
reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
reipl_capabilities |= IPL_TYPE_CCW;
Expand Down Expand Up @@ -827,13 +919,11 @@ static int __init dump_ccw_init(void)
return 0;
}

extern char s390_readinfo_sccb[];

static int __init dump_fcp_init(void)
{
int rc;

if(!(s390_readinfo_sccb[91] & 0x2))
if(!(SCCB_FLAG & 0x2) || !SCCB_VALID)
return 0; /* LDIPL DUMP is not installed */
if (!diag308_set_works)
return 0;
Expand Down

0 comments on commit 03a4d20

Please sign in to comment.