diff options
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/kernel/ipl.c | 98 |
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 | |||
26 | extern 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 | ||
23 | enum ipl_type { | 31 | enum 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 | ||
300 | static 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 | |||
312 | static struct subsys_attribute sys_ipl_ccw_loadparm_attr = | ||
313 | __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL); | ||
314 | |||
292 | static struct attribute *ipl_ccw_attrs[] = { | 315 | static 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 = { | |||
348 | DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", | 372 | DEFINE_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 | ||
375 | static 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 | |||
384 | static 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 | |||
392 | static 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 | |||
419 | static struct subsys_attribute sys_reipl_ccw_loadparm_attr = | ||
420 | __ATTR(loadparm, 0644, reipl_ccw_loadparm_show, | ||
421 | reipl_ccw_loadparm_store); | ||
422 | |||
351 | static struct attribute *reipl_ccw_attrs[] = { | 423 | static 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 | ||
830 | extern char s390_readinfo_sccb[]; | ||
831 | |||
832 | static int __init dump_fcp_init(void) | 922 | static 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; |