root/drivers/s390/char/sclp_ctl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sclp_ctl_cmdw_supported
  2. u64_to_uptr
  3. sclp_ctl_ioctl_sccb
  4. sclp_ctl_ioctl

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * IOCTL interface for SCLP
   4  *
   5  * Copyright IBM Corp. 2012
   6  *
   7  * Author: Michael Holzheu <holzheu@linux.vnet.ibm.com>
   8  */
   9 
  10 #include <linux/compat.h>
  11 #include <linux/uaccess.h>
  12 #include <linux/miscdevice.h>
  13 #include <linux/gfp.h>
  14 #include <linux/init.h>
  15 #include <linux/ioctl.h>
  16 #include <linux/fs.h>
  17 #include <asm/sclp_ctl.h>
  18 #include <asm/sclp.h>
  19 
  20 #include "sclp.h"
  21 
  22 /*
  23  * Supported command words
  24  */
  25 static unsigned int sclp_ctl_sccb_wlist[] = {
  26         0x00400002,
  27         0x00410002,
  28 };
  29 
  30 /*
  31  * Check if command word is supported
  32  */
  33 static int sclp_ctl_cmdw_supported(unsigned int cmdw)
  34 {
  35         int i;
  36 
  37         for (i = 0; i < ARRAY_SIZE(sclp_ctl_sccb_wlist); i++) {
  38                 if (cmdw == sclp_ctl_sccb_wlist[i])
  39                         return 1;
  40         }
  41         return 0;
  42 }
  43 
  44 static void __user *u64_to_uptr(u64 value)
  45 {
  46         if (is_compat_task())
  47                 return compat_ptr(value);
  48         else
  49                 return (void __user *)(unsigned long)value;
  50 }
  51 
  52 /*
  53  * Start SCLP request
  54  */
  55 static int sclp_ctl_ioctl_sccb(void __user *user_area)
  56 {
  57         struct sclp_ctl_sccb ctl_sccb;
  58         struct sccb_header *sccb;
  59         unsigned long copied;
  60         int rc;
  61 
  62         if (copy_from_user(&ctl_sccb, user_area, sizeof(ctl_sccb)))
  63                 return -EFAULT;
  64         if (!sclp_ctl_cmdw_supported(ctl_sccb.cmdw))
  65                 return -EOPNOTSUPP;
  66         sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
  67         if (!sccb)
  68                 return -ENOMEM;
  69         copied = PAGE_SIZE -
  70                 copy_from_user(sccb, u64_to_uptr(ctl_sccb.sccb), PAGE_SIZE);
  71         if (offsetof(struct sccb_header, length) +
  72             sizeof(sccb->length) > copied || sccb->length > copied) {
  73                 rc = -EFAULT;
  74                 goto out_free;
  75         }
  76         if (sccb->length < 8) {
  77                 rc = -EINVAL;
  78                 goto out_free;
  79         }
  80         rc = sclp_sync_request(ctl_sccb.cmdw, sccb);
  81         if (rc)
  82                 goto out_free;
  83         if (copy_to_user(u64_to_uptr(ctl_sccb.sccb), sccb, sccb->length))
  84                 rc = -EFAULT;
  85 out_free:
  86         free_page((unsigned long) sccb);
  87         return rc;
  88 }
  89 
  90 /*
  91  * SCLP SCCB ioctl function
  92  */
  93 static long sclp_ctl_ioctl(struct file *filp, unsigned int cmd,
  94                            unsigned long arg)
  95 {
  96         void __user *argp;
  97 
  98         if (is_compat_task())
  99                 argp = compat_ptr(arg);
 100         else
 101                 argp = (void __user *) arg;
 102         switch (cmd) {
 103         case SCLP_CTL_SCCB:
 104                 return sclp_ctl_ioctl_sccb(argp);
 105         default: /* unknown ioctl number */
 106                 return -ENOTTY;
 107         }
 108 }
 109 
 110 /*
 111  * File operations
 112  */
 113 static const struct file_operations sclp_ctl_fops = {
 114         .owner = THIS_MODULE,
 115         .open = nonseekable_open,
 116         .unlocked_ioctl = sclp_ctl_ioctl,
 117         .compat_ioctl = sclp_ctl_ioctl,
 118         .llseek = no_llseek,
 119 };
 120 
 121 /*
 122  * Misc device definition
 123  */
 124 static struct miscdevice sclp_ctl_device = {
 125         .minor = MISC_DYNAMIC_MINOR,
 126         .name = "sclp",
 127         .fops = &sclp_ctl_fops,
 128 };
 129 builtin_misc_device(sclp_ctl_device);

/* [<][>][^][v][top][bottom][index][help] */