Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *    SCLP Event Type (ET) 7 - Diagnostic Test FTP Services, useable on LPAR
0004  *
0005  *    Copyright IBM Corp. 2013
0006  *    Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
0007  *
0008  */
0009 
0010 #define KMSG_COMPONENT "hmcdrv"
0011 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
0012 
0013 #include <linux/kernel.h>
0014 #include <linux/mm.h>
0015 #include <linux/slab.h>
0016 #include <linux/io.h>
0017 #include <linux/wait.h>
0018 #include <linux/string.h>
0019 #include <linux/jiffies.h>
0020 #include <asm/sysinfo.h>
0021 #include <asm/ebcdic.h>
0022 
0023 #include "sclp.h"
0024 #include "sclp_diag.h"
0025 #include "sclp_ftp.h"
0026 
0027 static DECLARE_COMPLETION(sclp_ftp_rx_complete);
0028 static u8 sclp_ftp_ldflg;
0029 static u64 sclp_ftp_fsize;
0030 static u64 sclp_ftp_length;
0031 
0032 /**
0033  * sclp_ftp_txcb() - Diagnostic Test FTP services SCLP command callback
0034  * @req: sclp request
0035  * @data: pointer to struct completion
0036  */
0037 static void sclp_ftp_txcb(struct sclp_req *req, void *data)
0038 {
0039     struct completion *completion = data;
0040 
0041 #ifdef DEBUG
0042     pr_debug("SCLP (ET7) TX-IRQ, SCCB @ 0x%p: %*phN\n",
0043          req->sccb, 24, req->sccb);
0044 #endif
0045     complete(completion);
0046 }
0047 
0048 /**
0049  * sclp_ftp_rxcb() - Diagnostic Test FTP services receiver event callback
0050  * @evbuf: pointer to Diagnostic Test (ET7) event buffer
0051  */
0052 static void sclp_ftp_rxcb(struct evbuf_header *evbuf)
0053 {
0054     struct sclp_diag_evbuf *diag = (struct sclp_diag_evbuf *) evbuf;
0055 
0056     /*
0057      * Check for Diagnostic Test FTP Service
0058      */
0059     if (evbuf->type != EVTYP_DIAG_TEST ||
0060         diag->route != SCLP_DIAG_FTP_ROUTE ||
0061         diag->mdd.ftp.pcx != SCLP_DIAG_FTP_XPCX ||
0062         evbuf->length < SCLP_DIAG_FTP_EVBUF_LEN)
0063         return;
0064 
0065 #ifdef DEBUG
0066     pr_debug("SCLP (ET7) RX-IRQ, Event @ 0x%p: %*phN\n",
0067          evbuf, 24, evbuf);
0068 #endif
0069 
0070     /*
0071      * Because the event buffer is located in a page which is owned
0072      * by the SCLP core, all data of interest must be copied. The
0073      * error indication is in 'sclp_ftp_ldflg'
0074      */
0075     sclp_ftp_ldflg = diag->mdd.ftp.ldflg;
0076     sclp_ftp_fsize = diag->mdd.ftp.fsize;
0077     sclp_ftp_length = diag->mdd.ftp.length;
0078 
0079     complete(&sclp_ftp_rx_complete);
0080 }
0081 
0082 /**
0083  * sclp_ftp_et7() - start a Diagnostic Test FTP Service SCLP request
0084  * @ftp: pointer to FTP descriptor
0085  *
0086  * Return: 0 on success, else a (negative) error code
0087  */
0088 static int sclp_ftp_et7(const struct hmcdrv_ftp_cmdspec *ftp)
0089 {
0090     struct completion completion;
0091     struct sclp_diag_sccb *sccb;
0092     struct sclp_req *req;
0093     size_t len;
0094     int rc;
0095 
0096     req = kzalloc(sizeof(*req), GFP_KERNEL);
0097     sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
0098     if (!req || !sccb) {
0099         rc = -ENOMEM;
0100         goto out_free;
0101     }
0102 
0103     sccb->hdr.length = SCLP_DIAG_FTP_EVBUF_LEN +
0104         sizeof(struct sccb_header);
0105     sccb->evbuf.hdr.type = EVTYP_DIAG_TEST;
0106     sccb->evbuf.hdr.length = SCLP_DIAG_FTP_EVBUF_LEN;
0107     sccb->evbuf.hdr.flags = 0; /* clear processed-buffer */
0108     sccb->evbuf.route = SCLP_DIAG_FTP_ROUTE;
0109     sccb->evbuf.mdd.ftp.pcx = SCLP_DIAG_FTP_XPCX;
0110     sccb->evbuf.mdd.ftp.srcflg = 0;
0111     sccb->evbuf.mdd.ftp.pgsize = 0;
0112     sccb->evbuf.mdd.ftp.asce = _ASCE_REAL_SPACE;
0113     sccb->evbuf.mdd.ftp.ldflg = SCLP_DIAG_FTP_LDFAIL;
0114     sccb->evbuf.mdd.ftp.fsize = 0;
0115     sccb->evbuf.mdd.ftp.cmd = ftp->id;
0116     sccb->evbuf.mdd.ftp.offset = ftp->ofs;
0117     sccb->evbuf.mdd.ftp.length = ftp->len;
0118     sccb->evbuf.mdd.ftp.bufaddr = virt_to_phys(ftp->buf);
0119 
0120     len = strlcpy(sccb->evbuf.mdd.ftp.fident, ftp->fname,
0121               HMCDRV_FTP_FIDENT_MAX);
0122     if (len >= HMCDRV_FTP_FIDENT_MAX) {
0123         rc = -EINVAL;
0124         goto out_free;
0125     }
0126 
0127     req->command = SCLP_CMDW_WRITE_EVENT_DATA;
0128     req->sccb = sccb;
0129     req->status = SCLP_REQ_FILLED;
0130     req->callback = sclp_ftp_txcb;
0131     req->callback_data = &completion;
0132 
0133     init_completion(&completion);
0134 
0135     rc = sclp_add_request(req);
0136     if (rc)
0137         goto out_free;
0138 
0139     /* Wait for end of ftp sclp command. */
0140     wait_for_completion(&completion);
0141 
0142 #ifdef DEBUG
0143     pr_debug("status of SCLP (ET7) request is 0x%04x (0x%02x)\n",
0144          sccb->hdr.response_code, sccb->evbuf.hdr.flags);
0145 #endif
0146 
0147     /*
0148      * Check if sclp accepted the request. The data transfer runs
0149      * asynchronously and the completion is indicated with an
0150      * sclp ET7 event.
0151      */
0152     if (req->status != SCLP_REQ_DONE ||
0153         (sccb->evbuf.hdr.flags & 0x80) == 0 || /* processed-buffer */
0154         (sccb->hdr.response_code & 0xffU) != 0x20U) {
0155         rc = -EIO;
0156     }
0157 
0158 out_free:
0159     free_page((unsigned long) sccb);
0160     kfree(req);
0161     return rc;
0162 }
0163 
0164 /**
0165  * sclp_ftp_cmd() - executes a HMC related SCLP Diagnose (ET7) FTP command
0166  * @ftp: pointer to FTP command specification
0167  * @fsize: return of file size (or NULL if undesirable)
0168  *
0169  * Attention: Notice that this function is not reentrant - so the caller
0170  * must ensure locking.
0171  *
0172  * Return: number of bytes read/written or a (negative) error code
0173  */
0174 ssize_t sclp_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize)
0175 {
0176     ssize_t len;
0177 #ifdef DEBUG
0178     unsigned long start_jiffies;
0179 
0180     pr_debug("starting SCLP (ET7), cmd %d for '%s' at %lld with %zd bytes\n",
0181          ftp->id, ftp->fname, (long long) ftp->ofs, ftp->len);
0182     start_jiffies = jiffies;
0183 #endif
0184 
0185     init_completion(&sclp_ftp_rx_complete);
0186 
0187     /* Start ftp sclp command. */
0188     len = sclp_ftp_et7(ftp);
0189     if (len)
0190         goto out_unlock;
0191 
0192     /*
0193      * There is no way to cancel the sclp ET7 request, the code
0194      * needs to wait unconditionally until the transfer is complete.
0195      */
0196     wait_for_completion(&sclp_ftp_rx_complete);
0197 
0198 #ifdef DEBUG
0199     pr_debug("completed SCLP (ET7) request after %lu ms (all)\n",
0200          (jiffies - start_jiffies) * 1000 / HZ);
0201     pr_debug("return code of SCLP (ET7) FTP Service is 0x%02x, with %lld/%lld bytes\n",
0202          sclp_ftp_ldflg, sclp_ftp_length, sclp_ftp_fsize);
0203 #endif
0204 
0205     switch (sclp_ftp_ldflg) {
0206     case SCLP_DIAG_FTP_OK:
0207         len = sclp_ftp_length;
0208         if (fsize)
0209             *fsize = sclp_ftp_fsize;
0210         break;
0211     case SCLP_DIAG_FTP_LDNPERM:
0212         len = -EPERM;
0213         break;
0214     case SCLP_DIAG_FTP_LDRUNS:
0215         len = -EBUSY;
0216         break;
0217     case SCLP_DIAG_FTP_LDFAIL:
0218         len = -ENOENT;
0219         break;
0220     default:
0221         len = -EIO;
0222         break;
0223     }
0224 
0225 out_unlock:
0226     return len;
0227 }
0228 
0229 /*
0230  * ET7 event listener
0231  */
0232 static struct sclp_register sclp_ftp_event = {
0233     .send_mask = EVTYP_DIAG_TEST_MASK,    /* want tx events */
0234     .receive_mask = EVTYP_DIAG_TEST_MASK, /* want rx events */
0235     .receiver_fn = sclp_ftp_rxcb,         /* async callback (rx) */
0236     .state_change_fn = NULL,
0237 };
0238 
0239 /**
0240  * sclp_ftp_startup() - startup of FTP services, when running on LPAR
0241  */
0242 int sclp_ftp_startup(void)
0243 {
0244 #ifdef DEBUG
0245     unsigned long info;
0246 #endif
0247     int rc;
0248 
0249     rc = sclp_register(&sclp_ftp_event);
0250     if (rc)
0251         return rc;
0252 
0253 #ifdef DEBUG
0254     info = get_zeroed_page(GFP_KERNEL);
0255 
0256     if (info != 0) {
0257         struct sysinfo_2_2_2 *info222 = (struct sysinfo_2_2_2 *)info;
0258 
0259         if (!stsi(info222, 2, 2, 2)) { /* get SYSIB 2.2.2 */
0260             info222->name[sizeof(info222->name) - 1] = '\0';
0261             EBCASC_500(info222->name, sizeof(info222->name) - 1);
0262             pr_debug("SCLP (ET7) FTP Service working on LPAR %u (%s)\n",
0263                  info222->lpar_number, info222->name);
0264         }
0265 
0266         free_page(info);
0267     }
0268 #endif  /* DEBUG */
0269     return 0;
0270 }
0271 
0272 /**
0273  * sclp_ftp_shutdown() - shutdown of FTP services, when running on LPAR
0274  */
0275 void sclp_ftp_shutdown(void)
0276 {
0277     sclp_unregister(&sclp_ftp_event);
0278 }