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.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;