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 { __u8 data[CHSC_SIZE - sizeof(struct chsc_async_header)]; } __attribute__ ((packed)); +struct chsc_header { + __u16 length; + __u16 code; +} __attribute__ ((packed)); + +struct chsc_sync_area { + struct chsc_header header; + __u8 data[CHSC_SIZE - sizeof(struct chsc_header)]; +} __attribute__ ((packed)); + struct chsc_response_struct { __u16 length; __u16 code; @@ -126,5 +136,6 @@ struct chsc_cpd_info { #define CHSC_INFO_CCL _IOWR(CHSC_IOCTL_MAGIC, 0x86, struct chsc_comp_list) #define CHSC_INFO_CPD _IOWR(CHSC_IOCTL_MAGIC, 0x87, struct chsc_cpd_info) #define CHSC_INFO_DCAL _IOWR(CHSC_IOCTL_MAGIC, 0x88, struct chsc_dcal) +#define CHSC_START_SYNC _IOWR(CHSC_IOCTL_MAGIC, 0x89, struct chsc_sync_area) #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 @@ #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: