aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorMichael Holzheu <holzheu@linux.vnet.ibm.com>2013-06-06 09:44:28 +0200
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-06-26 21:10:10 +0200
commit64150adf89df2ed165d6760f414fa6df07d22628 (patch)
treefaacbf1ffd1daf2aa370d2b4880b8b093ac2966f /drivers/s390
parents390/pci: sysfs remove strlen (diff)
downloadlinux-dev-64150adf89df2ed165d6760f414fa6df07d22628.tar.xz
linux-dev-64150adf89df2ed165d6760f414fa6df07d22628.zip
s390/cio: Introduce generic synchronous CHSC IOCTL
This patch adds a new ioctl CHSC_START_SYNC that allows to execute any synchronous CHSC that is provided by user space. Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/chsc.h5
-rw-r--r--drivers/s390/cio/chsc_sch.c37
2 files changed, 35 insertions, 7 deletions
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index e7ef2a683b8f..62d096f11e65 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -10,11 +10,6 @@
#define CHSC_SDA_OC_MSS 0x2
-struct chsc_header {
- u16 length;
- u16 code;
-} __attribute__ ((packed));
-
#define NR_MEASUREMENT_CHARS 5
struct cmg_chars {
u32 values[NR_MEASUREMENT_CHARS];
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index facdf809113f..190fc844d814 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -287,11 +287,11 @@ static int chsc_async(struct chsc_async_area *chsc_area,
return ret;
}
-static void chsc_log_command(struct chsc_async_area *chsc_area)
+static void chsc_log_command(void *chsc_area)
{
char dbf[10];
- sprintf(dbf, "CHSC:%x", chsc_area->header.code);
+ sprintf(dbf, "CHSC:%x", ((uint16_t *)chsc_area)[1]);
CHSC_LOG(0, dbf);
CHSC_LOG_HEX(0, chsc_area, 32);
}
@@ -362,6 +362,37 @@ out_free:
return ret;
}
+static int chsc_ioctl_start_sync(void __user *user_area)
+{
+ struct chsc_sync_area *chsc_area;
+ int ret, ccode;
+
+ chsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!chsc_area)
+ return -ENOMEM;
+ if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) {
+ ret = -EFAULT;
+ goto out_free;
+ }
+ if (chsc_area->header.code & 0x4000) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+ chsc_log_command(chsc_area);
+ ccode = chsc(chsc_area);
+ if (ccode != 0) {
+ ret = -EIO;
+ goto out_free;
+ }
+ if (copy_to_user(user_area, chsc_area, PAGE_SIZE))
+ ret = -EFAULT;
+ else
+ ret = 0;
+out_free:
+ free_page((unsigned long)chsc_area);
+ return ret;
+}
+
static int chsc_ioctl_info_channel_path(void __user *user_cd)
{
struct chsc_chp_cd *cd;
@@ -795,6 +826,8 @@ static long chsc_ioctl(struct file *filp, unsigned int cmd,
switch (cmd) {
case CHSC_START:
return chsc_ioctl_start(argp);
+ case CHSC_START_SYNC:
+ return chsc_ioctl_start_sync(argp);
case CHSC_INFO_CHANNEL_PATH:
return chsc_ioctl_info_channel_path(argp);
case CHSC_INFO_CU: