Browse Source

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>
Michael Holzheu 12 years ago
parent
commit
64150adf89
3 changed files with 46 additions and 7 deletions
  1. 11 0
      arch/s390/include/uapi/asm/chsc.h
  2. 0 5
      drivers/s390/cio/chsc.h
  3. 35 2
      drivers/s390/cio/chsc_sch.c

+ 11 - 0
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

+ 0 - 5
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];

+ 35 - 2
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: