aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorGerald Schaefer <gerald.schaefer@de.ibm.com>2009-06-16 04:30:51 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2009-06-16 04:31:22 -0400
commitc369527f18f8560bd3580be2676cb55b54b02ee6 (patch)
treed9e3b9c4ee8cfa493bdb8e9a3c863df11815a9ed /drivers/s390
parent2b1e3e5558b9de0f85ed9183a7adb2d61aab363b (diff)
[S390] pm: dcssblk power management callbacks.
Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dcssblk.c132
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 */
946static 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
972static 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;
998out_panic:
999 panic("fatal dcssblk resume error\n");
1000}
1001
1002static int dcssblk_thaw(struct device *dev)
1003{
1004 return 0;
1005}
1006
1007static struct dev_pm_ops dcssblk_pm_ops = {
1008 .freeze = dcssblk_freeze,
1009 .thaw = dcssblk_thaw,
1010 .restore = dcssblk_restore,
1011};
1012
1013static struct platform_driver dcssblk_pdrv = {
1014 .driver = {
1015 .name = "dcssblk",
1016 .owner = THIS_MODULE,
1017 .pm = &dcssblk_pm_ops,
1018 },
1019};
1020
1021static struct platform_device *dcssblk_pdev;
1022
1023
1024/*
943 * The init/exit functions. 1025 * The init/exit functions.
944 */ 1026 */
945static void __exit 1027static void __exit
946dcssblk_exit(void) 1028dcssblk_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
1072out_root:
1073 root_device_unregister(dcssblk_root_dev);
1074out_pdev:
1075 platform_device_unregister(dcssblk_pdev);
1076out_pdrv:
1077 platform_driver_unregister(&dcssblk_pdrv);
1078 return rc;
981} 1079}
982 1080
983module_init(dcssblk_init); 1081module_init(dcssblk_init);