aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/ipl.c
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 /arch/s390/kernel/ipl.c
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>
Diffstat (limited to 'arch/s390/kernel/ipl.c')
-rw-r--r--arch/s390/kernel/ipl.c157
1 files changed, 142 insertions, 15 deletions
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;