aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/char/vmcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/char/vmcp.c')
-rw-r--r--drivers/s390/char/vmcp.c89
1 files changed, 51 insertions, 38 deletions
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
index 82e6a6b253eb..2f419b0ea628 100644
--- a/drivers/s390/char/vmcp.c
+++ b/drivers/s390/char/vmcp.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Copyright (C) 2004,2005 IBM Corporation 2 * Copyright IBM Corp. 2004,2007
3 * Interface implementation for communication with the z/VM control program 3 * Interface implementation for communication with the z/VM control program
4 * Author(s): Christian Borntraeger <cborntra@de.ibm.com> 4 * Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
5 * 5 *
6 * 6 *
7 * z/VMs CP offers the possibility to issue commands via the diagnose code 8 7 * z/VMs CP offers the possibility to issue commands via the diagnose code 8
@@ -22,9 +22,11 @@
22#include "vmcp.h" 22#include "vmcp.h"
23 23
24MODULE_LICENSE("GPL"); 24MODULE_LICENSE("GPL");
25MODULE_AUTHOR("Christian Borntraeger <cborntra@de.ibm.com>"); 25MODULE_AUTHOR("Christian Borntraeger <borntraeger@de.ibm.com>");
26MODULE_DESCRIPTION("z/VM CP interface"); 26MODULE_DESCRIPTION("z/VM CP interface");
27 27
28#define PRINTK_HEADER "vmcp: "
29
28static debug_info_t *vmcp_debug; 30static debug_info_t *vmcp_debug;
29 31
30static int vmcp_open(struct inode *inode, struct file *file) 32static int vmcp_open(struct inode *inode, struct file *file)
@@ -40,7 +42,7 @@ static int vmcp_open(struct inode *inode, struct file *file)
40 session->bufsize = PAGE_SIZE; 42 session->bufsize = PAGE_SIZE;
41 session->response = NULL; 43 session->response = NULL;
42 session->resp_size = 0; 44 session->resp_size = 0;
43 init_MUTEX(&session->mutex); 45 mutex_init(&session->mutex);
44 file->private_data = session; 46 file->private_data = session;
45 return nonseekable_open(inode, file); 47 return nonseekable_open(inode, file);
46} 48}
@@ -57,37 +59,37 @@ static int vmcp_release(struct inode *inode, struct file *file)
57} 59}
58 60
59static ssize_t 61static ssize_t
60vmcp_read(struct file *file, char __user * buff, size_t count, loff_t * ppos) 62vmcp_read(struct file *file, char __user *buff, size_t count, loff_t *ppos)
61{ 63{
62 size_t tocopy; 64 size_t tocopy;
63 struct vmcp_session *session; 65 struct vmcp_session *session;
64 66
65 session = (struct vmcp_session *)file->private_data; 67 session = (struct vmcp_session *)file->private_data;
66 if (down_interruptible(&session->mutex)) 68 if (mutex_lock_interruptible(&session->mutex))
67 return -ERESTARTSYS; 69 return -ERESTARTSYS;
68 if (!session->response) { 70 if (!session->response) {
69 up(&session->mutex); 71 mutex_unlock(&session->mutex);
70 return 0; 72 return 0;
71 } 73 }
72 if (*ppos > session->resp_size) { 74 if (*ppos > session->resp_size) {
73 up(&session->mutex); 75 mutex_unlock(&session->mutex);
74 return 0; 76 return 0;
75 } 77 }
76 tocopy = min(session->resp_size - (size_t) (*ppos), count); 78 tocopy = min(session->resp_size - (size_t) (*ppos), count);
77 tocopy = min(tocopy,session->bufsize - (size_t) (*ppos)); 79 tocopy = min(tocopy, session->bufsize - (size_t) (*ppos));
78 80
79 if (copy_to_user(buff, session->response + (*ppos), tocopy)) { 81 if (copy_to_user(buff, session->response + (*ppos), tocopy)) {
80 up(&session->mutex); 82 mutex_unlock(&session->mutex);
81 return -EFAULT; 83 return -EFAULT;
82 } 84 }
83 up(&session->mutex); 85 mutex_unlock(&session->mutex);
84 *ppos += tocopy; 86 *ppos += tocopy;
85 return tocopy; 87 return tocopy;
86} 88}
87 89
88static ssize_t 90static ssize_t
89vmcp_write(struct file *file, const char __user * buff, size_t count, 91vmcp_write(struct file *file, const char __user *buff, size_t count,
90 loff_t * ppos) 92 loff_t *ppos)
91{ 93{
92 char *cmd; 94 char *cmd;
93 struct vmcp_session *session; 95 struct vmcp_session *session;
@@ -103,24 +105,23 @@ vmcp_write(struct file *file, const char __user * buff, size_t count,
103 } 105 }
104 cmd[count] = '\0'; 106 cmd[count] = '\0';
105 session = (struct vmcp_session *)file->private_data; 107 session = (struct vmcp_session *)file->private_data;
106 if (down_interruptible(&session->mutex)) { 108 if (mutex_lock_interruptible(&session->mutex)) {
107 kfree(cmd); 109 kfree(cmd);
108 return -ERESTARTSYS; 110 return -ERESTARTSYS;
109 } 111 }
110 if (!session->response) 112 if (!session->response)
111 session->response = (char *)__get_free_pages(GFP_KERNEL 113 session->response = (char *)__get_free_pages(GFP_KERNEL
112 | __GFP_REPEAT | GFP_DMA, 114 | __GFP_REPEAT | GFP_DMA,
113 get_order(session->bufsize)); 115 get_order(session->bufsize));
114 if (!session->response) { 116 if (!session->response) {
115 up(&session->mutex); 117 mutex_unlock(&session->mutex);
116 kfree(cmd); 118 kfree(cmd);
117 return -ENOMEM; 119 return -ENOMEM;
118 } 120 }
119 debug_text_event(vmcp_debug, 1, cmd); 121 debug_text_event(vmcp_debug, 1, cmd);
120 session->resp_size = cpcmd(cmd, session->response, 122 session->resp_size = cpcmd(cmd, session->response, session->bufsize,
121 session->bufsize, 123 &session->resp_code);
122 &session->resp_code); 124 mutex_unlock(&session->mutex);
123 up(&session->mutex);
124 kfree(cmd); 125 kfree(cmd);
125 *ppos = 0; /* reset the file pointer after a command */ 126 *ppos = 0; /* reset the file pointer after a command */
126 return count; 127 return count;
@@ -145,12 +146,12 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
145 int temp; 146 int temp;
146 147
147 session = (struct vmcp_session *)file->private_data; 148 session = (struct vmcp_session *)file->private_data;
148 if (down_interruptible(&session->mutex)) 149 if (mutex_lock_interruptible(&session->mutex))
149 return -ERESTARTSYS; 150 return -ERESTARTSYS;
150 switch (cmd) { 151 switch (cmd) {
151 case VMCP_GETCODE: 152 case VMCP_GETCODE:
152 temp = session->resp_code; 153 temp = session->resp_code;
153 up(&session->mutex); 154 mutex_unlock(&session->mutex);
154 return put_user(temp, (int __user *)arg); 155 return put_user(temp, (int __user *)arg);
155 case VMCP_SETBUF: 156 case VMCP_SETBUF:
156 free_pages((unsigned long)session->response, 157 free_pages((unsigned long)session->response,
@@ -161,14 +162,14 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
161 session->bufsize = PAGE_SIZE; 162 session->bufsize = PAGE_SIZE;
162 temp = -EINVAL; 163 temp = -EINVAL;
163 } 164 }
164 up(&session->mutex); 165 mutex_unlock(&session->mutex);
165 return temp; 166 return temp;
166 case VMCP_GETSIZE: 167 case VMCP_GETSIZE:
167 temp = session->resp_size; 168 temp = session->resp_size;
168 up(&session->mutex); 169 mutex_unlock(&session->mutex);
169 return put_user(temp, (int __user *)arg); 170 return put_user(temp, (int __user *)arg);
170 default: 171 default:
171 up(&session->mutex); 172 mutex_unlock(&session->mutex);
172 return -ENOIOCTLCMD; 173 return -ENOIOCTLCMD;
173 } 174 }
174} 175}
@@ -180,7 +181,7 @@ static const struct file_operations vmcp_fops = {
180 .read = vmcp_read, 181 .read = vmcp_read,
181 .write = vmcp_write, 182 .write = vmcp_write,
182 .unlocked_ioctl = vmcp_ioctl, 183 .unlocked_ioctl = vmcp_ioctl,
183 .compat_ioctl = vmcp_ioctl 184 .compat_ioctl = vmcp_ioctl,
184}; 185};
185 186
186static struct miscdevice vmcp_dev = { 187static struct miscdevice vmcp_dev = {
@@ -194,26 +195,38 @@ static int __init vmcp_init(void)
194 int ret; 195 int ret;
195 196
196 if (!MACHINE_IS_VM) { 197 if (!MACHINE_IS_VM) {
197 printk(KERN_WARNING 198 PRINT_WARN("z/VM CP interface is only available under z/VM\n");
198 "z/VM CP interface is only available under z/VM\n");
199 return -ENODEV; 199 return -ENODEV;
200 } 200 }
201 ret = misc_register(&vmcp_dev);
202 if (!ret)
203 printk(KERN_INFO "z/VM CP interface loaded\n");
204 else
205 printk(KERN_WARNING
206 "z/VM CP interface not loaded. Could not register misc device.\n");
207 vmcp_debug = debug_register("vmcp", 1, 1, 240); 201 vmcp_debug = debug_register("vmcp", 1, 1, 240);
208 debug_register_view(vmcp_debug, &debug_hex_ascii_view); 202 if (!vmcp_debug) {
209 return ret; 203 PRINT_ERR("z/VM CP interface not loaded. Could not register "
204 "debug feature\n");
205 return -ENOMEM;
206 }
207 ret = debug_register_view(vmcp_debug, &debug_hex_ascii_view);
208 if (ret) {
209 PRINT_ERR("z/VM CP interface not loaded. Could not register "
210 "debug feature view. Error code: %d\n", ret);
211 debug_unregister(vmcp_debug);
212 return ret;
213 }
214 ret = misc_register(&vmcp_dev);
215 if (ret) {
216 PRINT_ERR("z/VM CP interface not loaded. Could not register "
217 "misc device. Error code: %d\n", ret);
218 debug_unregister(vmcp_debug);
219 return ret;
220 }
221 PRINT_INFO("z/VM CP interface loaded\n");
222 return 0;
210} 223}
211 224
212static void __exit vmcp_exit(void) 225static void __exit vmcp_exit(void)
213{ 226{
214 WARN_ON(misc_deregister(&vmcp_dev) != 0); 227 misc_deregister(&vmcp_dev);
215 debug_unregister(vmcp_debug); 228 debug_unregister(vmcp_debug);
216 printk(KERN_INFO "z/VM CP interface unloaded.\n"); 229 PRINT_INFO("z/VM CP interface unloaded.\n");
217} 230}
218 231
219module_init(vmcp_init); 232module_init(vmcp_init);