0001
0002
0003
0004
0005
0006
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
0034
0035
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
0050
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
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
0072
0073
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
0084
0085
0086
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;
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
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
0149
0150
0151
0152 if (req->status != SCLP_REQ_DONE ||
0153 (sccb->evbuf.hdr.flags & 0x80) == 0 ||
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
0166
0167
0168
0169
0170
0171
0172
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
0188 len = sclp_ftp_et7(ftp);
0189 if (len)
0190 goto out_unlock;
0191
0192
0193
0194
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
0231
0232 static struct sclp_register sclp_ftp_event = {
0233 .send_mask = EVTYP_DIAG_TEST_MASK,
0234 .receive_mask = EVTYP_DIAG_TEST_MASK,
0235 .receiver_fn = sclp_ftp_rxcb,
0236 .state_change_fn = NULL,
0237 };
0238
0239
0240
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)) {
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
0269 return 0;
0270 }
0271
0272
0273
0274
0275 void sclp_ftp_shutdown(void)
0276 {
0277 sclp_unregister(&sclp_ftp_event);
0278 }