sclp_ctl.c 2.8 KB

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