sclp_async.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /*
  2. * Enable Asynchronous Notification via SCLP.
  3. *
  4. * Copyright IBM Corp. 2009
  5. * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
  6. *
  7. */
  8. #include <linux/init.h>
  9. #include <linux/module.h>
  10. #include <linux/device.h>
  11. #include <linux/stat.h>
  12. #include <linux/string.h>
  13. #include <linux/ctype.h>
  14. #include <linux/kmod.h>
  15. #include <linux/err.h>
  16. #include <linux/errno.h>
  17. #include <linux/proc_fs.h>
  18. #include <linux/sysctl.h>
  19. #include <linux/utsname.h>
  20. #include "sclp.h"
  21. static int callhome_enabled;
  22. static struct sclp_req *request;
  23. static struct sclp_async_sccb *sccb;
  24. static int sclp_async_send_wait(char *message);
  25. static struct ctl_table_header *callhome_sysctl_header;
  26. static DEFINE_SPINLOCK(sclp_async_lock);
  27. static char nodename[64];
  28. #define SCLP_NORMAL_WRITE 0x00
  29. struct async_evbuf {
  30. struct evbuf_header header;
  31. u64 reserved;
  32. u8 rflags;
  33. u8 empty;
  34. u8 rtype;
  35. u8 otype;
  36. char comp_id[12];
  37. char data[3000]; /* there is still some space left */
  38. } __attribute__((packed));
  39. struct sclp_async_sccb {
  40. struct sccb_header header;
  41. struct async_evbuf evbuf;
  42. } __attribute__((packed));
  43. static struct sclp_register sclp_async_register = {
  44. .send_mask = EVTYP_ASYNC_MASK,
  45. };
  46. static int call_home_on_panic(struct notifier_block *self,
  47. unsigned long event, void *data)
  48. {
  49. strncat(data, nodename, strlen(nodename));
  50. sclp_async_send_wait(data);
  51. return NOTIFY_DONE;
  52. }
  53. static struct notifier_block call_home_panic_nb = {
  54. .notifier_call = call_home_on_panic,
  55. .priority = INT_MAX,
  56. };
  57. static int proc_handler_callhome(ctl_table *ctl, int write, struct file *filp,
  58. void __user *buffer, size_t *count,
  59. loff_t *ppos)
  60. {
  61. unsigned long val;
  62. int len, rc;
  63. char buf[2];
  64. if (!*count | (*ppos && !write)) {
  65. *count = 0;
  66. return 0;
  67. }
  68. if (!write) {
  69. len = sprintf(buf, "%d\n", callhome_enabled);
  70. buf[len] = '\0';
  71. rc = copy_to_user(buffer, buf, sizeof(buf));
  72. if (rc != 0)
  73. return -EFAULT;
  74. } else {
  75. len = *count;
  76. rc = copy_from_user(buf, buffer, sizeof(buf));
  77. if (rc != 0)
  78. return -EFAULT;
  79. if (strict_strtoul(buf, 0, &val) != 0)
  80. return -EINVAL;
  81. if (val != 0 && val != 1)
  82. return -EINVAL;
  83. callhome_enabled = val;
  84. }
  85. *count = len;
  86. *ppos += len;
  87. return 0;
  88. }
  89. static struct ctl_table callhome_table[] = {
  90. {
  91. .procname = "callhome",
  92. .mode = 0644,
  93. .proc_handler = &proc_handler_callhome,
  94. },
  95. { .ctl_name = 0 }
  96. };
  97. static struct ctl_table kern_dir_table[] = {
  98. {
  99. .ctl_name = CTL_KERN,
  100. .procname = "kernel",
  101. .maxlen = 0,
  102. .mode = 0555,
  103. .child = callhome_table,
  104. },
  105. { .ctl_name = 0 }
  106. };
  107. /*
  108. * Function used to transfer asynchronous notification
  109. * records which waits for send completion
  110. */
  111. static int sclp_async_send_wait(char *message)
  112. {
  113. struct async_evbuf *evb;
  114. int rc;
  115. unsigned long flags;
  116. if (!callhome_enabled)
  117. return 0;
  118. sccb->evbuf.header.type = EVTYP_ASYNC;
  119. sccb->evbuf.rtype = 0xA5;
  120. sccb->evbuf.otype = 0x00;
  121. evb = &sccb->evbuf;
  122. request->command = SCLP_CMDW_WRITE_EVENT_DATA;
  123. request->sccb = sccb;
  124. request->status = SCLP_REQ_FILLED;
  125. strncpy(sccb->evbuf.data, message, sizeof(sccb->evbuf.data));
  126. /*
  127. * Retain Queue
  128. * e.g. 5639CC140 500 Red Hat RHEL5 Linux for zSeries (RHEL AS)
  129. */
  130. strncpy(sccb->evbuf.comp_id, "000000000", sizeof(sccb->evbuf.comp_id));
  131. sccb->evbuf.header.length = sizeof(sccb->evbuf);
  132. sccb->header.length = sizeof(sccb->evbuf) + sizeof(sccb->header);
  133. sccb->header.function_code = SCLP_NORMAL_WRITE;
  134. rc = sclp_add_request(request);
  135. if (rc)
  136. return rc;
  137. spin_lock_irqsave(&sclp_async_lock, flags);
  138. while (request->status != SCLP_REQ_DONE &&
  139. request->status != SCLP_REQ_FAILED) {
  140. sclp_sync_wait();
  141. }
  142. spin_unlock_irqrestore(&sclp_async_lock, flags);
  143. if (request->status != SCLP_REQ_DONE)
  144. return -EIO;
  145. rc = ((struct sclp_async_sccb *)
  146. request->sccb)->header.response_code;
  147. if (rc != 0x0020)
  148. return -EIO;
  149. if (evb->header.flags != 0x80)
  150. return -EIO;
  151. return rc;
  152. }
  153. static int __init sclp_async_init(void)
  154. {
  155. int rc;
  156. rc = sclp_register(&sclp_async_register);
  157. if (rc)
  158. return rc;
  159. callhome_sysctl_header = register_sysctl_table(kern_dir_table);
  160. if (!callhome_sysctl_header) {
  161. rc = -ENOMEM;
  162. goto out_sclp;
  163. }
  164. if (!(sclp_async_register.sclp_receive_mask & EVTYP_ASYNC_MASK)) {
  165. rc = -EOPNOTSUPP;
  166. goto out_sclp;
  167. }
  168. rc = -ENOMEM;
  169. request = kzalloc(sizeof(struct sclp_req), GFP_KERNEL);
  170. if (!request)
  171. goto out_sys;
  172. sccb = (struct sclp_async_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
  173. if (!sccb)
  174. goto out_mem;
  175. rc = atomic_notifier_chain_register(&panic_notifier_list,
  176. &call_home_panic_nb);
  177. if (rc)
  178. goto out_mem;
  179. strncpy(nodename, init_utsname()->nodename, 64);
  180. return 0;
  181. out_mem:
  182. kfree(request);
  183. free_page((unsigned long) sccb);
  184. out_sys:
  185. unregister_sysctl_table(callhome_sysctl_header);
  186. out_sclp:
  187. sclp_unregister(&sclp_async_register);
  188. return rc;
  189. }
  190. module_init(sclp_async_init);
  191. static void __exit sclp_async_exit(void)
  192. {
  193. atomic_notifier_chain_unregister(&panic_notifier_list,
  194. &call_home_panic_nb);
  195. unregister_sysctl_table(callhome_sysctl_header);
  196. sclp_unregister(&sclp_async_register);
  197. free_page((unsigned long) sccb);
  198. kfree(request);
  199. }
  200. module_exit(sclp_async_exit);
  201. MODULE_AUTHOR("Copyright IBM Corp. 2009");
  202. MODULE_AUTHOR("Hans-Joachim Picht <hans@linux.vnet.ibm.com>");
  203. MODULE_LICENSE("GPL");
  204. MODULE_DESCRIPTION("SCLP Asynchronous Notification Records");