brintos

brintos / linux-shallow public Read only

0
0
Text · 6.7 KiB · d27e2cb Raw
279 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *    SCLP Event Type (ET) 7 - Diagnostic Test FTP Services, useable on LPAR4 *5 *    Copyright IBM Corp. 20136 *    Author(s): Ralf Hoppe (rhoppe@de.ibm.com)7 *8 */9 10#define KMSG_COMPONENT "hmcdrv"11#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt12 13#include <linux/kernel.h>14#include <linux/mm.h>15#include <linux/slab.h>16#include <linux/io.h>17#include <linux/wait.h>18#include <linux/string.h>19#include <linux/jiffies.h>20#include <asm/sysinfo.h>21#include <asm/ebcdic.h>22 23#include "sclp.h"24#include "sclp_diag.h"25#include "sclp_ftp.h"26 27static DECLARE_COMPLETION(sclp_ftp_rx_complete);28static u8 sclp_ftp_ldflg;29static u64 sclp_ftp_fsize;30static u64 sclp_ftp_length;31 32/**33 * sclp_ftp_txcb() - Diagnostic Test FTP services SCLP command callback34 * @req: sclp request35 * @data: pointer to struct completion36 */37static void sclp_ftp_txcb(struct sclp_req *req, void *data)38{39	struct completion *completion = data;40 41#ifdef DEBUG42	pr_debug("SCLP (ET7) TX-IRQ, SCCB @ 0x%p: %*phN\n",43		 req->sccb, 24, req->sccb);44#endif45	complete(completion);46}47 48/**49 * sclp_ftp_rxcb() - Diagnostic Test FTP services receiver event callback50 * @evbuf: pointer to Diagnostic Test (ET7) event buffer51 */52static void sclp_ftp_rxcb(struct evbuf_header *evbuf)53{54	struct sclp_diag_evbuf *diag = (struct sclp_diag_evbuf *) evbuf;55 56	/*57	 * Check for Diagnostic Test FTP Service58	 */59	if (evbuf->type != EVTYP_DIAG_TEST ||60	    diag->route != SCLP_DIAG_FTP_ROUTE ||61	    diag->mdd.ftp.pcx != SCLP_DIAG_FTP_XPCX ||62	    evbuf->length < SCLP_DIAG_FTP_EVBUF_LEN)63		return;64 65#ifdef DEBUG66	pr_debug("SCLP (ET7) RX-IRQ, Event @ 0x%p: %*phN\n",67		 evbuf, 24, evbuf);68#endif69 70	/*71	 * Because the event buffer is located in a page which is owned72	 * by the SCLP core, all data of interest must be copied. The73	 * error indication is in 'sclp_ftp_ldflg'74	 */75	sclp_ftp_ldflg = diag->mdd.ftp.ldflg;76	sclp_ftp_fsize = diag->mdd.ftp.fsize;77	sclp_ftp_length = diag->mdd.ftp.length;78 79	complete(&sclp_ftp_rx_complete);80}81 82/**83 * sclp_ftp_et7() - start a Diagnostic Test FTP Service SCLP request84 * @ftp: pointer to FTP descriptor85 *86 * Return: 0 on success, else a (negative) error code87 */88static int sclp_ftp_et7(const struct hmcdrv_ftp_cmdspec *ftp)89{90	struct completion completion;91	struct sclp_diag_sccb *sccb;92	struct sclp_req *req;93	ssize_t len;94	int rc;95 96	req = kzalloc(sizeof(*req), GFP_KERNEL);97	sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);98	if (!req || !sccb) {99		rc = -ENOMEM;100		goto out_free;101	}102 103	sccb->hdr.length = SCLP_DIAG_FTP_EVBUF_LEN +104		sizeof(struct sccb_header);105	sccb->evbuf.hdr.type = EVTYP_DIAG_TEST;106	sccb->evbuf.hdr.length = SCLP_DIAG_FTP_EVBUF_LEN;107	sccb->evbuf.hdr.flags = 0; /* clear processed-buffer */108	sccb->evbuf.route = SCLP_DIAG_FTP_ROUTE;109	sccb->evbuf.mdd.ftp.pcx = SCLP_DIAG_FTP_XPCX;110	sccb->evbuf.mdd.ftp.srcflg = 0;111	sccb->evbuf.mdd.ftp.pgsize = 0;112	sccb->evbuf.mdd.ftp.asce = _ASCE_REAL_SPACE;113	sccb->evbuf.mdd.ftp.ldflg = SCLP_DIAG_FTP_LDFAIL;114	sccb->evbuf.mdd.ftp.fsize = 0;115	sccb->evbuf.mdd.ftp.cmd = ftp->id;116	sccb->evbuf.mdd.ftp.offset = ftp->ofs;117	sccb->evbuf.mdd.ftp.length = ftp->len;118	sccb->evbuf.mdd.ftp.bufaddr = virt_to_phys(ftp->buf);119 120	len = strscpy(sccb->evbuf.mdd.ftp.fident, ftp->fname,121		      HMCDRV_FTP_FIDENT_MAX);122	if (len < 0) {123		rc = -EINVAL;124		goto out_free;125	}126 127	req->command = SCLP_CMDW_WRITE_EVENT_DATA;128	req->sccb = sccb;129	req->status = SCLP_REQ_FILLED;130	req->callback = sclp_ftp_txcb;131	req->callback_data = &completion;132 133	init_completion(&completion);134 135	rc = sclp_add_request(req);136	if (rc)137		goto out_free;138 139	/* Wait for end of ftp sclp command. */140	wait_for_completion(&completion);141 142#ifdef DEBUG143	pr_debug("status of SCLP (ET7) request is 0x%04x (0x%02x)\n",144		 sccb->hdr.response_code, sccb->evbuf.hdr.flags);145#endif146 147	/*148	 * Check if sclp accepted the request. The data transfer runs149	 * asynchronously and the completion is indicated with an150	 * sclp ET7 event.151	 */152	if (req->status != SCLP_REQ_DONE ||153	    (sccb->evbuf.hdr.flags & 0x80) == 0 || /* processed-buffer */154	    (sccb->hdr.response_code & 0xffU) != 0x20U) {155		rc = -EIO;156	}157 158out_free:159	free_page((unsigned long) sccb);160	kfree(req);161	return rc;162}163 164/**165 * sclp_ftp_cmd() - executes a HMC related SCLP Diagnose (ET7) FTP command166 * @ftp: pointer to FTP command specification167 * @fsize: return of file size (or NULL if undesirable)168 *169 * Attention: Notice that this function is not reentrant - so the caller170 * must ensure locking.171 *172 * Return: number of bytes read/written or a (negative) error code173 */174ssize_t sclp_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize)175{176	ssize_t len;177#ifdef DEBUG178	unsigned long start_jiffies;179 180	pr_debug("starting SCLP (ET7), cmd %d for '%s' at %lld with %zd bytes\n",181		 ftp->id, ftp->fname, (long long) ftp->ofs, ftp->len);182	start_jiffies = jiffies;183#endif184 185	init_completion(&sclp_ftp_rx_complete);186 187	/* Start ftp sclp command. */188	len = sclp_ftp_et7(ftp);189	if (len)190		goto out_unlock;191 192	/*193	 * There is no way to cancel the sclp ET7 request, the code194	 * needs to wait unconditionally until the transfer is complete.195	 */196	wait_for_completion(&sclp_ftp_rx_complete);197 198#ifdef DEBUG199	pr_debug("completed SCLP (ET7) request after %lu ms (all)\n",200		 (jiffies - start_jiffies) * 1000 / HZ);201	pr_debug("return code of SCLP (ET7) FTP Service is 0x%02x, with %lld/%lld bytes\n",202		 sclp_ftp_ldflg, sclp_ftp_length, sclp_ftp_fsize);203#endif204 205	switch (sclp_ftp_ldflg) {206	case SCLP_DIAG_FTP_OK:207		len = sclp_ftp_length;208		if (fsize)209			*fsize = sclp_ftp_fsize;210		break;211	case SCLP_DIAG_FTP_LDNPERM:212		len = -EPERM;213		break;214	case SCLP_DIAG_FTP_LDRUNS:215		len = -EBUSY;216		break;217	case SCLP_DIAG_FTP_LDFAIL:218		len = -ENOENT;219		break;220	default:221		len = -EIO;222		break;223	}224 225out_unlock:226	return len;227}228 229/*230 * ET7 event listener231 */232static struct sclp_register sclp_ftp_event = {233	.send_mask = EVTYP_DIAG_TEST_MASK,    /* want tx events */234	.receive_mask = EVTYP_DIAG_TEST_MASK, /* want rx events */235	.receiver_fn = sclp_ftp_rxcb,	      /* async callback (rx) */236	.state_change_fn = NULL,237};238 239/**240 * sclp_ftp_startup() - startup of FTP services, when running on LPAR241 */242int sclp_ftp_startup(void)243{244#ifdef DEBUG245	unsigned long info;246#endif247	int rc;248 249	rc = sclp_register(&sclp_ftp_event);250	if (rc)251		return rc;252 253#ifdef DEBUG254	info = get_zeroed_page(GFP_KERNEL);255 256	if (info != 0) {257		struct sysinfo_2_2_2 *info222 = (struct sysinfo_2_2_2 *)info;258 259		if (!stsi(info222, 2, 2, 2)) { /* get SYSIB 2.2.2 */260			info222->name[sizeof(info222->name) - 1] = '\0';261			EBCASC_500(info222->name, sizeof(info222->name) - 1);262			pr_debug("SCLP (ET7) FTP Service working on LPAR %u (%s)\n",263				 info222->lpar_number, info222->name);264		}265 266		free_page(info);267	}268#endif	/* DEBUG */269	return 0;270}271 272/**273 * sclp_ftp_shutdown() - shutdown of FTP services, when running on LPAR274 */275void sclp_ftp_shutdown(void)276{277	sclp_unregister(&sclp_ftp_event);278}279