1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 28f933b10SRalf Hoppe /* 38f933b10SRalf Hoppe * SCLP Event Type (ET) 7 - Diagnostic Test FTP Services, useable on LPAR 48f933b10SRalf Hoppe * 58f933b10SRalf Hoppe * Copyright IBM Corp. 2013 68f933b10SRalf Hoppe * Author(s): Ralf Hoppe (rhoppe@de.ibm.com) 78f933b10SRalf Hoppe * 88f933b10SRalf Hoppe */ 98f933b10SRalf Hoppe 108f933b10SRalf Hoppe #define KMSG_COMPONENT "hmcdrv" 118f933b10SRalf Hoppe #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 128f933b10SRalf Hoppe 138f933b10SRalf Hoppe #include <linux/kernel.h> 148f933b10SRalf Hoppe #include <linux/mm.h> 158f933b10SRalf Hoppe #include <linux/slab.h> 168f933b10SRalf Hoppe #include <linux/io.h> 178f933b10SRalf Hoppe #include <linux/wait.h> 188f933b10SRalf Hoppe #include <linux/string.h> 198f933b10SRalf Hoppe #include <linux/jiffies.h> 208f933b10SRalf Hoppe #include <asm/sysinfo.h> 218f933b10SRalf Hoppe #include <asm/ebcdic.h> 228f933b10SRalf Hoppe 238f933b10SRalf Hoppe #include "sclp.h" 248f933b10SRalf Hoppe #include "sclp_diag.h" 258f933b10SRalf Hoppe #include "sclp_ftp.h" 268f933b10SRalf Hoppe 278f933b10SRalf Hoppe static DECLARE_COMPLETION(sclp_ftp_rx_complete); 288f933b10SRalf Hoppe static u8 sclp_ftp_ldflg; 298f933b10SRalf Hoppe static u64 sclp_ftp_fsize; 308f933b10SRalf Hoppe static u64 sclp_ftp_length; 318f933b10SRalf Hoppe 328f933b10SRalf Hoppe /** 338f933b10SRalf Hoppe * sclp_ftp_txcb() - Diagnostic Test FTP services SCLP command callback 348f933b10SRalf Hoppe */ 358f933b10SRalf Hoppe static void sclp_ftp_txcb(struct sclp_req *req, void *data) 368f933b10SRalf Hoppe { 378f933b10SRalf Hoppe struct completion *completion = data; 388f933b10SRalf Hoppe 398f933b10SRalf Hoppe #ifdef DEBUG 408f933b10SRalf Hoppe pr_debug("SCLP (ET7) TX-IRQ, SCCB @ 0x%p: %*phN\n", 418f933b10SRalf Hoppe req->sccb, 24, req->sccb); 428f933b10SRalf Hoppe #endif 438f933b10SRalf Hoppe complete(completion); 448f933b10SRalf Hoppe } 458f933b10SRalf Hoppe 468f933b10SRalf Hoppe /** 478f933b10SRalf Hoppe * sclp_ftp_rxcb() - Diagnostic Test FTP services receiver event callback 488f933b10SRalf Hoppe */ 498f933b10SRalf Hoppe static void sclp_ftp_rxcb(struct evbuf_header *evbuf) 508f933b10SRalf Hoppe { 518f933b10SRalf Hoppe struct sclp_diag_evbuf *diag = (struct sclp_diag_evbuf *) evbuf; 528f933b10SRalf Hoppe 538f933b10SRalf Hoppe /* 548f933b10SRalf Hoppe * Check for Diagnostic Test FTP Service 558f933b10SRalf Hoppe */ 568f933b10SRalf Hoppe if (evbuf->type != EVTYP_DIAG_TEST || 578f933b10SRalf Hoppe diag->route != SCLP_DIAG_FTP_ROUTE || 588f933b10SRalf Hoppe diag->mdd.ftp.pcx != SCLP_DIAG_FTP_XPCX || 598f933b10SRalf Hoppe evbuf->length < SCLP_DIAG_FTP_EVBUF_LEN) 608f933b10SRalf Hoppe return; 618f933b10SRalf Hoppe 628f933b10SRalf Hoppe #ifdef DEBUG 638f933b10SRalf Hoppe pr_debug("SCLP (ET7) RX-IRQ, Event @ 0x%p: %*phN\n", 648f933b10SRalf Hoppe evbuf, 24, evbuf); 658f933b10SRalf Hoppe #endif 668f933b10SRalf Hoppe 678f933b10SRalf Hoppe /* 688f933b10SRalf Hoppe * Because the event buffer is located in a page which is owned 698f933b10SRalf Hoppe * by the SCLP core, all data of interest must be copied. The 708f933b10SRalf Hoppe * error indication is in 'sclp_ftp_ldflg' 718f933b10SRalf Hoppe */ 728f933b10SRalf Hoppe sclp_ftp_ldflg = diag->mdd.ftp.ldflg; 738f933b10SRalf Hoppe sclp_ftp_fsize = diag->mdd.ftp.fsize; 748f933b10SRalf Hoppe sclp_ftp_length = diag->mdd.ftp.length; 758f933b10SRalf Hoppe 768f933b10SRalf Hoppe complete(&sclp_ftp_rx_complete); 778f933b10SRalf Hoppe } 788f933b10SRalf Hoppe 798f933b10SRalf Hoppe /** 808f933b10SRalf Hoppe * sclp_ftp_et7() - start a Diagnostic Test FTP Service SCLP request 818f933b10SRalf Hoppe * @ftp: pointer to FTP descriptor 828f933b10SRalf Hoppe * 838f933b10SRalf Hoppe * Return: 0 on success, else a (negative) error code 848f933b10SRalf Hoppe */ 858f933b10SRalf Hoppe static int sclp_ftp_et7(const struct hmcdrv_ftp_cmdspec *ftp) 868f933b10SRalf Hoppe { 878f933b10SRalf Hoppe struct completion completion; 888f933b10SRalf Hoppe struct sclp_diag_sccb *sccb; 898f933b10SRalf Hoppe struct sclp_req *req; 908f933b10SRalf Hoppe size_t len; 918f933b10SRalf Hoppe int rc; 928f933b10SRalf Hoppe 938f933b10SRalf Hoppe req = kzalloc(sizeof(*req), GFP_KERNEL); 948f933b10SRalf Hoppe sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); 958f933b10SRalf Hoppe if (!req || !sccb) { 968f933b10SRalf Hoppe rc = -ENOMEM; 978f933b10SRalf Hoppe goto out_free; 988f933b10SRalf Hoppe } 998f933b10SRalf Hoppe 1008f933b10SRalf Hoppe sccb->hdr.length = SCLP_DIAG_FTP_EVBUF_LEN + 1018f933b10SRalf Hoppe sizeof(struct sccb_header); 1028f933b10SRalf Hoppe sccb->evbuf.hdr.type = EVTYP_DIAG_TEST; 1038f933b10SRalf Hoppe sccb->evbuf.hdr.length = SCLP_DIAG_FTP_EVBUF_LEN; 1048f933b10SRalf Hoppe sccb->evbuf.hdr.flags = 0; /* clear processed-buffer */ 1058f933b10SRalf Hoppe sccb->evbuf.route = SCLP_DIAG_FTP_ROUTE; 1068f933b10SRalf Hoppe sccb->evbuf.mdd.ftp.pcx = SCLP_DIAG_FTP_XPCX; 1078f933b10SRalf Hoppe sccb->evbuf.mdd.ftp.srcflg = 0; 1088f933b10SRalf Hoppe sccb->evbuf.mdd.ftp.pgsize = 0; 1098f933b10SRalf Hoppe sccb->evbuf.mdd.ftp.asce = _ASCE_REAL_SPACE; 1108f933b10SRalf Hoppe sccb->evbuf.mdd.ftp.ldflg = SCLP_DIAG_FTP_LDFAIL; 1118f933b10SRalf Hoppe sccb->evbuf.mdd.ftp.fsize = 0; 1128f933b10SRalf Hoppe sccb->evbuf.mdd.ftp.cmd = ftp->id; 1138f933b10SRalf Hoppe sccb->evbuf.mdd.ftp.offset = ftp->ofs; 1148f933b10SRalf Hoppe sccb->evbuf.mdd.ftp.length = ftp->len; 1158f933b10SRalf Hoppe sccb->evbuf.mdd.ftp.bufaddr = virt_to_phys(ftp->buf); 1168f933b10SRalf Hoppe 1178f933b10SRalf Hoppe len = strlcpy(sccb->evbuf.mdd.ftp.fident, ftp->fname, 1188f933b10SRalf Hoppe HMCDRV_FTP_FIDENT_MAX); 1198f933b10SRalf Hoppe if (len >= HMCDRV_FTP_FIDENT_MAX) { 1208f933b10SRalf Hoppe rc = -EINVAL; 1218f933b10SRalf Hoppe goto out_free; 1228f933b10SRalf Hoppe } 1238f933b10SRalf Hoppe 1248f933b10SRalf Hoppe req->command = SCLP_CMDW_WRITE_EVENT_DATA; 1258f933b10SRalf Hoppe req->sccb = sccb; 1268f933b10SRalf Hoppe req->status = SCLP_REQ_FILLED; 1278f933b10SRalf Hoppe req->callback = sclp_ftp_txcb; 1288f933b10SRalf Hoppe req->callback_data = &completion; 1298f933b10SRalf Hoppe 1308f933b10SRalf Hoppe init_completion(&completion); 1318f933b10SRalf Hoppe 1328f933b10SRalf Hoppe rc = sclp_add_request(req); 1338f933b10SRalf Hoppe if (rc) 1348f933b10SRalf Hoppe goto out_free; 1358f933b10SRalf Hoppe 1368f933b10SRalf Hoppe /* Wait for end of ftp sclp command. */ 1378f933b10SRalf Hoppe wait_for_completion(&completion); 1388f933b10SRalf Hoppe 1398f933b10SRalf Hoppe #ifdef DEBUG 1408f933b10SRalf Hoppe pr_debug("status of SCLP (ET7) request is 0x%04x (0x%02x)\n", 1418f933b10SRalf Hoppe sccb->hdr.response_code, sccb->evbuf.hdr.flags); 1428f933b10SRalf Hoppe #endif 1438f933b10SRalf Hoppe 1448f933b10SRalf Hoppe /* 1458f933b10SRalf Hoppe * Check if sclp accepted the request. The data transfer runs 1468f933b10SRalf Hoppe * asynchronously and the completion is indicated with an 1478f933b10SRalf Hoppe * sclp ET7 event. 1488f933b10SRalf Hoppe */ 1498f933b10SRalf Hoppe if (req->status != SCLP_REQ_DONE || 1508f933b10SRalf Hoppe (sccb->evbuf.hdr.flags & 0x80) == 0 || /* processed-buffer */ 1518f933b10SRalf Hoppe (sccb->hdr.response_code & 0xffU) != 0x20U) { 1528f933b10SRalf Hoppe rc = -EIO; 1538f933b10SRalf Hoppe } 1548f933b10SRalf Hoppe 1558f933b10SRalf Hoppe out_free: 1568f933b10SRalf Hoppe free_page((unsigned long) sccb); 1578f933b10SRalf Hoppe kfree(req); 1588f933b10SRalf Hoppe return rc; 1598f933b10SRalf Hoppe } 1608f933b10SRalf Hoppe 1618f933b10SRalf Hoppe /** 1628f933b10SRalf Hoppe * sclp_ftp_cmd() - executes a HMC related SCLP Diagnose (ET7) FTP command 1638f933b10SRalf Hoppe * @ftp: pointer to FTP command specification 1648f933b10SRalf Hoppe * @fsize: return of file size (or NULL if undesirable) 1658f933b10SRalf Hoppe * 1668f933b10SRalf Hoppe * Attention: Notice that this function is not reentrant - so the caller 1678f933b10SRalf Hoppe * must ensure locking. 1688f933b10SRalf Hoppe * 1698f933b10SRalf Hoppe * Return: number of bytes read/written or a (negative) error code 1708f933b10SRalf Hoppe */ 1718f933b10SRalf Hoppe ssize_t sclp_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize) 1728f933b10SRalf Hoppe { 1738f933b10SRalf Hoppe ssize_t len; 1748f933b10SRalf Hoppe #ifdef DEBUG 1758f933b10SRalf Hoppe unsigned long start_jiffies; 1768f933b10SRalf Hoppe 1778f933b10SRalf Hoppe pr_debug("starting SCLP (ET7), cmd %d for '%s' at %lld with %zd bytes\n", 1788f933b10SRalf Hoppe ftp->id, ftp->fname, (long long) ftp->ofs, ftp->len); 1798f933b10SRalf Hoppe start_jiffies = jiffies; 1808f933b10SRalf Hoppe #endif 1818f933b10SRalf Hoppe 1828f933b10SRalf Hoppe init_completion(&sclp_ftp_rx_complete); 1838f933b10SRalf Hoppe 1848f933b10SRalf Hoppe /* Start ftp sclp command. */ 1858f933b10SRalf Hoppe len = sclp_ftp_et7(ftp); 1868f933b10SRalf Hoppe if (len) 1878f933b10SRalf Hoppe goto out_unlock; 1888f933b10SRalf Hoppe 1898f933b10SRalf Hoppe /* 1908f933b10SRalf Hoppe * There is no way to cancel the sclp ET7 request, the code 1918f933b10SRalf Hoppe * needs to wait unconditionally until the transfer is complete. 1928f933b10SRalf Hoppe */ 1938f933b10SRalf Hoppe wait_for_completion(&sclp_ftp_rx_complete); 1948f933b10SRalf Hoppe 1958f933b10SRalf Hoppe #ifdef DEBUG 1968f933b10SRalf Hoppe pr_debug("completed SCLP (ET7) request after %lu ms (all)\n", 1978f933b10SRalf Hoppe (jiffies - start_jiffies) * 1000 / HZ); 1988f933b10SRalf Hoppe pr_debug("return code of SCLP (ET7) FTP Service is 0x%02x, with %lld/%lld bytes\n", 1998f933b10SRalf Hoppe sclp_ftp_ldflg, sclp_ftp_length, sclp_ftp_fsize); 2008f933b10SRalf Hoppe #endif 2018f933b10SRalf Hoppe 2028f933b10SRalf Hoppe switch (sclp_ftp_ldflg) { 2038f933b10SRalf Hoppe case SCLP_DIAG_FTP_OK: 2048f933b10SRalf Hoppe len = sclp_ftp_length; 2058f933b10SRalf Hoppe if (fsize) 2068f933b10SRalf Hoppe *fsize = sclp_ftp_fsize; 2078f933b10SRalf Hoppe break; 2088f933b10SRalf Hoppe case SCLP_DIAG_FTP_LDNPERM: 2098f933b10SRalf Hoppe len = -EPERM; 2108f933b10SRalf Hoppe break; 2118f933b10SRalf Hoppe case SCLP_DIAG_FTP_LDRUNS: 2128f933b10SRalf Hoppe len = -EBUSY; 2138f933b10SRalf Hoppe break; 2148f933b10SRalf Hoppe case SCLP_DIAG_FTP_LDFAIL: 2158f933b10SRalf Hoppe len = -ENOENT; 2168f933b10SRalf Hoppe break; 2178f933b10SRalf Hoppe default: 2188f933b10SRalf Hoppe len = -EIO; 2198f933b10SRalf Hoppe break; 2208f933b10SRalf Hoppe } 2218f933b10SRalf Hoppe 2228f933b10SRalf Hoppe out_unlock: 2238f933b10SRalf Hoppe return len; 2248f933b10SRalf Hoppe } 2258f933b10SRalf Hoppe 2268f933b10SRalf Hoppe /* 2278f933b10SRalf Hoppe * ET7 event listener 2288f933b10SRalf Hoppe */ 2298f933b10SRalf Hoppe static struct sclp_register sclp_ftp_event = { 2308f933b10SRalf Hoppe .send_mask = EVTYP_DIAG_TEST_MASK, /* want tx events */ 2318f933b10SRalf Hoppe .receive_mask = EVTYP_DIAG_TEST_MASK, /* want rx events */ 2328f933b10SRalf Hoppe .receiver_fn = sclp_ftp_rxcb, /* async callback (rx) */ 2338f933b10SRalf Hoppe .state_change_fn = NULL, 2348f933b10SRalf Hoppe .pm_event_fn = NULL, 2358f933b10SRalf Hoppe }; 2368f933b10SRalf Hoppe 2378f933b10SRalf Hoppe /** 2388f933b10SRalf Hoppe * sclp_ftp_startup() - startup of FTP services, when running on LPAR 2398f933b10SRalf Hoppe */ 2408f933b10SRalf Hoppe int sclp_ftp_startup(void) 2418f933b10SRalf Hoppe { 2428f933b10SRalf Hoppe #ifdef DEBUG 2438f933b10SRalf Hoppe unsigned long info; 2448f933b10SRalf Hoppe #endif 2458f933b10SRalf Hoppe int rc; 2468f933b10SRalf Hoppe 2478f933b10SRalf Hoppe rc = sclp_register(&sclp_ftp_event); 2488f933b10SRalf Hoppe if (rc) 2498f933b10SRalf Hoppe return rc; 2508f933b10SRalf Hoppe 2518f933b10SRalf Hoppe #ifdef DEBUG 2528f933b10SRalf Hoppe info = get_zeroed_page(GFP_KERNEL); 2538f933b10SRalf Hoppe 2548f933b10SRalf Hoppe if (info != 0) { 2558f933b10SRalf Hoppe struct sysinfo_2_2_2 *info222 = (struct sysinfo_2_2_2 *)info; 2568f933b10SRalf Hoppe 2578f933b10SRalf Hoppe if (!stsi(info222, 2, 2, 2)) { /* get SYSIB 2.2.2 */ 2588f933b10SRalf Hoppe info222->name[sizeof(info222->name) - 1] = '\0'; 2598f933b10SRalf Hoppe EBCASC_500(info222->name, sizeof(info222->name) - 1); 2608f933b10SRalf Hoppe pr_debug("SCLP (ET7) FTP Service working on LPAR %u (%s)\n", 2618f933b10SRalf Hoppe info222->lpar_number, info222->name); 2628f933b10SRalf Hoppe } 2638f933b10SRalf Hoppe 2648f933b10SRalf Hoppe free_page(info); 2658f933b10SRalf Hoppe } 2668f933b10SRalf Hoppe #endif /* DEBUG */ 2678f933b10SRalf Hoppe return 0; 2688f933b10SRalf Hoppe } 2698f933b10SRalf Hoppe 2708f933b10SRalf Hoppe /** 2718f933b10SRalf Hoppe * sclp_ftp_shutdown() - shutdown of FTP services, when running on LPAR 2728f933b10SRalf Hoppe */ 2738f933b10SRalf Hoppe void sclp_ftp_shutdown(void) 2748f933b10SRalf Hoppe { 2758f933b10SRalf Hoppe sclp_unregister(&sclp_ftp_event); 2768f933b10SRalf Hoppe } 277