diff options
author | Michael Holzheu <holzheu@linux.vnet.ibm.com> | 2013-06-06 03:44:28 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-06-26 15:10:10 -0400 |
commit | 64150adf89df2ed165d6760f414fa6df07d22628 (patch) | |
tree | faacbf1ffd1daf2aa370d2b4880b8b093ac2966f | |
parent | 80b054ba2ab1c46e6c34c6a54f542d8f7ad77fca (diff) |
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>
-rw-r--r-- | arch/s390/include/uapi/asm/chsc.h | 11 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.h | 5 | ||||
-rw-r--r-- | drivers/s390/cio/chsc_sch.c | 37 |
3 files changed, 46 insertions, 7 deletions
diff --git a/arch/s390/include/uapi/asm/chsc.h b/arch/s390/include/uapi/asm/chsc.h index 1c6a7f85a581..6e5307fbeb1e 100644 --- a/arch/s390/include/uapi/asm/chsc.h +++ b/arch/s390/include/uapi/asm/chsc.h | |||
@@ -29,6 +29,16 @@ struct chsc_async_area { | |||
29 | __u8 data[CHSC_SIZE - sizeof(struct chsc_async_header)]; | 29 | __u8 data[CHSC_SIZE - sizeof(struct chsc_async_header)]; |
30 | } __attribute__ ((packed)); | 30 | } __attribute__ ((packed)); |
31 | 31 | ||
32 | struct chsc_header { | ||
33 | __u16 length; | ||
34 | __u16 code; | ||
35 | } __attribute__ ((packed)); | ||
36 | |||
37 | struct chsc_sync_area { | ||
38 | struct chsc_header header; | ||
39 | __u8 data[CHSC_SIZE - sizeof(struct chsc_header)]; | ||
40 | } __attribute__ ((packed)); | ||
41 | |||
32 | struct chsc_response_struct { | 42 | struct chsc_response_struct { |
33 | __u16 length; | 43 | __u16 length; |
34 | __u16 code; | 44 | __u16 code; |
@@ -126,5 +136,6 @@ struct chsc_cpd_info { | |||
126 | #define CHSC_INFO_CCL _IOWR(CHSC_IOCTL_MAGIC, 0x86, struct chsc_comp_list) | 136 | #define CHSC_INFO_CCL _IOWR(CHSC_IOCTL_MAGIC, 0x86, struct chsc_comp_list) |
127 | #define CHSC_INFO_CPD _IOWR(CHSC_IOCTL_MAGIC, 0x87, struct chsc_cpd_info) | 137 | #define CHSC_INFO_CPD _IOWR(CHSC_IOCTL_MAGIC, 0x87, struct chsc_cpd_info) |
128 | #define CHSC_INFO_DCAL _IOWR(CHSC_IOCTL_MAGIC, 0x88, struct chsc_dcal) | 138 | #define CHSC_INFO_DCAL _IOWR(CHSC_IOCTL_MAGIC, 0x88, struct chsc_dcal) |
139 | #define CHSC_START_SYNC _IOWR(CHSC_IOCTL_MAGIC, 0x89, struct chsc_sync_area) | ||
129 | 140 | ||
130 | #endif | 141 | #endif |
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 @@ | |||
10 | 10 | ||
11 | #define CHSC_SDA_OC_MSS 0x2 | 11 | #define CHSC_SDA_OC_MSS 0x2 |
12 | 12 | ||
13 | struct chsc_header { | ||
14 | u16 length; | ||
15 | u16 code; | ||
16 | } __attribute__ ((packed)); | ||
17 | |||
18 | #define NR_MEASUREMENT_CHARS 5 | 13 | #define NR_MEASUREMENT_CHARS 5 |
19 | struct cmg_chars { | 14 | struct cmg_chars { |
20 | u32 values[NR_MEASUREMENT_CHARS]; | 15 | 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, | |||
287 | return ret; | 287 | return ret; |
288 | } | 288 | } |
289 | 289 | ||
290 | static void chsc_log_command(struct chsc_async_area *chsc_area) | 290 | static void chsc_log_command(void *chsc_area) |
291 | { | 291 | { |
292 | char dbf[10]; | 292 | char dbf[10]; |
293 | 293 | ||
294 | sprintf(dbf, "CHSC:%x", chsc_area->header.code); | 294 | sprintf(dbf, "CHSC:%x", ((uint16_t *)chsc_area)[1]); |
295 | CHSC_LOG(0, dbf); | 295 | CHSC_LOG(0, dbf); |
296 | CHSC_LOG_HEX(0, chsc_area, 32); | 296 | CHSC_LOG_HEX(0, chsc_area, 32); |
297 | } | 297 | } |
@@ -362,6 +362,37 @@ out_free: | |||
362 | return ret; | 362 | return ret; |
363 | } | 363 | } |
364 | 364 | ||
365 | static int chsc_ioctl_start_sync(void __user *user_area) | ||
366 | { | ||
367 | struct chsc_sync_area *chsc_area; | ||
368 | int ret, ccode; | ||
369 | |||
370 | chsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | ||
371 | if (!chsc_area) | ||
372 | return -ENOMEM; | ||
373 | if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) { | ||
374 | ret = -EFAULT; | ||
375 | goto out_free; | ||
376 | } | ||
377 | if (chsc_area->header.code & 0x4000) { | ||
378 | ret = -EINVAL; | ||
379 | goto out_free; | ||
380 | } | ||
381 | chsc_log_command(chsc_area); | ||
382 | ccode = chsc(chsc_area); | ||
383 | if (ccode != 0) { | ||
384 | ret = -EIO; | ||
385 | goto out_free; | ||
386 | } | ||
387 | if (copy_to_user(user_area, chsc_area, PAGE_SIZE)) | ||
388 | ret = -EFAULT; | ||
389 | else | ||
390 | ret = 0; | ||
391 | out_free: | ||
392 | free_page((unsigned long)chsc_area); | ||
393 | return ret; | ||
394 | } | ||
395 | |||
365 | static int chsc_ioctl_info_channel_path(void __user *user_cd) | 396 | static int chsc_ioctl_info_channel_path(void __user *user_cd) |
366 | { | 397 | { |
367 | struct chsc_chp_cd *cd; | 398 | struct chsc_chp_cd *cd; |
@@ -795,6 +826,8 @@ static long chsc_ioctl(struct file *filp, unsigned int cmd, | |||
795 | switch (cmd) { | 826 | switch (cmd) { |
796 | case CHSC_START: | 827 | case CHSC_START: |
797 | return chsc_ioctl_start(argp); | 828 | return chsc_ioctl_start(argp); |
829 | case CHSC_START_SYNC: | ||
830 | return chsc_ioctl_start_sync(argp); | ||
798 | case CHSC_INFO_CHANNEL_PATH: | 831 | case CHSC_INFO_CHANNEL_PATH: |
799 | return chsc_ioctl_info_channel_path(argp); | 832 | return chsc_ioctl_info_channel_path(argp); |
800 | case CHSC_INFO_CU: | 833 | case CHSC_INFO_CU: |