aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390')
-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;