aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>2009-09-11 04:28:40 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2009-09-11 04:29:46 -0400
commit684d2fd48e718e70dad21ef7c528649578147e48 (patch)
treed830bd35b8871f29998dbeada751e07e310ddac8
parent6292b9ef5a4e85d6b782412a85725dd38df24b85 (diff)
[S390] kernel: Append scpdata to kernel boot command line
Append scpdata to the kernel boot command line. If scpdata starts with the equal sign (=), the kernel boot command line is replaced. (For consistency with zIPL and IPL PARM parameters.) To use scpdata for the kernel boot command line, scpdata must consist of ascii characters only. If scpdata contains other characters, scpdata is not appended to the kernel boot command line. In addition, re-IPL is extended for setting scpdata for the next Linux reboot. Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/ipl.h5
-rw-r--r--arch/s390/include/asm/setup.h2
-rw-r--r--arch/s390/kernel/early.c35
-rw-r--r--arch/s390/kernel/ipl.c157
4 files changed, 172 insertions, 27 deletions
diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h
index 1171e6d144a3..5e95d95450b3 100644
--- a/arch/s390/include/asm/ipl.h
+++ b/arch/s390/include/asm/ipl.h
@@ -57,6 +57,8 @@ struct ipl_block_fcp {
57} __attribute__((packed)); 57} __attribute__((packed));
58 58
59#define DIAG308_VMPARM_SIZE 64 59#define DIAG308_VMPARM_SIZE 64
60#define DIAG308_SCPDATA_SIZE (PAGE_SIZE - (sizeof(struct ipl_list_hdr) + \
61 offsetof(struct ipl_block_fcp, scp_data)))
60 62
61struct ipl_block_ccw { 63struct ipl_block_ccw {
62 u8 load_parm[8]; 64 u8 load_parm[8];
@@ -91,7 +93,8 @@ extern void do_halt(void);
91extern void do_poff(void); 93extern void do_poff(void);
92extern void ipl_save_parameters(void); 94extern void ipl_save_parameters(void);
93extern void ipl_update_parameters(void); 95extern void ipl_update_parameters(void);
94extern void get_ipl_vmparm(char *); 96extern size_t append_ipl_vmparm(char *, size_t);
97extern size_t append_ipl_scpdata(char *, size_t);
95 98
96enum { 99enum {
97 IPL_DEVNO_VALID = 1, 100 IPL_DEVNO_VALID = 1,
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index 38b0fc221ed7..e37478e87286 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -8,7 +8,7 @@
8#ifndef _ASM_S390_SETUP_H 8#ifndef _ASM_S390_SETUP_H
9#define _ASM_S390_SETUP_H 9#define _ASM_S390_SETUP_H
10 10
11#define COMMAND_LINE_SIZE 1024 11#define COMMAND_LINE_SIZE 4096
12 12
13#define ARCH_COMMAND_LINE_SIZE 896 13#define ARCH_COMMAND_LINE_SIZE 896
14 14
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index cae14c499511..21f3799fe27c 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -81,6 +81,8 @@ asm(
81 " br 14\n" 81 " br 14\n"
82 " .size savesys_ipl_nss, .-savesys_ipl_nss\n"); 82 " .size savesys_ipl_nss, .-savesys_ipl_nss\n");
83 83
84static __initdata char upper_command_line[COMMAND_LINE_SIZE];
85
84static noinline __init void create_kernel_nss(void) 86static noinline __init void create_kernel_nss(void)
85{ 87{
86 unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size; 88 unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
@@ -90,7 +92,6 @@ static noinline __init void create_kernel_nss(void)
90 int response; 92 int response;
91 size_t len; 93 size_t len;
92 char *savesys_ptr; 94 char *savesys_ptr;
93 char upper_command_line[COMMAND_LINE_SIZE];
94 char defsys_cmd[DEFSYS_CMD_SIZE]; 95 char defsys_cmd[DEFSYS_CMD_SIZE];
95 char savesys_cmd[SAVESYS_CMD_SIZE]; 96 char savesys_cmd[SAVESYS_CMD_SIZE];
96 97
@@ -367,21 +368,35 @@ static __init void rescue_initrd(void)
367} 368}
368 369
369/* Set up boot command line */ 370/* Set up boot command line */
370static void __init setup_boot_command_line(void) 371static void __init append_to_cmdline(size_t (*ipl_data)(char *, size_t))
371{ 372{
372 char *parm = NULL; 373 char *parm, *delim;
374 size_t rc, len;
375
376 len = strlen(boot_command_line);
373 377
378 delim = boot_command_line + len; /* '\0' character position */
379 parm = boot_command_line + len + 1; /* append right after '\0' */
380
381 rc = ipl_data(parm, COMMAND_LINE_SIZE - len - 1);
382 if (rc) {
383 if (*parm == '=')
384 memmove(boot_command_line, parm + 1, rc);
385 else
386 *delim = ' '; /* replace '\0' with space */
387 }
388}
389
390static void __init setup_boot_command_line(void)
391{
374 /* copy arch command line */ 392 /* copy arch command line */
375 strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); 393 strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE);
376 394
377 /* append IPL PARM data to the boot command line */ 395 /* append IPL PARM data to the boot command line */
378 if (MACHINE_IS_VM) { 396 if (MACHINE_IS_VM)
379 parm = boot_command_line + strlen(boot_command_line); 397 append_to_cmdline(append_ipl_vmparm);
380 *parm++ = ' '; 398
381 get_ipl_vmparm(parm); 399 append_to_cmdline(append_ipl_scpdata);
382 if (parm[0] == '=')
383 memmove(boot_command_line, parm + 1, strlen(parm));
384 }
385} 400}
386 401
387 402
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 371a2d88f4ac..04451a5e3c15 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -272,17 +272,18 @@ static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr,
272static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); 272static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
273 273
274/* VM IPL PARM routines */ 274/* VM IPL PARM routines */
275static void reipl_get_ascii_vmparm(char *dest, 275size_t reipl_get_ascii_vmparm(char *dest, size_t size,
276 const struct ipl_parameter_block *ipb) 276 const struct ipl_parameter_block *ipb)
277{ 277{
278 int i; 278 int i;
279 int len = 0; 279 size_t len;
280 char has_lowercase = 0; 280 char has_lowercase = 0;
281 281
282 len = 0;
282 if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) && 283 if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) &&
283 (ipb->ipl_info.ccw.vm_parm_len > 0)) { 284 (ipb->ipl_info.ccw.vm_parm_len > 0)) {
284 285
285 len = ipb->ipl_info.ccw.vm_parm_len; 286 len = min_t(size_t, size - 1, ipb->ipl_info.ccw.vm_parm_len);
286 memcpy(dest, ipb->ipl_info.ccw.vm_parm, len); 287 memcpy(dest, ipb->ipl_info.ccw.vm_parm, len);
287 /* If at least one character is lowercase, we assume mixed 288 /* If at least one character is lowercase, we assume mixed
288 * case; otherwise we convert everything to lowercase. 289 * case; otherwise we convert everything to lowercase.
@@ -299,14 +300,20 @@ static void reipl_get_ascii_vmparm(char *dest,
299 EBCASC(dest, len); 300 EBCASC(dest, len);
300 } 301 }
301 dest[len] = 0; 302 dest[len] = 0;
303
304 return len;
302} 305}
303 306
304void get_ipl_vmparm(char *dest) 307size_t append_ipl_vmparm(char *dest, size_t size)
305{ 308{
309 size_t rc;
310
311 rc = 0;
306 if (diag308_set_works && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW)) 312 if (diag308_set_works && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW))
307 reipl_get_ascii_vmparm(dest, &ipl_block); 313 rc = reipl_get_ascii_vmparm(dest, size, &ipl_block);
308 else 314 else
309 dest[0] = 0; 315 dest[0] = 0;
316 return rc;
310} 317}
311 318
312static ssize_t ipl_vm_parm_show(struct kobject *kobj, 319static ssize_t ipl_vm_parm_show(struct kobject *kobj,
@@ -314,10 +321,56 @@ static ssize_t ipl_vm_parm_show(struct kobject *kobj,
314{ 321{
315 char parm[DIAG308_VMPARM_SIZE + 1] = {}; 322 char parm[DIAG308_VMPARM_SIZE + 1] = {};
316 323
317 get_ipl_vmparm(parm); 324 append_ipl_vmparm(parm, sizeof(parm));
318 return sprintf(page, "%s\n", parm); 325 return sprintf(page, "%s\n", parm);
319} 326}
320 327
328static size_t scpdata_length(const char* buf, size_t count)
329{
330 while (count) {
331 if (buf[count - 1] != '\0' && buf[count - 1] != ' ')
332 break;
333 count--;
334 }
335 return count;
336}
337
338size_t reipl_append_ascii_scpdata(char *dest, size_t size,
339 const struct ipl_parameter_block *ipb)
340{
341 size_t count;
342 size_t i;
343
344 count = min(size - 1, scpdata_length(ipb->ipl_info.fcp.scp_data,
345 ipb->ipl_info.fcp.scp_data_len));
346 if (!count)
347 goto out;
348
349 for (i = 0; i < count; i++)
350 if (!isascii(ipb->ipl_info.fcp.scp_data[i])) {
351 count = 0;
352 goto out;
353 }
354
355 memcpy(dest, ipb->ipl_info.fcp.scp_data, count);
356out:
357 dest[count] = '\0';
358 return count;
359}
360
361size_t append_ipl_scpdata(char *dest, size_t len)
362{
363 size_t rc;
364
365 rc = 0;
366 if (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_FCP)
367 rc = reipl_append_ascii_scpdata(dest, len, &ipl_block);
368 else
369 dest[0] = 0;
370 return rc;
371}
372
373
321static struct kobj_attribute sys_ipl_vm_parm_attr = 374static struct kobj_attribute sys_ipl_vm_parm_attr =
322 __ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL); 375 __ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL);
323 376
@@ -553,7 +606,7 @@ static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb,
553{ 606{
554 char vmparm[DIAG308_VMPARM_SIZE + 1] = {}; 607 char vmparm[DIAG308_VMPARM_SIZE + 1] = {};
555 608
556 reipl_get_ascii_vmparm(vmparm, ipb); 609 reipl_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb);
557 return sprintf(page, "%s\n", vmparm); 610 return sprintf(page, "%s\n", vmparm);
558} 611}
559 612
@@ -626,6 +679,59 @@ static struct kobj_attribute sys_reipl_ccw_vmparm_attr =
626 679
627/* FCP reipl device attributes */ 680/* FCP reipl device attributes */
628 681
682static ssize_t reipl_fcp_scpdata_read(struct kobject *kobj,
683 struct bin_attribute *attr,
684 char *buf, loff_t off, size_t count)
685{
686 size_t size = reipl_block_fcp->ipl_info.fcp.scp_data_len;
687 void *scp_data = reipl_block_fcp->ipl_info.fcp.scp_data;
688
689 return memory_read_from_buffer(buf, count, &off, scp_data, size);
690}
691
692static ssize_t reipl_fcp_scpdata_write(struct kobject *kobj,
693 struct bin_attribute *attr,
694 char *buf, loff_t off, size_t count)
695{
696 size_t padding;
697 size_t scpdata_len;
698
699 if (off < 0)
700 return -EINVAL;
701
702 if (off >= DIAG308_SCPDATA_SIZE)
703 return -ENOSPC;
704
705 if (count > DIAG308_SCPDATA_SIZE - off)
706 count = DIAG308_SCPDATA_SIZE - off;
707
708 memcpy(reipl_block_fcp->ipl_info.fcp.scp_data, buf + off, count);
709 scpdata_len = off + count;
710
711 if (scpdata_len % 8) {
712 padding = 8 - (scpdata_len % 8);
713 memset(reipl_block_fcp->ipl_info.fcp.scp_data + scpdata_len,
714 0, padding);
715 scpdata_len += padding;
716 }
717
718 reipl_block_fcp->ipl_info.fcp.scp_data_len = scpdata_len;
719 reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN + scpdata_len;
720 reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN + scpdata_len;
721
722 return count;
723}
724
725static struct bin_attribute sys_reipl_fcp_scp_data_attr = {
726 .attr = {
727 .name = "scp_data",
728 .mode = S_IRUGO | S_IWUSR,
729 },
730 .size = PAGE_SIZE,
731 .read = reipl_fcp_scpdata_read,
732 .write = reipl_fcp_scpdata_write,
733};
734
629DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n", 735DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
630 reipl_block_fcp->ipl_info.fcp.wwpn); 736 reipl_block_fcp->ipl_info.fcp.wwpn);
631DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n", 737DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n",
@@ -647,7 +753,6 @@ static struct attribute *reipl_fcp_attrs[] = {
647}; 753};
648 754
649static struct attribute_group reipl_fcp_attr_group = { 755static struct attribute_group reipl_fcp_attr_group = {
650 .name = IPL_FCP_STR,
651 .attrs = reipl_fcp_attrs, 756 .attrs = reipl_fcp_attrs,
652}; 757};
653 758
@@ -895,6 +1000,7 @@ static struct kobj_attribute reipl_type_attr =
895 __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store); 1000 __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
896 1001
897static struct kset *reipl_kset; 1002static struct kset *reipl_kset;
1003static struct kset *reipl_fcp_kset;
898 1004
899static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb, 1005static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb,
900 const enum ipl_method m) 1006 const enum ipl_method m)
@@ -906,7 +1012,7 @@ static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb,
906 1012
907 reipl_get_ascii_loadparm(loadparm, ipb); 1013 reipl_get_ascii_loadparm(loadparm, ipb);
908 reipl_get_ascii_nss_name(nss_name, ipb); 1014 reipl_get_ascii_nss_name(nss_name, ipb);
909 reipl_get_ascii_vmparm(vmparm, ipb); 1015 reipl_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb);
910 1016
911 switch (m) { 1017 switch (m) {
912 case REIPL_METHOD_CCW_VM: 1018 case REIPL_METHOD_CCW_VM:
@@ -1076,23 +1182,44 @@ static int __init reipl_fcp_init(void)
1076 int rc; 1182 int rc;
1077 1183
1078 if (!diag308_set_works) { 1184 if (!diag308_set_works) {
1079 if (ipl_info.type == IPL_TYPE_FCP) 1185 if (ipl_info.type == IPL_TYPE_FCP) {
1080 make_attrs_ro(reipl_fcp_attrs); 1186 make_attrs_ro(reipl_fcp_attrs);
1081 else 1187 sys_reipl_fcp_scp_data_attr.attr.mode = S_IRUGO;
1188 } else
1082 return 0; 1189 return 0;
1083 } 1190 }
1084 1191
1085 reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); 1192 reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
1086 if (!reipl_block_fcp) 1193 if (!reipl_block_fcp)
1087 return -ENOMEM; 1194 return -ENOMEM;
1088 rc = sysfs_create_group(&reipl_kset->kobj, &reipl_fcp_attr_group); 1195
1196 /* sysfs: create fcp kset for mixing attr group and bin attrs */
1197 reipl_fcp_kset = kset_create_and_add(IPL_FCP_STR, NULL,
1198 &reipl_kset->kobj);
1199 if (!reipl_kset) {
1200 free_page((unsigned long) reipl_block_fcp);
1201 return -ENOMEM;
1202 }
1203
1204 rc = sysfs_create_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group);
1089 if (rc) { 1205 if (rc) {
1090 free_page((unsigned long)reipl_block_fcp); 1206 kset_unregister(reipl_fcp_kset);
1207 free_page((unsigned long) reipl_block_fcp);
1091 return rc; 1208 return rc;
1092 } 1209 }
1093 if (ipl_info.type == IPL_TYPE_FCP) { 1210
1211 rc = sysfs_create_bin_file(&reipl_fcp_kset->kobj,
1212 &sys_reipl_fcp_scp_data_attr);
1213 if (rc) {
1214 sysfs_remove_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group);
1215 kset_unregister(reipl_fcp_kset);
1216 free_page((unsigned long) reipl_block_fcp);
1217 return rc;
1218 }
1219
1220 if (ipl_info.type == IPL_TYPE_FCP)
1094 memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE); 1221 memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE);
1095 } else { 1222 else {
1096 reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN; 1223 reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
1097 reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION; 1224 reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
1098 reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN; 1225 reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN;