aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/ipl.c
diff options
context:
space:
mode:
authorMichael Holzheu <holzheu@de.ibm.com>2006-12-04 09:39:58 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2006-12-04 09:39:58 -0500
commit03a4d2087644f5477d9a9742e75a329f23b279e6 (patch)
tree809666d8b789a5781ca8e0382c9e3e43bbce6933 /arch/s390/kernel/ipl.c
parentf7675ad791df4bec2b9d21bcc0f846320f0a921b (diff)
[S390] Add ipl/reipl loadparm attribute.
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>
Diffstat (limited to 'arch/s390/kernel/ipl.c')
-rw-r--r--arch/s390/kernel/ipl.c98
1 files changed, 94 insertions, 4 deletions
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 1f5e782b3d05..36f0d3004f94 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -13,12 +13,20 @@
13#include <linux/device.h> 13#include <linux/device.h>
14#include <linux/delay.h> 14#include <linux/delay.h>
15#include <linux/reboot.h> 15#include <linux/reboot.h>
16#include <linux/ctype.h>
16#include <asm/smp.h> 17#include <asm/smp.h>
17#include <asm/setup.h> 18#include <asm/setup.h>
18#include <asm/cpcmd.h> 19#include <asm/cpcmd.h>
19#include <asm/cio.h> 20#include <asm/cio.h>
21#include <asm/ebcdic.h>
20 22
21#define IPL_PARM_BLOCK_VERSION 0 23#define IPL_PARM_BLOCK_VERSION 0
24#define LOADPARM_LEN 8
25
26extern char s390_readinfo_sccb[];
27#define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010)
28#define SCCB_LOADPARM (&s390_readinfo_sccb[24])
29#define SCCB_FLAG (s390_readinfo_sccb[91])
22 30
23enum ipl_type { 31enum ipl_type {
24 IPL_TYPE_NONE = 1, 32 IPL_TYPE_NONE = 1,
@@ -289,9 +297,25 @@ static struct attribute_group ipl_fcp_attr_group = {
289 297
290/* CCW ipl device attributes */ 298/* CCW ipl device attributes */
291 299
300static ssize_t ipl_ccw_loadparm_show(struct subsystem *subsys, char *page)
301{
302 char loadparm[LOADPARM_LEN + 1] = {};
303
304 if (!SCCB_VALID)
305 return sprintf(page, "#unknown#\n");
306 memcpy(loadparm, SCCB_LOADPARM, LOADPARM_LEN);
307 EBCASC(loadparm, LOADPARM_LEN);
308 strstrip(loadparm);
309 return sprintf(page, "%s\n", loadparm);
310}
311
312static struct subsys_attribute sys_ipl_ccw_loadparm_attr =
313 __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
314
292static struct attribute *ipl_ccw_attrs[] = { 315static struct attribute *ipl_ccw_attrs[] = {
293 &sys_ipl_type_attr.attr, 316 &sys_ipl_type_attr.attr,
294 &sys_ipl_device_attr.attr, 317 &sys_ipl_device_attr.attr,
318 &sys_ipl_ccw_loadparm_attr.attr,
295 NULL, 319 NULL,
296}; 320};
297 321
@@ -348,8 +372,57 @@ static struct attribute_group reipl_fcp_attr_group = {
348DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", 372DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
349 reipl_block_ccw->ipl_info.ccw.devno); 373 reipl_block_ccw->ipl_info.ccw.devno);
350 374
375static void reipl_get_ascii_loadparm(char *loadparm)
376{
377 memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param,
378 LOADPARM_LEN);
379 EBCASC(loadparm, LOADPARM_LEN);
380 loadparm[LOADPARM_LEN] = 0;
381 strstrip(loadparm);
382}
383
384static ssize_t reipl_ccw_loadparm_show(struct subsystem *subsys, char *page)
385{
386 char buf[LOADPARM_LEN + 1];
387
388 reipl_get_ascii_loadparm(buf);
389 return sprintf(page, "%s\n", buf);
390}
391
392static ssize_t reipl_ccw_loadparm_store(struct subsystem *subsys,
393 const char *buf, size_t len)
394{
395 int i, lp_len;
396
397 /* ignore trailing newline */
398 lp_len = len;
399 if ((len > 0) && (buf[len - 1] == '\n'))
400 lp_len--;
401 /* loadparm can have max 8 characters and must not start with a blank */
402 if ((lp_len > LOADPARM_LEN) || ((lp_len > 0) && (buf[0] == ' ')))
403 return -EINVAL;
404 /* loadparm can only contain "a-z,A-Z,0-9,SP,." */
405 for (i = 0; i < lp_len; i++) {
406 if (isalpha(buf[i]) || isdigit(buf[i]) || (buf[i] == ' ') ||
407 (buf[i] == '.'))
408 continue;
409 return -EINVAL;
410 }
411 /* initialize loadparm with blanks */
412 memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', LOADPARM_LEN);
413 /* copy and convert to ebcdic */
414 memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len);
415 ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN);
416 return len;
417}
418
419static struct subsys_attribute sys_reipl_ccw_loadparm_attr =
420 __ATTR(loadparm, 0644, reipl_ccw_loadparm_show,
421 reipl_ccw_loadparm_store);
422
351static struct attribute *reipl_ccw_attrs[] = { 423static struct attribute *reipl_ccw_attrs[] = {
352 &sys_reipl_ccw_device_attr.attr, 424 &sys_reipl_ccw_device_attr.attr,
425 &sys_reipl_ccw_loadparm_attr.attr,
353 NULL, 426 NULL,
354}; 427};
355 428
@@ -571,11 +644,14 @@ void do_reipl(void)
571{ 644{
572 struct ccw_dev_id devid; 645 struct ccw_dev_id devid;
573 static char buf[100]; 646 static char buf[100];
647 char loadparm[LOADPARM_LEN + 1];
574 648
575 switch (reipl_type) { 649 switch (reipl_type) {
576 case IPL_TYPE_CCW: 650 case IPL_TYPE_CCW:
651 reipl_get_ascii_loadparm(loadparm);
577 printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n", 652 printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n",
578 reipl_block_ccw->ipl_info.ccw.devno); 653 reipl_block_ccw->ipl_info.ccw.devno);
654 printk(KERN_EMERG "loadparm = '%s'\n", loadparm);
579 break; 655 break;
580 case IPL_TYPE_FCP: 656 case IPL_TYPE_FCP:
581 printk(KERN_EMERG "reboot on fcp device:\n"); 657 printk(KERN_EMERG "reboot on fcp device:\n");
@@ -592,7 +668,12 @@ void do_reipl(void)
592 reipl_ccw_dev(&devid); 668 reipl_ccw_dev(&devid);
593 break; 669 break;
594 case IPL_METHOD_CCW_VM: 670 case IPL_METHOD_CCW_VM:
595 sprintf(buf, "IPL %X", reipl_block_ccw->ipl_info.ccw.devno); 671 if (strlen(loadparm) == 0)
672 sprintf(buf, "IPL %X",
673 reipl_block_ccw->ipl_info.ccw.devno);
674 else
675 sprintf(buf, "IPL %X LOADPARM '%s'",
676 reipl_block_ccw->ipl_info.ccw.devno, loadparm);
596 cpcmd(buf, NULL, 0, NULL); 677 cpcmd(buf, NULL, 0, NULL);
597 break; 678 break;
598 case IPL_METHOD_CCW_DIAG: 679 case IPL_METHOD_CCW_DIAG:
@@ -746,6 +827,17 @@ static int __init reipl_ccw_init(void)
746 reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; 827 reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
747 reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw); 828 reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw);
748 reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; 829 reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
830 /* check if read scp info worked and set loadparm */
831 if (SCCB_VALID)
832 memcpy(reipl_block_ccw->ipl_info.ccw.load_param,
833 SCCB_LOADPARM, LOADPARM_LEN);
834 else
835 /* read scp info failed: set empty loadparm (EBCDIC blanks) */
836 memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40,
837 LOADPARM_LEN);
838 /* FIXME: check for diag308_set_works when enabling diag ccw reipl */
839 if (!MACHINE_IS_VM)
840 sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
749 if (ipl_get_type() == IPL_TYPE_CCW) 841 if (ipl_get_type() == IPL_TYPE_CCW)
750 reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; 842 reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
751 reipl_capabilities |= IPL_TYPE_CCW; 843 reipl_capabilities |= IPL_TYPE_CCW;
@@ -827,13 +919,11 @@ static int __init dump_ccw_init(void)
827 return 0; 919 return 0;
828} 920}
829 921
830extern char s390_readinfo_sccb[];
831
832static int __init dump_fcp_init(void) 922static int __init dump_fcp_init(void)
833{ 923{
834 int rc; 924 int rc;
835 925
836 if(!(s390_readinfo_sccb[91] & 0x2)) 926 if(!(SCCB_FLAG & 0x2) || !SCCB_VALID)
837 return 0; /* LDIPL DUMP is not installed */ 927 return 0; /* LDIPL DUMP is not installed */
838 if (!diag308_set_works) 928 if (!diag308_set_works)
839 return 0; 929 return 0;