sclp_ctl.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. unsigned long copied;
  53. int rc;
  54. if (copy_from_user(&ctl_sccb, user_area, sizeof(ctl_sccb)))
  55. return -EFAULT;
  56. if (!sclp_ctl_cmdw_supported(ctl_sccb.cmdw))
  57. return -EOPNOTSUPP;
  58. sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
  59. if (!sccb)
  60. return -ENOMEM;
  61. copied = PAGE_SIZE -
  62. copy_from_user(sccb, u64_to_uptr(ctl_sccb.sccb), PAGE_SIZE);
  63. if (offsetof(struct sccb_header, length) +
  64. sizeof(sccb->length) > copied || sccb->length > copied) {
  65. rc = -EFAULT;
  66. goto out_free;
  67. }
  68. if (sccb->length < 8) {
  69. rc = -EINVAL;
  70. goto out_free;
  71. }
  72. rc = sclp_sync_request(ctl_sccb.cmdw, sccb);
  73. if (rc)
  74. goto out_free;
  75. if (copy_to_user(u64_to_uptr(ctl_sccb.sccb), sccb, sccb->length))
  76. rc = -EFAULT;
  77. out_free:
  78. free_page((unsigned long) sccb);
  79. return rc;
  80. }
  81. /*
  82. * SCLP SCCB ioctl function
  83. */
  84. static long sclp_ctl_ioctl(struct file *filp, unsigned int cmd,
  85. unsigned long arg)
  86. {
  87. void __user *argp;
  88. if (is_compat_task())
  89. argp = compat_ptr(arg);
  90. else
  91. argp = (void __user *) arg;
  92. switch (cmd) {
  93. case SCLP_CTL_SCCB:
  94. return sclp_ctl_ioctl_sccb(argp);
  95. default: /* unknown ioctl number */
  96. return -ENOTTY;
  97. }
  98. }
  99. /*
  100. * File operations
  101. */
  102. static const struct file_operations sclp_ctl_fops = {
  103. .owner = THIS_MODULE,
  104. .open = nonseekable_open,
  105. .unlocked_ioctl = sclp_ctl_ioctl,
  106. .compat_ioctl = sclp_ctl_ioctl,
  107. .llseek = no_llseek,
  108. };
  109. /*
  110. * Misc device definition
  111. */
  112. static struct miscdevice sclp_ctl_device = {
  113. .minor = MISC_DYNAMIC_MINOR,
  114. .name = "sclp",
  115. .fops = &sclp_ctl_fops,
  116. };
  117. /*
  118. * Register sclp_ctl misc device
  119. */
  120. static int __init sclp_ctl_init(void)
  121. {
  122. return misc_register(&sclp_ctl_device);
  123. }
  124. module_init(sclp_ctl_init);
  125. /*
  126. * Deregister sclp_ctl misc device
  127. */
  128. static void __exit sclp_ctl_exit(void)
  129. {
  130. misc_deregister(&sclp_ctl_device);
  131. }
  132. module_exit(sclp_ctl_exit);