root/drivers/s390/char/sclp_ftp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sclp_ftp_txcb
  2. sclp_ftp_rxcb
  3. sclp_ftp_et7
  4. sclp_ftp_cmd
  5. sclp_ftp_startup
  6. sclp_ftp_shutdown

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

/* [<][>][^][v][top][bottom][index][help] */