aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/setup.c')
-rw-r--r--arch/s390/kernel/setup.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 5204778b8e5e..31e7b19348b7 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -36,6 +36,7 @@
36#include <linux/console.h> 36#include <linux/console.h>
37#include <linux/seq_file.h> 37#include <linux/seq_file.h>
38#include <linux/kernel_stat.h> 38#include <linux/kernel_stat.h>
39#include <linux/device.h>
39 40
40#include <asm/uaccess.h> 41#include <asm/uaccess.h>
41#include <asm/system.h> 42#include <asm/system.h>
@@ -685,3 +686,188 @@ struct seq_operations cpuinfo_op = {
685 .show = show_cpuinfo, 686 .show = show_cpuinfo,
686}; 687};
687 688
689#define DEFINE_IPL_ATTR(_name, _format, _value) \
690static ssize_t ipl_##_name##_show(struct subsystem *subsys, \
691 char *page) \
692{ \
693 return sprintf(page, _format, _value); \
694} \
695static struct subsys_attribute ipl_##_name##_attr = \
696 __ATTR(_name, S_IRUGO, ipl_##_name##_show, NULL);
697
698DEFINE_IPL_ATTR(wwpn, "0x%016llx\n", (unsigned long long)
699 IPL_PARMBLOCK_START->fcp.wwpn);
700DEFINE_IPL_ATTR(lun, "0x%016llx\n", (unsigned long long)
701 IPL_PARMBLOCK_START->fcp.lun);
702DEFINE_IPL_ATTR(bootprog, "%lld\n", (unsigned long long)
703 IPL_PARMBLOCK_START->fcp.bootprog);
704DEFINE_IPL_ATTR(br_lba, "%lld\n", (unsigned long long)
705 IPL_PARMBLOCK_START->fcp.br_lba);
706
707enum ipl_type_type {
708 ipl_type_unknown,
709 ipl_type_ccw,
710 ipl_type_fcp,
711};
712
713static enum ipl_type_type
714get_ipl_type(void)
715{
716 struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
717
718 if (!IPL_DEVNO_VALID)
719 return ipl_type_unknown;
720 if (!IPL_PARMBLOCK_VALID)
721 return ipl_type_ccw;
722 if (ipl->hdr.header.version > IPL_MAX_SUPPORTED_VERSION)
723 return ipl_type_unknown;
724 if (ipl->fcp.pbt != IPL_TYPE_FCP)
725 return ipl_type_unknown;
726 return ipl_type_fcp;
727}
728
729static ssize_t
730ipl_type_show(struct subsystem *subsys, char *page)
731{
732 switch (get_ipl_type()) {
733 case ipl_type_ccw:
734 return sprintf(page, "ccw\n");
735 case ipl_type_fcp:
736 return sprintf(page, "fcp\n");
737 default:
738 return sprintf(page, "unknown\n");
739 }
740}
741
742static struct subsys_attribute ipl_type_attr = __ATTR_RO(ipl_type);
743
744static ssize_t
745ipl_device_show(struct subsystem *subsys, char *page)
746{
747 struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
748
749 switch (get_ipl_type()) {
750 case ipl_type_ccw:
751 return sprintf(page, "0.0.%04x\n", ipl_devno);
752 case ipl_type_fcp:
753 return sprintf(page, "0.0.%04x\n", ipl->fcp.devno);
754 default:
755 return 0;
756 }
757}
758
759static struct subsys_attribute ipl_device_attr =
760 __ATTR(device, S_IRUGO, ipl_device_show, NULL);
761
762static struct attribute *ipl_fcp_attrs[] = {
763 &ipl_type_attr.attr,
764 &ipl_device_attr.attr,
765 &ipl_wwpn_attr.attr,
766 &ipl_lun_attr.attr,
767 &ipl_bootprog_attr.attr,
768 &ipl_br_lba_attr.attr,
769 NULL,
770};
771
772static struct attribute_group ipl_fcp_attr_group = {
773 .attrs = ipl_fcp_attrs,
774};
775
776static struct attribute *ipl_ccw_attrs[] = {
777 &ipl_type_attr.attr,
778 &ipl_device_attr.attr,
779 NULL,
780};
781
782static struct attribute_group ipl_ccw_attr_group = {
783 .attrs = ipl_ccw_attrs,
784};
785
786static struct attribute *ipl_unknown_attrs[] = {
787 &ipl_type_attr.attr,
788 NULL,
789};
790
791static struct attribute_group ipl_unknown_attr_group = {
792 .attrs = ipl_unknown_attrs,
793};
794
795static ssize_t
796ipl_parameter_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
797{
798 unsigned int size = IPL_PARMBLOCK_SIZE;
799
800 if (off > size)
801 return 0;
802 if (off + count > size)
803 count = size - off;
804
805 memcpy(buf, (void *) IPL_PARMBLOCK_START + off, count);
806 return count;
807}
808
809static struct bin_attribute ipl_parameter_attr = {
810 .attr = {
811 .name = "binary_parameter",
812 .mode = S_IRUGO,
813 .owner = THIS_MODULE,
814 },
815 .size = PAGE_SIZE,
816 .read = &ipl_parameter_read,
817};
818
819static ssize_t
820ipl_scp_data_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
821{
822 unsigned int size = IPL_PARMBLOCK_START->fcp.scp_data_len;
823 void *scp_data = &IPL_PARMBLOCK_START->fcp.scp_data;
824
825 if (off > size)
826 return 0;
827 if (off + count > size)
828 count = size - off;
829
830 memcpy(buf, scp_data + off, count);
831 return count;
832}
833
834static struct bin_attribute ipl_scp_data_attr = {
835 .attr = {
836 .name = "scp_data",
837 .mode = S_IRUGO,
838 .owner = THIS_MODULE,
839 },
840 .size = PAGE_SIZE,
841 .read = &ipl_scp_data_read,
842};
843
844static decl_subsys(ipl, NULL, NULL);
845
846static int __init
847ipl_device_sysfs_register(void) {
848 int rc;
849
850 rc = firmware_register(&ipl_subsys);
851 if (rc)
852 return rc;
853
854 switch (get_ipl_type()) {
855 case ipl_type_ccw:
856 sysfs_create_group(&ipl_subsys.kset.kobj, &ipl_ccw_attr_group);
857 break;
858 case ipl_type_fcp:
859 sysfs_create_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group);
860 sysfs_create_bin_file(&ipl_subsys.kset.kobj,
861 &ipl_parameter_attr);
862 sysfs_create_bin_file(&ipl_subsys.kset.kobj,
863 &ipl_scp_data_attr);
864 break;
865 default:
866 sysfs_create_group(&ipl_subsys.kset.kobj,
867 &ipl_unknown_attr_group);
868 break;
869 }
870 return 0;
871}
872
873__initcall(ipl_device_sysfs_register);