Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Michael Holzheu and committed by
Martin Schwidefsky
03a4d208 f7675ad7

+94 -4
+94 -4
arch/s390/kernel/ipl.c
··· 13 13 #include <linux/device.h> 14 14 #include <linux/delay.h> 15 15 #include <linux/reboot.h> 16 + #include <linux/ctype.h> 16 17 #include <asm/smp.h> 17 18 #include <asm/setup.h> 18 19 #include <asm/cpcmd.h> 19 20 #include <asm/cio.h> 21 + #include <asm/ebcdic.h> 20 22 21 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 31 enum ipl_type { 24 32 IPL_TYPE_NONE = 1, ··· 297 289 298 290 /* CCW ipl device attributes */ 299 291 292 + static ssize_t ipl_ccw_loadparm_show(struct subsystem *subsys, char *page) 293 + { 294 + char loadparm[LOADPARM_LEN + 1] = {}; 295 + 296 + if (!SCCB_VALID) 297 + return sprintf(page, "#unknown#\n"); 298 + memcpy(loadparm, SCCB_LOADPARM, LOADPARM_LEN); 299 + EBCASC(loadparm, LOADPARM_LEN); 300 + strstrip(loadparm); 301 + return sprintf(page, "%s\n", loadparm); 302 + } 303 + 304 + static struct subsys_attribute sys_ipl_ccw_loadparm_attr = 305 + __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL); 306 + 300 307 static struct attribute *ipl_ccw_attrs[] = { 301 308 &sys_ipl_type_attr.attr, 302 309 &sys_ipl_device_attr.attr, 310 + &sys_ipl_ccw_loadparm_attr.attr, 303 311 NULL, 304 312 }; 305 313 ··· 372 348 DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", 373 349 reipl_block_ccw->ipl_info.ccw.devno); 374 350 351 + static void reipl_get_ascii_loadparm(char *loadparm) 352 + { 353 + memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param, 354 + LOADPARM_LEN); 355 + EBCASC(loadparm, LOADPARM_LEN); 356 + loadparm[LOADPARM_LEN] = 0; 357 + strstrip(loadparm); 358 + } 359 + 360 + static ssize_t reipl_ccw_loadparm_show(struct subsystem *subsys, char *page) 361 + { 362 + char buf[LOADPARM_LEN + 1]; 363 + 364 + reipl_get_ascii_loadparm(buf); 365 + return sprintf(page, "%s\n", buf); 366 + } 367 + 368 + static ssize_t reipl_ccw_loadparm_store(struct subsystem *subsys, 369 + const char *buf, size_t len) 370 + { 371 + int i, lp_len; 372 + 373 + /* ignore trailing newline */ 374 + lp_len = len; 375 + if ((len > 0) && (buf[len - 1] == '\n')) 376 + lp_len--; 377 + /* loadparm can have max 8 characters and must not start with a blank */ 378 + if ((lp_len > LOADPARM_LEN) || ((lp_len > 0) && (buf[0] == ' '))) 379 + return -EINVAL; 380 + /* loadparm can only contain "a-z,A-Z,0-9,SP,." */ 381 + for (i = 0; i < lp_len; i++) { 382 + if (isalpha(buf[i]) || isdigit(buf[i]) || (buf[i] == ' ') || 383 + (buf[i] == '.')) 384 + continue; 385 + return -EINVAL; 386 + } 387 + /* initialize loadparm with blanks */ 388 + memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', LOADPARM_LEN); 389 + /* copy and convert to ebcdic */ 390 + memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len); 391 + ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN); 392 + return len; 393 + } 394 + 395 + static struct subsys_attribute sys_reipl_ccw_loadparm_attr = 396 + __ATTR(loadparm, 0644, reipl_ccw_loadparm_show, 397 + reipl_ccw_loadparm_store); 398 + 375 399 static struct attribute *reipl_ccw_attrs[] = { 376 400 &sys_reipl_ccw_device_attr.attr, 401 + &sys_reipl_ccw_loadparm_attr.attr, 377 402 NULL, 378 403 }; 379 404 ··· 644 571 { 645 572 struct ccw_dev_id devid; 646 573 static char buf[100]; 574 + char loadparm[LOADPARM_LEN + 1]; 647 575 648 576 switch (reipl_type) { 649 577 case IPL_TYPE_CCW: 578 + reipl_get_ascii_loadparm(loadparm); 650 579 printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n", 651 580 reipl_block_ccw->ipl_info.ccw.devno); 581 + printk(KERN_EMERG "loadparm = '%s'\n", loadparm); 652 582 break; 653 583 case IPL_TYPE_FCP: 654 584 printk(KERN_EMERG "reboot on fcp device:\n"); ··· 668 592 reipl_ccw_dev(&devid); 669 593 break; 670 594 case IPL_METHOD_CCW_VM: 671 - sprintf(buf, "IPL %X", reipl_block_ccw->ipl_info.ccw.devno); 595 + if (strlen(loadparm) == 0) 596 + sprintf(buf, "IPL %X", 597 + reipl_block_ccw->ipl_info.ccw.devno); 598 + else 599 + sprintf(buf, "IPL %X LOADPARM '%s'", 600 + reipl_block_ccw->ipl_info.ccw.devno, loadparm); 672 601 cpcmd(buf, NULL, 0, NULL); 673 602 break; 674 603 case IPL_METHOD_CCW_DIAG: ··· 827 746 reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; 828 747 reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw); 829 748 reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; 749 + /* check if read scp info worked and set loadparm */ 750 + if (SCCB_VALID) 751 + memcpy(reipl_block_ccw->ipl_info.ccw.load_param, 752 + SCCB_LOADPARM, LOADPARM_LEN); 753 + else 754 + /* read scp info failed: set empty loadparm (EBCDIC blanks) */ 755 + memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40, 756 + LOADPARM_LEN); 757 + /* FIXME: check for diag308_set_works when enabling diag ccw reipl */ 758 + if (!MACHINE_IS_VM) 759 + sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO; 830 760 if (ipl_get_type() == IPL_TYPE_CCW) 831 761 reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; 832 762 reipl_capabilities |= IPL_TYPE_CCW; ··· 919 827 return 0; 920 828 } 921 829 922 - extern char s390_readinfo_sccb[]; 923 - 924 830 static int __init dump_fcp_init(void) 925 831 { 926 832 int rc; 927 833 928 - if(!(s390_readinfo_sccb[91] & 0x2)) 834 + if(!(SCCB_FLAG & 0x2) || !SCCB_VALID) 929 835 return 0; /* LDIPL DUMP is not installed */ 930 836 if (!diag308_set_works) 931 837 return 0;