diff options
| -rw-r--r-- | drivers/s390/block/dcssblk.c | 132 |
1 files changed, 115 insertions, 17 deletions
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index b21caf177e37..016f9e9d2591 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c | |||
| @@ -14,10 +14,11 @@ | |||
| 14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
| 16 | #include <linux/blkdev.h> | 16 | #include <linux/blkdev.h> |
| 17 | #include <asm/extmem.h> | ||
| 18 | #include <asm/io.h> | ||
| 19 | #include <linux/completion.h> | 17 | #include <linux/completion.h> |
| 20 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
| 19 | #include <linux/platform_device.h> | ||
| 20 | #include <asm/extmem.h> | ||
| 21 | #include <asm/io.h> | ||
| 21 | 22 | ||
| 22 | #define DCSSBLK_NAME "dcssblk" | 23 | #define DCSSBLK_NAME "dcssblk" |
| 23 | #define DCSSBLK_MINORS_PER_DISK 1 | 24 | #define DCSSBLK_MINORS_PER_DISK 1 |
| @@ -940,11 +941,94 @@ dcssblk_check_params(void) | |||
| 940 | } | 941 | } |
| 941 | 942 | ||
| 942 | /* | 943 | /* |
| 944 | * Suspend / Resume | ||
| 945 | */ | ||
| 946 | static int dcssblk_freeze(struct device *dev) | ||
| 947 | { | ||
| 948 | struct dcssblk_dev_info *dev_info; | ||
| 949 | int rc = 0; | ||
| 950 | |||
| 951 | list_for_each_entry(dev_info, &dcssblk_devices, lh) { | ||
| 952 | switch (dev_info->segment_type) { | ||
| 953 | case SEG_TYPE_SR: | ||
| 954 | case SEG_TYPE_ER: | ||
| 955 | case SEG_TYPE_SC: | ||
| 956 | if (!dev_info->is_shared) | ||
| 957 | rc = -EINVAL; | ||
| 958 | break; | ||
| 959 | default: | ||
| 960 | rc = -EINVAL; | ||
| 961 | break; | ||
| 962 | } | ||
| 963 | if (rc) | ||
| 964 | break; | ||
| 965 | } | ||
| 966 | if (rc) | ||
| 967 | pr_err("Suspend failed because device %s is writeable.\n", | ||
| 968 | dev_info->segment_name); | ||
| 969 | return rc; | ||
| 970 | } | ||
| 971 | |||
| 972 | static int dcssblk_restore(struct device *dev) | ||
| 973 | { | ||
| 974 | struct dcssblk_dev_info *dev_info; | ||
| 975 | struct segment_info *entry; | ||
| 976 | unsigned long start, end; | ||
| 977 | int rc = 0; | ||
| 978 | |||
| 979 | list_for_each_entry(dev_info, &dcssblk_devices, lh) { | ||
| 980 | list_for_each_entry(entry, &dev_info->seg_list, lh) { | ||
| 981 | segment_unload(entry->segment_name); | ||
| 982 | rc = segment_load(entry->segment_name, SEGMENT_SHARED, | ||
| 983 | &start, &end); | ||
| 984 | if (rc < 0) { | ||
| 985 | // TODO in_use check ? | ||
| 986 | segment_warning(rc, entry->segment_name); | ||
| 987 | goto out_panic; | ||
| 988 | } | ||
| 989 | if (start != entry->start || end != entry->end) { | ||
| 990 | pr_err("Mismatch of start / end address after " | ||
| 991 | "resuming device %s\n", | ||
| 992 | entry->segment_name); | ||
| 993 | goto out_panic; | ||
| 994 | } | ||
| 995 | } | ||
| 996 | } | ||
| 997 | return 0; | ||
| 998 | out_panic: | ||
| 999 | panic("fatal dcssblk resume error\n"); | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | static int dcssblk_thaw(struct device *dev) | ||
| 1003 | { | ||
| 1004 | return 0; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | static struct dev_pm_ops dcssblk_pm_ops = { | ||
| 1008 | .freeze = dcssblk_freeze, | ||
| 1009 | .thaw = dcssblk_thaw, | ||
| 1010 | .restore = dcssblk_restore, | ||
| 1011 | }; | ||
| 1012 | |||
| 1013 | static struct platform_driver dcssblk_pdrv = { | ||
| 1014 | .driver = { | ||
| 1015 | .name = "dcssblk", | ||
| 1016 | .owner = THIS_MODULE, | ||
| 1017 | .pm = &dcssblk_pm_ops, | ||
| 1018 | }, | ||
| 1019 | }; | ||
| 1020 | |||
| 1021 | static struct platform_device *dcssblk_pdev; | ||
| 1022 | |||
| 1023 | |||
| 1024 | /* | ||
| 943 | * The init/exit functions. | 1025 | * The init/exit functions. |
| 944 | */ | 1026 | */ |
| 945 | static void __exit | 1027 | static void __exit |
| 946 | dcssblk_exit(void) | 1028 | dcssblk_exit(void) |
| 947 | { | 1029 | { |
| 1030 | platform_device_unregister(dcssblk_pdev); | ||
| 1031 | platform_driver_unregister(&dcssblk_pdrv); | ||
| 948 | root_device_unregister(dcssblk_root_dev); | 1032 | root_device_unregister(dcssblk_root_dev); |
| 949 | unregister_blkdev(dcssblk_major, DCSSBLK_NAME); | 1033 | unregister_blkdev(dcssblk_major, DCSSBLK_NAME); |
| 950 | } | 1034 | } |
| @@ -954,30 +1038,44 @@ dcssblk_init(void) | |||
| 954 | { | 1038 | { |
| 955 | int rc; | 1039 | int rc; |
| 956 | 1040 | ||
| 957 | dcssblk_root_dev = root_device_register("dcssblk"); | 1041 | rc = platform_driver_register(&dcssblk_pdrv); |
| 958 | if (IS_ERR(dcssblk_root_dev)) | 1042 | if (rc) |
| 959 | return PTR_ERR(dcssblk_root_dev); | ||
| 960 | rc = device_create_file(dcssblk_root_dev, &dev_attr_add); | ||
| 961 | if (rc) { | ||
| 962 | root_device_unregister(dcssblk_root_dev); | ||
| 963 | return rc; | 1043 | return rc; |
| 1044 | |||
| 1045 | dcssblk_pdev = platform_device_register_simple("dcssblk", -1, NULL, | ||
| 1046 | 0); | ||
| 1047 | if (IS_ERR(dcssblk_pdev)) { | ||
| 1048 | rc = PTR_ERR(dcssblk_pdev); | ||
| 1049 | goto out_pdrv; | ||
| 964 | } | 1050 | } |
| 965 | rc = device_create_file(dcssblk_root_dev, &dev_attr_remove); | 1051 | |
| 966 | if (rc) { | 1052 | dcssblk_root_dev = root_device_register("dcssblk"); |
| 967 | root_device_unregister(dcssblk_root_dev); | 1053 | if (IS_ERR(dcssblk_root_dev)) { |
| 968 | return rc; | 1054 | rc = PTR_ERR(dcssblk_root_dev); |
| 1055 | goto out_pdev; | ||
| 969 | } | 1056 | } |
| 1057 | rc = device_create_file(dcssblk_root_dev, &dev_attr_add); | ||
| 1058 | if (rc) | ||
| 1059 | goto out_root; | ||
| 1060 | rc = device_create_file(dcssblk_root_dev, &dev_attr_remove); | ||
| 1061 | if (rc) | ||
| 1062 | goto out_root; | ||
| 970 | rc = register_blkdev(0, DCSSBLK_NAME); | 1063 | rc = register_blkdev(0, DCSSBLK_NAME); |
| 971 | if (rc < 0) { | 1064 | if (rc < 0) |
| 972 | root_device_unregister(dcssblk_root_dev); | 1065 | goto out_root; |
| 973 | return rc; | ||
| 974 | } | ||
| 975 | dcssblk_major = rc; | 1066 | dcssblk_major = rc; |
| 976 | init_rwsem(&dcssblk_devices_sem); | 1067 | init_rwsem(&dcssblk_devices_sem); |
| 977 | 1068 | ||
| 978 | dcssblk_check_params(); | 1069 | dcssblk_check_params(); |
| 979 | |||
| 980 | return 0; | 1070 | return 0; |
| 1071 | |||
| 1072 | out_root: | ||
| 1073 | root_device_unregister(dcssblk_root_dev); | ||
| 1074 | out_pdev: | ||
| 1075 | platform_device_unregister(dcssblk_pdev); | ||
| 1076 | out_pdrv: | ||
| 1077 | platform_driver_unregister(&dcssblk_pdrv); | ||
| 1078 | return rc; | ||
| 981 | } | 1079 | } |
| 982 | 1080 | ||
| 983 | module_init(dcssblk_init); | 1081 | module_init(dcssblk_init); |
