sclp_ftp.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * SCLP Event Type (ET) 7 - Diagnostic Test FTP Services, useable on LPAR
  4. *
  5. * Copyright IBM Corp. 2013
  6. * Author(s): Ralf Hoppe ([email protected])
  7. *
  8. */
  9. #define KMSG_COMPONENT "hmcdrv"
  10. #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  11. #include <linux/kernel.h>
  12. #include <linux/mm.h>
  13. #include <linux/slab.h>
  14. #include <linux/io.h>
  15. #include <linux/wait.h>
  16. #include <linux/string.h>
  17. #include <linux/jiffies.h>
  18. #include <asm/sysinfo.h>
  19. #include <asm/ebcdic.h>
  20. #include "sclp.h"
  21. #include "sclp_diag.h"
  22. #include "sclp_ftp.h"
  23. static DECLARE_COMPLETION(sclp_ftp_rx_complete);
  24. static u8 sclp_ftp_ldflg;
  25. static u64 sclp_ftp_fsize;
  26. static u64 sclp_ftp_length;
  27. /**
  28. * sclp_ftp_txcb() - Diagnostic Test FTP services SCLP command callback
  29. * @req: sclp request
  30. * @data: pointer to struct completion
  31. */
  32. static void sclp_ftp_txcb(struct sclp_req *req, void *data)
  33. {
  34. struct completion *completion = data;
  35. #ifdef DEBUG
  36. pr_debug("SCLP (ET7) TX-IRQ, SCCB @ 0x%p: %*phN\n",
  37. req->sccb, 24, req->sccb);
  38. #endif
  39. complete(completion);
  40. }
  41. /**
  42. * sclp_ftp_rxcb() - Diagnostic Test FTP services receiver event callback
  43. * @evbuf: pointer to Diagnostic Test (ET7) event buffer
  44. */
  45. static void sclp_ftp_rxcb(struct evbuf_header *evbuf)
  46. {
  47. struct sclp_diag_evbuf *diag = (struct sclp_diag_evbuf *) evbuf;
  48. /*
  49. * Check for Diagnostic Test FTP Service
  50. */
  51. if (evbuf->type != EVTYP_DIAG_TEST ||
  52. diag->route != SCLP_DIAG_FTP_ROUTE ||
  53. diag->mdd.ftp.pcx != SCLP_DIAG_FTP_XPCX ||
  54. evbuf->length < SCLP_DIAG_FTP_EVBUF_LEN)
  55. return;
  56. #ifdef DEBUG
  57. pr_debug("SCLP (ET7) RX-IRQ, Event @ 0x%p: %*phN\n",
  58. evbuf, 24, evbuf);
  59. #endif
  60. /*
  61. * Because the event buffer is located in a page which is owned
  62. * by the SCLP core, all data of interest must be copied. The
  63. * error indication is in 'sclp_ftp_ldflg'
  64. */
  65. sclp_ftp_ldflg = diag->mdd.ftp.ldflg;
  66. sclp_ftp_fsize = diag->mdd.ftp.fsize;
  67. sclp_ftp_length = diag->mdd.ftp.length;
  68. complete(&sclp_ftp_rx_complete);
  69. }
  70. /**
  71. * sclp_ftp_et7() - start a Diagnostic Test FTP Service SCLP request
  72. * @ftp: pointer to FTP descriptor
  73. *
  74. * Return: 0 on success, else a (negative) error code
  75. */
  76. static int sclp_ftp_et7(const struct hmcdrv_ftp_cmdspec *ftp)
  77. {
  78. struct completion completion;
  79. struct sclp_diag_sccb *sccb;
  80. struct sclp_req *req;
  81. size_t len;
  82. int rc;
  83. req = kzalloc(sizeof(*req), GFP_KERNEL);
  84. sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
  85. if (!req || !sccb) {
  86. rc = -ENOMEM;
  87. goto out_free;
  88. }
  89. sccb->hdr.length = SCLP_DIAG_FTP_EVBUF_LEN +
  90. sizeof(struct sccb_header);
  91. sccb->evbuf.hdr.type = EVTYP_DIAG_TEST;
  92. sccb->evbuf.hdr.length = SCLP_DIAG_FTP_EVBUF_LEN;
  93. sccb->evbuf.hdr.flags = 0; /* clear processed-buffer */
  94. sccb->evbuf.route = SCLP_DIAG_FTP_ROUTE;
  95. sccb->evbuf.mdd.ftp.pcx = SCLP_DIAG_FTP_XPCX;
  96. sccb->evbuf.mdd.ftp.srcflg = 0;
  97. sccb->evbuf.mdd.ftp.pgsize = 0;
  98. sccb->evbuf.mdd.ftp.asce = _ASCE_REAL_SPACE;
  99. sccb->evbuf.mdd.ftp.ldflg = SCLP_DIAG_FTP_LDFAIL;
  100. sccb->evbuf.mdd.ftp.fsize = 0;
  101. sccb->evbuf.mdd.ftp.cmd = ftp->id;
  102. sccb->evbuf.mdd.ftp.offset = ftp->ofs;
  103. sccb->evbuf.mdd.ftp.length = ftp->len;
  104. sccb->evbuf.mdd.ftp.bufaddr = virt_to_phys(ftp->buf);
  105. len = strlcpy(sccb->evbuf.mdd.ftp.fident, ftp->fname,
  106. HMCDRV_FTP_FIDENT_MAX);
  107. if (len >= HMCDRV_FTP_FIDENT_MAX) {
  108. rc = -EINVAL;
  109. goto out_free;
  110. }
  111. req->command = SCLP_CMDW_WRITE_EVENT_DATA;
  112. req->sccb = sccb;
  113. req->status = SCLP_REQ_FILLED;
  114. req->callback = sclp_ftp_txcb;
  115. req->callback_data = &completion;
  116. init_completion(&completion);
  117. rc = sclp_add_request(req);
  118. if (rc)
  119. goto out_free;
  120. /* Wait for end of ftp sclp command. */
  121. wait_for_completion(&completion);
  122. #ifdef DEBUG
  123. pr_debug("status of SCLP (ET7) request is 0x%04x (0x%02x)\n",
  124. sccb->hdr.response_code, sccb->evbuf.hdr.flags);
  125. #endif
  126. /*
  127. * Check if sclp accepted the request. The data transfer runs
  128. * asynchronously and the completion is indicated with an
  129. * sclp ET7 event.
  130. */
  131. if (req->status != SCLP_REQ_DONE ||
  132. (sccb->evbuf.hdr.flags & 0x80) == 0 || /* processed-buffer */
  133. (sccb->hdr.response_code & 0xffU) != 0x20U) {
  134. rc = -EIO;
  135. }
  136. out_free:
  137. free_page((unsigned long) sccb);
  138. kfree(req);
  139. return rc;
  140. }
  141. /**
  142. * sclp_ftp_cmd() - executes a HMC related SCLP Diagnose (ET7) FTP command
  143. * @ftp: pointer to FTP command specification
  144. * @fsize: return of file size (or NULL if undesirable)
  145. *
  146. * Attention: Notice that this function is not reentrant - so the caller
  147. * must ensure locking.
  148. *
  149. * Return: number of bytes read/written or a (negative) error code
  150. */
  151. ssize_t sclp_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize)
  152. {
  153. ssize_t len;
  154. #ifdef DEBUG
  155. unsigned long start_jiffies;
  156. pr_debug("starting SCLP (ET7), cmd %d for '%s' at %lld with %zd bytes\n",
  157. ftp->id, ftp->fname, (long long) ftp->ofs, ftp->len);
  158. start_jiffies = jiffies;
  159. #endif
  160. init_completion(&sclp_ftp_rx_complete);
  161. /* Start ftp sclp command. */
  162. len = sclp_ftp_et7(ftp);
  163. if (len)
  164. goto out_unlock;
  165. /*
  166. * There is no way to cancel the sclp ET7 request, the code
  167. * needs to wait unconditionally until the transfer is complete.
  168. */
  169. wait_for_completion(&sclp_ftp_rx_complete);
  170. #ifdef DEBUG
  171. pr_debug("completed SCLP (ET7) request after %lu ms (all)\n",
  172. (jiffies - start_jiffies) * 1000 / HZ);
  173. pr_debug("return code of SCLP (ET7) FTP Service is 0x%02x, with %lld/%lld bytes\n",
  174. sclp_ftp_ldflg, sclp_ftp_length, sclp_ftp_fsize);
  175. #endif
  176. switch (sclp_ftp_ldflg) {
  177. case SCLP_DIAG_FTP_OK:
  178. len = sclp_ftp_length;
  179. if (fsize)
  180. *fsize = sclp_ftp_fsize;
  181. break;
  182. case SCLP_DIAG_FTP_LDNPERM:
  183. len = -EPERM;
  184. break;
  185. case SCLP_DIAG_FTP_LDRUNS:
  186. len = -EBUSY;
  187. break;
  188. case SCLP_DIAG_FTP_LDFAIL:
  189. len = -ENOENT;
  190. break;
  191. default:
  192. len = -EIO;
  193. break;
  194. }
  195. out_unlock:
  196. return len;
  197. }
  198. /*
  199. * ET7 event listener
  200. */
  201. static struct sclp_register sclp_ftp_event = {
  202. .send_mask = EVTYP_DIAG_TEST_MASK, /* want tx events */
  203. .receive_mask = EVTYP_DIAG_TEST_MASK, /* want rx events */
  204. .receiver_fn = sclp_ftp_rxcb, /* async callback (rx) */
  205. .state_change_fn = NULL,
  206. };
  207. /**
  208. * sclp_ftp_startup() - startup of FTP services, when running on LPAR
  209. */
  210. int sclp_ftp_startup(void)
  211. {
  212. #ifdef DEBUG
  213. unsigned long info;
  214. #endif
  215. int rc;
  216. rc = sclp_register(&sclp_ftp_event);
  217. if (rc)
  218. return rc;
  219. #ifdef DEBUG
  220. info = get_zeroed_page(GFP_KERNEL);
  221. if (info != 0) {
  222. struct sysinfo_2_2_2 *info222 = (struct sysinfo_2_2_2 *)info;
  223. if (!stsi(info222, 2, 2, 2)) { /* get SYSIB 2.2.2 */
  224. info222->name[sizeof(info222->name) - 1] = '\0';
  225. EBCASC_500(info222->name, sizeof(info222->name) - 1);
  226. pr_debug("SCLP (ET7) FTP Service working on LPAR %u (%s)\n",
  227. info222->lpar_number, info222->name);
  228. }
  229. free_page(info);
  230. }
  231. #endif /* DEBUG */
  232. return 0;
  233. }
  234. /**
  235. * sclp_ftp_shutdown() - shutdown of FTP services, when running on LPAR
  236. */
  237. void sclp_ftp_shutdown(void)
  238. {
  239. sclp_unregister(&sclp_ftp_event);
  240. }