1 // SPDX-License-Identifier: GPL-2.0
3 * SCLP Event Type (ET) 7 - Diagnostic Test FTP Services, useable on LPAR
5 * Copyright IBM Corp. 2013
6 * Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
10 #define KMSG_COMPONENT "hmcdrv"
11 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
13 #include <linux/kernel.h>
15 #include <linux/slab.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>
24 #include "sclp_diag.h"
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
;
33 * sclp_ftp_txcb() - Diagnostic Test FTP services SCLP command callback
35 static void sclp_ftp_txcb(struct sclp_req
*req
, void *data
)
37 struct completion
*completion
= data
;
40 pr_debug("SCLP (ET7) TX-IRQ, SCCB @ 0x%p: %*phN\n",
41 req
->sccb
, 24, req
->sccb
);
47 * sclp_ftp_rxcb() - Diagnostic Test FTP services receiver event callback
49 static void sclp_ftp_rxcb(struct evbuf_header
*evbuf
)
51 struct sclp_diag_evbuf
*diag
= (struct sclp_diag_evbuf
*) evbuf
;
54 * Check for Diagnostic Test FTP Service
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
)
63 pr_debug("SCLP (ET7) RX-IRQ, Event @ 0x%p: %*phN\n",
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'
72 sclp_ftp_ldflg
= diag
->mdd
.ftp
.ldflg
;
73 sclp_ftp_fsize
= diag
->mdd
.ftp
.fsize
;
74 sclp_ftp_length
= diag
->mdd
.ftp
.length
;
76 complete(&sclp_ftp_rx_complete
);
80 * sclp_ftp_et7() - start a Diagnostic Test FTP Service SCLP request
81 * @ftp: pointer to FTP descriptor
83 * Return: 0 on success, else a (negative) error code
85 static int sclp_ftp_et7(const struct hmcdrv_ftp_cmdspec
*ftp
)
87 struct completion completion
;
88 struct sclp_diag_sccb
*sccb
;
93 req
= kzalloc(sizeof(*req
), GFP_KERNEL
);
94 sccb
= (void *) get_zeroed_page(GFP_KERNEL
| GFP_DMA
);
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
);
117 len
= strlcpy(sccb
->evbuf
.mdd
.ftp
.fident
, ftp
->fname
,
118 HMCDRV_FTP_FIDENT_MAX
);
119 if (len
>= HMCDRV_FTP_FIDENT_MAX
) {
124 req
->command
= SCLP_CMDW_WRITE_EVENT_DATA
;
126 req
->status
= SCLP_REQ_FILLED
;
127 req
->callback
= sclp_ftp_txcb
;
128 req
->callback_data
= &completion
;
130 init_completion(&completion
);
132 rc
= sclp_add_request(req
);
136 /* Wait for end of ftp sclp command. */
137 wait_for_completion(&completion
);
140 pr_debug("status of SCLP (ET7) request is 0x%04x (0x%02x)\n",
141 sccb
->hdr
.response_code
, sccb
->evbuf
.hdr
.flags
);
145 * Check if sclp accepted the request. The data transfer runs
146 * asynchronously and the completion is indicated with an
149 if (req
->status
!= SCLP_REQ_DONE
||
150 (sccb
->evbuf
.hdr
.flags
& 0x80) == 0 || /* processed-buffer */
151 (sccb
->hdr
.response_code
& 0xffU
) != 0x20U
) {
156 free_page((unsigned long) sccb
);
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)
166 * Attention: Notice that this function is not reentrant - so the caller
167 * must ensure locking.
169 * Return: number of bytes read/written or a (negative) error code
171 ssize_t
sclp_ftp_cmd(const struct hmcdrv_ftp_cmdspec
*ftp
, size_t *fsize
)
175 unsigned long start_jiffies
;
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
;
182 init_completion(&sclp_ftp_rx_complete
);
184 /* Start ftp sclp command. */
185 len
= sclp_ftp_et7(ftp
);
190 * There is no way to cancel the sclp ET7 request, the code
191 * needs to wait unconditionally until the transfer is complete.
193 wait_for_completion(&sclp_ftp_rx_complete
);
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
);
202 switch (sclp_ftp_ldflg
) {
203 case SCLP_DIAG_FTP_OK
:
204 len
= sclp_ftp_length
;
206 *fsize
= sclp_ftp_fsize
;
208 case SCLP_DIAG_FTP_LDNPERM
:
211 case SCLP_DIAG_FTP_LDRUNS
:
214 case SCLP_DIAG_FTP_LDFAIL
:
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
,
238 * sclp_ftp_startup() - startup of FTP services, when running on LPAR
240 int sclp_ftp_startup(void)
247 rc
= sclp_register(&sclp_ftp_event
);
252 info
= get_zeroed_page(GFP_KERNEL
);
255 struct sysinfo_2_2_2
*info222
= (struct sysinfo_2_2_2
*)info
;
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
);
271 * sclp_ftp_shutdown() - shutdown of FTP services, when running on LPAR
273 void sclp_ftp_shutdown(void)
275 sclp_unregister(&sclp_ftp_event
);