aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/ipl.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/ipl.c')
-rw-r--r--arch/s390/kernel/ipl.c236
1 files changed, 166 insertions, 70 deletions
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 1f5e782b3d05..9e9972e8a52b 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -13,12 +13,21 @@
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>
22#include <asm/reset.h>
20 23
21#define IPL_PARM_BLOCK_VERSION 0 24#define IPL_PARM_BLOCK_VERSION 0
25#define LOADPARM_LEN 8
26
27extern char s390_readinfo_sccb[];
28#define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010)
29#define SCCB_LOADPARM (&s390_readinfo_sccb[24])
30#define SCCB_FLAG (s390_readinfo_sccb[91])
22 31
23enum ipl_type { 32enum ipl_type {
24 IPL_TYPE_NONE = 1, 33 IPL_TYPE_NONE = 1,
@@ -289,9 +298,25 @@ static struct attribute_group ipl_fcp_attr_group = {
289 298
290/* CCW ipl device attributes */ 299/* CCW ipl device attributes */
291 300
301static ssize_t ipl_ccw_loadparm_show(struct subsystem *subsys, char *page)
302{
303 char loadparm[LOADPARM_LEN + 1] = {};
304
305 if (!SCCB_VALID)
306 return sprintf(page, "#unknown#\n");
307 memcpy(loadparm, SCCB_LOADPARM, LOADPARM_LEN);
308 EBCASC(loadparm, LOADPARM_LEN);
309 strstrip(loadparm);
310 return sprintf(page, "%s\n", loadparm);
311}
312
313static struct subsys_attribute sys_ipl_ccw_loadparm_attr =
314 __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
315
292static struct attribute *ipl_ccw_attrs[] = { 316static struct attribute *ipl_ccw_attrs[] = {
293 &sys_ipl_type_attr.attr, 317 &sys_ipl_type_attr.attr,
294 &sys_ipl_device_attr.attr, 318 &sys_ipl_device_attr.attr,
319 &sys_ipl_ccw_loadparm_attr.attr,
295 NULL, 320 NULL,
296}; 321};
297 322
@@ -348,8 +373,57 @@ static struct attribute_group reipl_fcp_attr_group = {
348DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", 373DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
349 reipl_block_ccw->ipl_info.ccw.devno); 374 reipl_block_ccw->ipl_info.ccw.devno);
350 375
376static void reipl_get_ascii_loadparm(char *loadparm)
377{
378 memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param,
379 LOADPARM_LEN);
380 EBCASC(loadparm, LOADPARM_LEN);
381 loadparm[LOADPARM_LEN] = 0;
382 strstrip(loadparm);
383}
384
385static ssize_t reipl_ccw_loadparm_show(struct subsystem *subsys, char *page)
386{
387 char buf[LOADPARM_LEN + 1];
388
389 reipl_get_ascii_loadparm(buf);
390 return sprintf(page, "%s\n", buf);
391}
392
393static ssize_t reipl_ccw_loadparm_store(struct subsystem *subsys,
394 const char *buf, size_t len)
395{
396 int i, lp_len;
397
398 /* ignore trailing newline */
399 lp_len = len;
400 if ((len > 0) && (buf[len - 1] == '\n'))
401 lp_len--;
402 /* loadparm can have max 8 characters and must not start with a blank */
403 if ((lp_len > LOADPARM_LEN) || ((lp_len > 0) && (buf[0] == ' ')))
404 return -EINVAL;
405 /* loadparm can only contain "a-z,A-Z,0-9,SP,." */
406 for (i = 0; i < lp_len; i++) {
407 if (isalpha(buf[i]) || isdigit(buf[i]) || (buf[i] == ' ') ||
408 (buf[i] == '.'))
409 continue;
410 return -EINVAL;
411 }
412 /* initialize loadparm with blanks */
413 memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', LOADPARM_LEN);
414 /* copy and convert to ebcdic */
415 memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len);
416 ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN);
417 return len;
418}
419
420static struct subsys_attribute sys_reipl_ccw_loadparm_attr =
421 __ATTR(loadparm, 0644, reipl_ccw_loadparm_show,
422 reipl_ccw_loadparm_store);
423
351static struct attribute *reipl_ccw_attrs[] = { 424static struct attribute *reipl_ccw_attrs[] = {
352 &sys_reipl_ccw_device_attr.attr, 425 &sys_reipl_ccw_device_attr.attr,
426 &sys_reipl_ccw_loadparm_attr.attr,
353 NULL, 427 NULL,
354}; 428};
355 429
@@ -502,23 +576,6 @@ static struct subsys_attribute dump_type_attr =
502 576
503static decl_subsys(dump, NULL, NULL); 577static decl_subsys(dump, NULL, NULL);
504 578
505#ifdef CONFIG_SMP
506static void dump_smp_stop_all(void)
507{
508 int cpu;
509 preempt_disable();
510 for_each_online_cpu(cpu) {
511 if (cpu == smp_processor_id())
512 continue;
513 while (signal_processor(cpu, sigp_stop) == sigp_busy)
514 udelay(10);
515 }
516 preempt_enable();
517}
518#else
519#define dump_smp_stop_all() do { } while (0)
520#endif
521
522/* 579/*
523 * Shutdown actions section 580 * Shutdown actions section
524 */ 581 */
@@ -552,48 +609,29 @@ static ssize_t on_panic_store(struct subsystem *subsys, const char *buf,
552static struct subsys_attribute on_panic_attr = 609static struct subsys_attribute on_panic_attr =
553 __ATTR(on_panic, 0644, on_panic_show, on_panic_store); 610 __ATTR(on_panic, 0644, on_panic_show, on_panic_store);
554 611
555static void print_fcp_block(struct ipl_parameter_block *fcp_block)
556{
557 printk(KERN_EMERG "wwpn: %016llx\n",
558 (unsigned long long)fcp_block->ipl_info.fcp.wwpn);
559 printk(KERN_EMERG "lun: %016llx\n",
560 (unsigned long long)fcp_block->ipl_info.fcp.lun);
561 printk(KERN_EMERG "bootprog: %lld\n",
562 (unsigned long long)fcp_block->ipl_info.fcp.bootprog);
563 printk(KERN_EMERG "br_lba: %lld\n",
564 (unsigned long long)fcp_block->ipl_info.fcp.br_lba);
565 printk(KERN_EMERG "device: %llx\n",
566 (unsigned long long)fcp_block->ipl_info.fcp.devno);
567 printk(KERN_EMERG "opt: %x\n", fcp_block->ipl_info.fcp.opt);
568}
569
570void do_reipl(void) 612void do_reipl(void)
571{ 613{
572 struct ccw_dev_id devid; 614 struct ccw_dev_id devid;
573 static char buf[100]; 615 static char buf[100];
574 616 char loadparm[LOADPARM_LEN + 1];
575 switch (reipl_type) {
576 case IPL_TYPE_CCW:
577 printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n",
578 reipl_block_ccw->ipl_info.ccw.devno);
579 break;
580 case IPL_TYPE_FCP:
581 printk(KERN_EMERG "reboot on fcp device:\n");
582 print_fcp_block(reipl_block_fcp);
583 break;
584 default:
585 break;
586 }
587 617
588 switch (reipl_method) { 618 switch (reipl_method) {
589 case IPL_METHOD_CCW_CIO: 619 case IPL_METHOD_CCW_CIO:
590 devid.devno = reipl_block_ccw->ipl_info.ccw.devno; 620 devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
621 if (ipl_get_type() == IPL_TYPE_CCW && devid.devno == ipl_devno)
622 diag308(DIAG308_IPL, NULL);
591 devid.ssid = 0; 623 devid.ssid = 0;
592 reipl_ccw_dev(&devid); 624 reipl_ccw_dev(&devid);
593 break; 625 break;
594 case IPL_METHOD_CCW_VM: 626 case IPL_METHOD_CCW_VM:
595 sprintf(buf, "IPL %X", reipl_block_ccw->ipl_info.ccw.devno); 627 reipl_get_ascii_loadparm(loadparm);
596 cpcmd(buf, NULL, 0, NULL); 628 if (strlen(loadparm) == 0)
629 sprintf(buf, "IPL %X",
630 reipl_block_ccw->ipl_info.ccw.devno);
631 else
632 sprintf(buf, "IPL %X LOADPARM '%s'",
633 reipl_block_ccw->ipl_info.ccw.devno, loadparm);
634 __cpcmd(buf, NULL, 0, NULL);
597 break; 635 break;
598 case IPL_METHOD_CCW_DIAG: 636 case IPL_METHOD_CCW_DIAG:
599 diag308(DIAG308_SET, reipl_block_ccw); 637 diag308(DIAG308_SET, reipl_block_ccw);
@@ -607,16 +645,16 @@ void do_reipl(void)
607 diag308(DIAG308_IPL, NULL); 645 diag308(DIAG308_IPL, NULL);
608 break; 646 break;
609 case IPL_METHOD_FCP_RO_VM: 647 case IPL_METHOD_FCP_RO_VM:
610 cpcmd("IPL", NULL, 0, NULL); 648 __cpcmd("IPL", NULL, 0, NULL);
611 break; 649 break;
612 case IPL_METHOD_NONE: 650 case IPL_METHOD_NONE:
613 default: 651 default:
614 if (MACHINE_IS_VM) 652 if (MACHINE_IS_VM)
615 cpcmd("IPL", NULL, 0, NULL); 653 __cpcmd("IPL", NULL, 0, NULL);
616 diag308(DIAG308_IPL, NULL); 654 diag308(DIAG308_IPL, NULL);
617 break; 655 break;
618 } 656 }
619 panic("reipl failed!\n"); 657 signal_processor(smp_processor_id(), sigp_stop_and_store_status);
620} 658}
621 659
622static void do_dump(void) 660static void do_dump(void)
@@ -624,32 +662,19 @@ static void do_dump(void)
624 struct ccw_dev_id devid; 662 struct ccw_dev_id devid;
625 static char buf[100]; 663 static char buf[100];
626 664
627 switch (dump_type) {
628 case IPL_TYPE_CCW:
629 printk(KERN_EMERG "Automatic dump on ccw device: 0.0.%04x\n",
630 dump_block_ccw->ipl_info.ccw.devno);
631 break;
632 case IPL_TYPE_FCP:
633 printk(KERN_EMERG "Automatic dump on fcp device:\n");
634 print_fcp_block(dump_block_fcp);
635 break;
636 default:
637 return;
638 }
639
640 switch (dump_method) { 665 switch (dump_method) {
641 case IPL_METHOD_CCW_CIO: 666 case IPL_METHOD_CCW_CIO:
642 dump_smp_stop_all(); 667 smp_send_stop();
643 devid.devno = dump_block_ccw->ipl_info.ccw.devno; 668 devid.devno = dump_block_ccw->ipl_info.ccw.devno;
644 devid.ssid = 0; 669 devid.ssid = 0;
645 reipl_ccw_dev(&devid); 670 reipl_ccw_dev(&devid);
646 break; 671 break;
647 case IPL_METHOD_CCW_VM: 672 case IPL_METHOD_CCW_VM:
648 dump_smp_stop_all(); 673 smp_send_stop();
649 sprintf(buf, "STORE STATUS"); 674 sprintf(buf, "STORE STATUS");
650 cpcmd(buf, NULL, 0, NULL); 675 __cpcmd(buf, NULL, 0, NULL);
651 sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno); 676 sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
652 cpcmd(buf, NULL, 0, NULL); 677 __cpcmd(buf, NULL, 0, NULL);
653 break; 678 break;
654 case IPL_METHOD_CCW_DIAG: 679 case IPL_METHOD_CCW_DIAG:
655 diag308(DIAG308_SET, dump_block_ccw); 680 diag308(DIAG308_SET, dump_block_ccw);
@@ -746,6 +771,17 @@ static int __init reipl_ccw_init(void)
746 reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; 771 reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
747 reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw); 772 reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw);
748 reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; 773 reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
774 /* check if read scp info worked and set loadparm */
775 if (SCCB_VALID)
776 memcpy(reipl_block_ccw->ipl_info.ccw.load_param,
777 SCCB_LOADPARM, LOADPARM_LEN);
778 else
779 /* read scp info failed: set empty loadparm (EBCDIC blanks) */
780 memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40,
781 LOADPARM_LEN);
782 /* FIXME: check for diag308_set_works when enabling diag ccw reipl */
783 if (!MACHINE_IS_VM)
784 sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
749 if (ipl_get_type() == IPL_TYPE_CCW) 785 if (ipl_get_type() == IPL_TYPE_CCW)
750 reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; 786 reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
751 reipl_capabilities |= IPL_TYPE_CCW; 787 reipl_capabilities |= IPL_TYPE_CCW;
@@ -827,13 +863,11 @@ static int __init dump_ccw_init(void)
827 return 0; 863 return 0;
828} 864}
829 865
830extern char s390_readinfo_sccb[];
831
832static int __init dump_fcp_init(void) 866static int __init dump_fcp_init(void)
833{ 867{
834 int rc; 868 int rc;
835 869
836 if(!(s390_readinfo_sccb[91] & 0x2)) 870 if(!(SCCB_FLAG & 0x2) || !SCCB_VALID)
837 return 0; /* LDIPL DUMP is not installed */ 871 return 0; /* LDIPL DUMP is not installed */
838 if (!diag308_set_works) 872 if (!diag308_set_works)
839 return 0; 873 return 0;
@@ -931,3 +965,65 @@ static int __init s390_ipl_init(void)
931} 965}
932 966
933__initcall(s390_ipl_init); 967__initcall(s390_ipl_init);
968
969static LIST_HEAD(rcall);
970static DEFINE_MUTEX(rcall_mutex);
971
972void register_reset_call(struct reset_call *reset)
973{
974 mutex_lock(&rcall_mutex);
975 list_add(&reset->list, &rcall);
976 mutex_unlock(&rcall_mutex);
977}
978EXPORT_SYMBOL_GPL(register_reset_call);
979
980void unregister_reset_call(struct reset_call *reset)
981{
982 mutex_lock(&rcall_mutex);
983 list_del(&reset->list);
984 mutex_unlock(&rcall_mutex);
985}
986EXPORT_SYMBOL_GPL(unregister_reset_call);
987
988static void do_reset_calls(void)
989{
990 struct reset_call *reset;
991
992 list_for_each_entry(reset, &rcall, list)
993 reset->fn();
994}
995
996extern void reset_mcck_handler(void);
997extern void reset_pgm_handler(void);
998extern __u32 dump_prefix_page;
999
1000void s390_reset_system(void)
1001{
1002 struct _lowcore *lc;
1003
1004 lc = (struct _lowcore *)(unsigned long) store_prefix();
1005
1006 /* Stack for interrupt/machine check handler */
1007 lc->panic_stack = S390_lowcore.panic_stack;
1008
1009 /* Save prefix page address for dump case */
1010 dump_prefix_page = (unsigned long) lc;
1011
1012 /* Disable prefixing */
1013 set_prefix(0);
1014
1015 /* Disable lowcore protection */
1016 __ctl_clear_bit(0,28);
1017
1018 /* Set new machine check handler */
1019 S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
1020 S390_lowcore.mcck_new_psw.addr =
1021 PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler;
1022
1023 /* Set new program check handler */
1024 S390_lowcore.program_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
1025 S390_lowcore.program_new_psw.addr =
1026 PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler;
1027
1028 do_reset_calls();
1029}