sclp_async.c 4.6 KB

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