sclp_pci.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. * PCI I/O adapter configuration related functions.
  3. *
  4. * Copyright IBM Corp. 2016
  5. */
  6. #define KMSG_COMPONENT "sclp_cmd"
  7. #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  8. #include <linux/completion.h>
  9. #include <linux/export.h>
  10. #include <linux/mutex.h>
  11. #include <linux/errno.h>
  12. #include <linux/slab.h>
  13. #include <linux/init.h>
  14. #include <linux/err.h>
  15. #include <asm/sclp.h>
  16. #include "sclp.h"
  17. #define SCLP_CMDW_CONFIGURE_PCI 0x001a0001
  18. #define SCLP_CMDW_DECONFIGURE_PCI 0x001b0001
  19. #define SCLP_ATYPE_PCI 2
  20. #define SCLP_ERRNOTIFY_AQ_REPAIR 1
  21. #define SCLP_ERRNOTIFY_AQ_INFO_LOG 2
  22. static DEFINE_MUTEX(sclp_pci_mutex);
  23. static struct sclp_register sclp_pci_event = {
  24. .send_mask = EVTYP_ERRNOTIFY_MASK,
  25. };
  26. struct err_notify_evbuf {
  27. struct evbuf_header header;
  28. u8 action;
  29. u8 atype;
  30. u32 fh;
  31. u32 fid;
  32. u8 data[0];
  33. } __packed;
  34. struct err_notify_sccb {
  35. struct sccb_header header;
  36. struct err_notify_evbuf evbuf;
  37. } __packed;
  38. struct pci_cfg_sccb {
  39. struct sccb_header header;
  40. u8 atype; /* adapter type */
  41. u8 reserved1;
  42. u16 reserved2;
  43. u32 aid; /* adapter identifier */
  44. } __packed;
  45. static int do_pci_configure(sclp_cmdw_t cmd, u32 fid)
  46. {
  47. struct pci_cfg_sccb *sccb;
  48. int rc;
  49. if (!SCLP_HAS_PCI_RECONFIG)
  50. return -EOPNOTSUPP;
  51. sccb = (struct pci_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
  52. if (!sccb)
  53. return -ENOMEM;
  54. sccb->header.length = PAGE_SIZE;
  55. sccb->atype = SCLP_ATYPE_PCI;
  56. sccb->aid = fid;
  57. rc = sclp_sync_request(cmd, sccb);
  58. if (rc)
  59. goto out;
  60. switch (sccb->header.response_code) {
  61. case 0x0020:
  62. case 0x0120:
  63. break;
  64. default:
  65. pr_warn("configure PCI I/O adapter failed: cmd=0x%08x response=0x%04x\n",
  66. cmd, sccb->header.response_code);
  67. rc = -EIO;
  68. break;
  69. }
  70. out:
  71. free_page((unsigned long) sccb);
  72. return rc;
  73. }
  74. int sclp_pci_configure(u32 fid)
  75. {
  76. return do_pci_configure(SCLP_CMDW_CONFIGURE_PCI, fid);
  77. }
  78. EXPORT_SYMBOL(sclp_pci_configure);
  79. int sclp_pci_deconfigure(u32 fid)
  80. {
  81. return do_pci_configure(SCLP_CMDW_DECONFIGURE_PCI, fid);
  82. }
  83. EXPORT_SYMBOL(sclp_pci_deconfigure);
  84. static void sclp_pci_callback(struct sclp_req *req, void *data)
  85. {
  86. struct completion *completion = data;
  87. complete(completion);
  88. }
  89. static int sclp_pci_check_report(struct zpci_report_error_header *report)
  90. {
  91. if (report->version != 1)
  92. return -EINVAL;
  93. if (report->action != SCLP_ERRNOTIFY_AQ_REPAIR &&
  94. report->action != SCLP_ERRNOTIFY_AQ_INFO_LOG)
  95. return -EINVAL;
  96. if (report->length > (PAGE_SIZE - sizeof(struct err_notify_sccb)))
  97. return -EINVAL;
  98. return 0;
  99. }
  100. int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid)
  101. {
  102. DECLARE_COMPLETION_ONSTACK(completion);
  103. struct err_notify_sccb *sccb;
  104. struct sclp_req req;
  105. int ret;
  106. ret = sclp_pci_check_report(report);
  107. if (ret)
  108. return ret;
  109. mutex_lock(&sclp_pci_mutex);
  110. ret = sclp_register(&sclp_pci_event);
  111. if (ret)
  112. goto out_unlock;
  113. if (!(sclp_pci_event.sclp_receive_mask & EVTYP_ERRNOTIFY_MASK)) {
  114. ret = -EOPNOTSUPP;
  115. goto out_unregister;
  116. }
  117. sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
  118. if (!sccb) {
  119. ret = -ENOMEM;
  120. goto out_unregister;
  121. }
  122. memset(&req, 0, sizeof(req));
  123. req.callback_data = &completion;
  124. req.callback = sclp_pci_callback;
  125. req.command = SCLP_CMDW_WRITE_EVENT_DATA;
  126. req.status = SCLP_REQ_FILLED;
  127. req.sccb = sccb;
  128. sccb->evbuf.header.length = sizeof(sccb->evbuf) + report->length;
  129. sccb->evbuf.header.type = EVTYP_ERRNOTIFY;
  130. sccb->header.length = sizeof(sccb->header) + sccb->evbuf.header.length;
  131. sccb->evbuf.action = report->action;
  132. sccb->evbuf.atype = SCLP_ATYPE_PCI;
  133. sccb->evbuf.fh = fh;
  134. sccb->evbuf.fid = fid;
  135. memcpy(sccb->evbuf.data, report->data, report->length);
  136. ret = sclp_add_request(&req);
  137. if (ret)
  138. goto out_free_req;
  139. wait_for_completion(&completion);
  140. if (req.status != SCLP_REQ_DONE) {
  141. pr_warn("request failed (status=0x%02x)\n",
  142. req.status);
  143. ret = -EIO;
  144. goto out_free_req;
  145. }
  146. if (sccb->header.response_code != 0x0020) {
  147. pr_warn("request failed with response code 0x%x\n",
  148. sccb->header.response_code);
  149. ret = -EIO;
  150. }
  151. out_free_req:
  152. free_page((unsigned long) sccb);
  153. out_unregister:
  154. sclp_unregister(&sclp_pci_event);
  155. out_unlock:
  156. mutex_unlock(&sclp_pci_mutex);
  157. return ret;
  158. }