diff options
Diffstat (limited to 'arch/s390/kernel/setup.c')
-rw-r--r-- | arch/s390/kernel/setup.c | 186 |
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) \ | ||
690 | static ssize_t ipl_##_name##_show(struct subsystem *subsys, \ | ||
691 | char *page) \ | ||
692 | { \ | ||
693 | return sprintf(page, _format, _value); \ | ||
694 | } \ | ||
695 | static struct subsys_attribute ipl_##_name##_attr = \ | ||
696 | __ATTR(_name, S_IRUGO, ipl_##_name##_show, NULL); | ||
697 | |||
698 | DEFINE_IPL_ATTR(wwpn, "0x%016llx\n", (unsigned long long) | ||
699 | IPL_PARMBLOCK_START->fcp.wwpn); | ||
700 | DEFINE_IPL_ATTR(lun, "0x%016llx\n", (unsigned long long) | ||
701 | IPL_PARMBLOCK_START->fcp.lun); | ||
702 | DEFINE_IPL_ATTR(bootprog, "%lld\n", (unsigned long long) | ||
703 | IPL_PARMBLOCK_START->fcp.bootprog); | ||
704 | DEFINE_IPL_ATTR(br_lba, "%lld\n", (unsigned long long) | ||
705 | IPL_PARMBLOCK_START->fcp.br_lba); | ||
706 | |||
707 | enum ipl_type_type { | ||
708 | ipl_type_unknown, | ||
709 | ipl_type_ccw, | ||
710 | ipl_type_fcp, | ||
711 | }; | ||
712 | |||
713 | static enum ipl_type_type | ||
714 | get_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 | |||
729 | static ssize_t | ||
730 | ipl_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 | |||
742 | static struct subsys_attribute ipl_type_attr = __ATTR_RO(ipl_type); | ||
743 | |||
744 | static ssize_t | ||
745 | ipl_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 | |||
759 | static struct subsys_attribute ipl_device_attr = | ||
760 | __ATTR(device, S_IRUGO, ipl_device_show, NULL); | ||
761 | |||
762 | static 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 | |||
772 | static struct attribute_group ipl_fcp_attr_group = { | ||
773 | .attrs = ipl_fcp_attrs, | ||
774 | }; | ||
775 | |||
776 | static struct attribute *ipl_ccw_attrs[] = { | ||
777 | &ipl_type_attr.attr, | ||
778 | &ipl_device_attr.attr, | ||
779 | NULL, | ||
780 | }; | ||
781 | |||
782 | static struct attribute_group ipl_ccw_attr_group = { | ||
783 | .attrs = ipl_ccw_attrs, | ||
784 | }; | ||
785 | |||
786 | static struct attribute *ipl_unknown_attrs[] = { | ||
787 | &ipl_type_attr.attr, | ||
788 | NULL, | ||
789 | }; | ||
790 | |||
791 | static struct attribute_group ipl_unknown_attr_group = { | ||
792 | .attrs = ipl_unknown_attrs, | ||
793 | }; | ||
794 | |||
795 | static ssize_t | ||
796 | ipl_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 | |||
809 | static 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 | |||
819 | static ssize_t | ||
820 | ipl_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 | |||
834 | static 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 | |||
844 | static decl_subsys(ipl, NULL, NULL); | ||
845 | |||
846 | static int __init | ||
847 | ipl_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); | ||