xref: /OK3568_Linux_fs/kernel/drivers/s390/char/sclp_sdias.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * SCLP "store data in absolute storage"
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright IBM Corp. 2003, 2013
6*4882a593Smuzhiyun  * Author(s): Michael Holzheu
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #define KMSG_COMPONENT "sclp_sdias"
10*4882a593Smuzhiyun #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/completion.h>
13*4882a593Smuzhiyun #include <linux/sched.h>
14*4882a593Smuzhiyun #include <asm/sclp.h>
15*4882a593Smuzhiyun #include <asm/debug.h>
16*4882a593Smuzhiyun #include <asm/ipl.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include "sclp_sdias.h"
19*4882a593Smuzhiyun #include "sclp.h"
20*4882a593Smuzhiyun #include "sclp_rw.h"
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define TRACE(x...) debug_sprintf_event(sdias_dbf, 1, x)
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define SDIAS_RETRIES 300
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun static struct debug_info *sdias_dbf;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun static struct sclp_register sclp_sdias_register = {
29*4882a593Smuzhiyun 	.send_mask = EVTYP_SDIAS_MASK,
30*4882a593Smuzhiyun };
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun static struct sdias_sccb *sclp_sdias_sccb;
33*4882a593Smuzhiyun static struct sdias_evbuf sdias_evbuf;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun static DECLARE_COMPLETION(evbuf_accepted);
36*4882a593Smuzhiyun static DECLARE_COMPLETION(evbuf_done);
37*4882a593Smuzhiyun static DEFINE_MUTEX(sdias_mutex);
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun /*
40*4882a593Smuzhiyun  * Called by SCLP base when read event data has been completed (async mode only)
41*4882a593Smuzhiyun  */
sclp_sdias_receiver_fn(struct evbuf_header * evbuf)42*4882a593Smuzhiyun static void sclp_sdias_receiver_fn(struct evbuf_header *evbuf)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun 	memcpy(&sdias_evbuf, evbuf,
45*4882a593Smuzhiyun 	       min_t(unsigned long, sizeof(sdias_evbuf), evbuf->length));
46*4882a593Smuzhiyun 	complete(&evbuf_done);
47*4882a593Smuzhiyun 	TRACE("sclp_sdias_receiver_fn done\n");
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun /*
51*4882a593Smuzhiyun  * Called by SCLP base when sdias event has been accepted
52*4882a593Smuzhiyun  */
sdias_callback(struct sclp_req * request,void * data)53*4882a593Smuzhiyun static void sdias_callback(struct sclp_req *request, void *data)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	complete(&evbuf_accepted);
56*4882a593Smuzhiyun 	TRACE("callback done\n");
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun 
sdias_sclp_send(struct sclp_req * req)59*4882a593Smuzhiyun static int sdias_sclp_send(struct sclp_req *req)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun 	struct sdias_sccb *sccb = sclp_sdias_sccb;
62*4882a593Smuzhiyun 	int retries;
63*4882a593Smuzhiyun 	int rc;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	for (retries = SDIAS_RETRIES; retries; retries--) {
66*4882a593Smuzhiyun 		TRACE("add request\n");
67*4882a593Smuzhiyun 		rc = sclp_add_request(req);
68*4882a593Smuzhiyun 		if (rc) {
69*4882a593Smuzhiyun 			/* not initiated, wait some time and retry */
70*4882a593Smuzhiyun 			set_current_state(TASK_INTERRUPTIBLE);
71*4882a593Smuzhiyun 			TRACE("add request failed: rc = %i\n",rc);
72*4882a593Smuzhiyun 			schedule_timeout(msecs_to_jiffies(500));
73*4882a593Smuzhiyun 			continue;
74*4882a593Smuzhiyun 		}
75*4882a593Smuzhiyun 		/* initiated, wait for completion of service call */
76*4882a593Smuzhiyun 		wait_for_completion(&evbuf_accepted);
77*4882a593Smuzhiyun 		if (req->status == SCLP_REQ_FAILED) {
78*4882a593Smuzhiyun 			TRACE("sclp request failed\n");
79*4882a593Smuzhiyun 			continue;
80*4882a593Smuzhiyun 		}
81*4882a593Smuzhiyun 		/* if not accepted, retry */
82*4882a593Smuzhiyun 		if (!(sccb->evbuf.hdr.flags & 0x80)) {
83*4882a593Smuzhiyun 			TRACE("sclp request failed: flags=%x\n",
84*4882a593Smuzhiyun 			      sccb->evbuf.hdr.flags);
85*4882a593Smuzhiyun 			continue;
86*4882a593Smuzhiyun 		}
87*4882a593Smuzhiyun 		/*
88*4882a593Smuzhiyun 		 * for the sync interface the response is in the initial sccb
89*4882a593Smuzhiyun 		 */
90*4882a593Smuzhiyun 		if (!sclp_sdias_register.receiver_fn) {
91*4882a593Smuzhiyun 			memcpy(&sdias_evbuf, &sccb->evbuf, sizeof(sdias_evbuf));
92*4882a593Smuzhiyun 			TRACE("sync request done\n");
93*4882a593Smuzhiyun 			return 0;
94*4882a593Smuzhiyun 		}
95*4882a593Smuzhiyun 		/* otherwise we wait for completion */
96*4882a593Smuzhiyun 		wait_for_completion(&evbuf_done);
97*4882a593Smuzhiyun 		TRACE("request done\n");
98*4882a593Smuzhiyun 		return 0;
99*4882a593Smuzhiyun 	}
100*4882a593Smuzhiyun 	return -EIO;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun /*
104*4882a593Smuzhiyun  * Get number of blocks (4K) available in the HSA
105*4882a593Smuzhiyun  */
sclp_sdias_blk_count(void)106*4882a593Smuzhiyun int sclp_sdias_blk_count(void)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	struct sdias_sccb *sccb = sclp_sdias_sccb;
109*4882a593Smuzhiyun 	struct sclp_req request;
110*4882a593Smuzhiyun 	int rc;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	mutex_lock(&sdias_mutex);
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	memset(sccb, 0, sizeof(*sccb));
115*4882a593Smuzhiyun 	memset(&request, 0, sizeof(request));
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	sccb->hdr.length = sizeof(*sccb);
118*4882a593Smuzhiyun 	sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
119*4882a593Smuzhiyun 	sccb->evbuf.hdr.type = EVTYP_SDIAS;
120*4882a593Smuzhiyun 	sccb->evbuf.event_qual = SDIAS_EQ_SIZE;
121*4882a593Smuzhiyun 	sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
122*4882a593Smuzhiyun 	sccb->evbuf.event_id = 4712;
123*4882a593Smuzhiyun 	sccb->evbuf.dbs = 1;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	request.sccb = sccb;
126*4882a593Smuzhiyun 	request.command = SCLP_CMDW_WRITE_EVENT_DATA;
127*4882a593Smuzhiyun 	request.status = SCLP_REQ_FILLED;
128*4882a593Smuzhiyun 	request.callback = sdias_callback;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	rc = sdias_sclp_send(&request);
131*4882a593Smuzhiyun 	if (rc) {
132*4882a593Smuzhiyun 		pr_err("sclp_send failed for get_nr_blocks\n");
133*4882a593Smuzhiyun 		goto out;
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 	if (sccb->hdr.response_code != 0x0020) {
136*4882a593Smuzhiyun 		TRACE("send failed: %x\n", sccb->hdr.response_code);
137*4882a593Smuzhiyun 		rc = -EIO;
138*4882a593Smuzhiyun 		goto out;
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	switch (sdias_evbuf.event_status) {
142*4882a593Smuzhiyun 		case 0:
143*4882a593Smuzhiyun 			rc = sdias_evbuf.blk_cnt;
144*4882a593Smuzhiyun 			break;
145*4882a593Smuzhiyun 		default:
146*4882a593Smuzhiyun 			pr_err("SCLP error: %x\n", sdias_evbuf.event_status);
147*4882a593Smuzhiyun 			rc = -EIO;
148*4882a593Smuzhiyun 			goto out;
149*4882a593Smuzhiyun 	}
150*4882a593Smuzhiyun 	TRACE("%i blocks\n", rc);
151*4882a593Smuzhiyun out:
152*4882a593Smuzhiyun 	mutex_unlock(&sdias_mutex);
153*4882a593Smuzhiyun 	return rc;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun /*
157*4882a593Smuzhiyun  * Copy from HSA to absolute storage (not reentrant):
158*4882a593Smuzhiyun  *
159*4882a593Smuzhiyun  * @dest     : Address of buffer where data should be copied
160*4882a593Smuzhiyun  * @start_blk: Start Block (beginning with 1)
161*4882a593Smuzhiyun  * @nr_blks  : Number of 4K blocks to copy
162*4882a593Smuzhiyun  *
163*4882a593Smuzhiyun  * Return Value: 0 : Requested 'number' of blocks of data copied
164*4882a593Smuzhiyun  *		 <0: ERROR - negative event status
165*4882a593Smuzhiyun  */
sclp_sdias_copy(void * dest,int start_blk,int nr_blks)166*4882a593Smuzhiyun int sclp_sdias_copy(void *dest, int start_blk, int nr_blks)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun 	struct sdias_sccb *sccb = sclp_sdias_sccb;
169*4882a593Smuzhiyun 	struct sclp_req request;
170*4882a593Smuzhiyun 	int rc;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	mutex_lock(&sdias_mutex);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	memset(sccb, 0, sizeof(*sccb));
175*4882a593Smuzhiyun 	memset(&request, 0, sizeof(request));
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	sccb->hdr.length = sizeof(*sccb);
178*4882a593Smuzhiyun 	sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
179*4882a593Smuzhiyun 	sccb->evbuf.hdr.type = EVTYP_SDIAS;
180*4882a593Smuzhiyun 	sccb->evbuf.hdr.flags = 0;
181*4882a593Smuzhiyun 	sccb->evbuf.event_qual = SDIAS_EQ_STORE_DATA;
182*4882a593Smuzhiyun 	sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
183*4882a593Smuzhiyun 	sccb->evbuf.event_id = 4712;
184*4882a593Smuzhiyun 	sccb->evbuf.asa_size = SDIAS_ASA_SIZE_64;
185*4882a593Smuzhiyun 	sccb->evbuf.event_status = 0;
186*4882a593Smuzhiyun 	sccb->evbuf.blk_cnt = nr_blks;
187*4882a593Smuzhiyun 	sccb->evbuf.asa = (unsigned long)dest;
188*4882a593Smuzhiyun 	sccb->evbuf.fbn = start_blk;
189*4882a593Smuzhiyun 	sccb->evbuf.lbn = 0;
190*4882a593Smuzhiyun 	sccb->evbuf.dbs = 1;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	request.sccb	 = sccb;
193*4882a593Smuzhiyun 	request.command  = SCLP_CMDW_WRITE_EVENT_DATA;
194*4882a593Smuzhiyun 	request.status	 = SCLP_REQ_FILLED;
195*4882a593Smuzhiyun 	request.callback = sdias_callback;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	rc = sdias_sclp_send(&request);
198*4882a593Smuzhiyun 	if (rc) {
199*4882a593Smuzhiyun 		pr_err("sclp_send failed: %x\n", rc);
200*4882a593Smuzhiyun 		goto out;
201*4882a593Smuzhiyun 	}
202*4882a593Smuzhiyun 	if (sccb->hdr.response_code != 0x0020) {
203*4882a593Smuzhiyun 		TRACE("copy failed: %x\n", sccb->hdr.response_code);
204*4882a593Smuzhiyun 		rc = -EIO;
205*4882a593Smuzhiyun 		goto out;
206*4882a593Smuzhiyun 	}
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	switch (sdias_evbuf.event_status) {
209*4882a593Smuzhiyun 	case SDIAS_EVSTATE_ALL_STORED:
210*4882a593Smuzhiyun 		TRACE("all stored\n");
211*4882a593Smuzhiyun 		break;
212*4882a593Smuzhiyun 	case SDIAS_EVSTATE_PART_STORED:
213*4882a593Smuzhiyun 		TRACE("part stored: %i\n", sdias_evbuf.blk_cnt);
214*4882a593Smuzhiyun 		break;
215*4882a593Smuzhiyun 	case SDIAS_EVSTATE_NO_DATA:
216*4882a593Smuzhiyun 		TRACE("no data\n");
217*4882a593Smuzhiyun 		fallthrough;
218*4882a593Smuzhiyun 	default:
219*4882a593Smuzhiyun 		pr_err("Error from SCLP while copying hsa. Event status = %x\n",
220*4882a593Smuzhiyun 		       sdias_evbuf.event_status);
221*4882a593Smuzhiyun 		rc = -EIO;
222*4882a593Smuzhiyun 	}
223*4882a593Smuzhiyun out:
224*4882a593Smuzhiyun 	mutex_unlock(&sdias_mutex);
225*4882a593Smuzhiyun 	return rc;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
sclp_sdias_register_check(void)228*4882a593Smuzhiyun static int __init sclp_sdias_register_check(void)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	int rc;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	rc = sclp_register(&sclp_sdias_register);
233*4882a593Smuzhiyun 	if (rc)
234*4882a593Smuzhiyun 		return rc;
235*4882a593Smuzhiyun 	if (sclp_sdias_blk_count() == 0) {
236*4882a593Smuzhiyun 		sclp_unregister(&sclp_sdias_register);
237*4882a593Smuzhiyun 		return -ENODEV;
238*4882a593Smuzhiyun 	}
239*4882a593Smuzhiyun 	return 0;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun 
sclp_sdias_init_sync(void)242*4882a593Smuzhiyun static int __init sclp_sdias_init_sync(void)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun 	TRACE("Try synchronous mode\n");
245*4882a593Smuzhiyun 	sclp_sdias_register.receive_mask = 0;
246*4882a593Smuzhiyun 	sclp_sdias_register.receiver_fn = NULL;
247*4882a593Smuzhiyun 	return sclp_sdias_register_check();
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun 
sclp_sdias_init_async(void)250*4882a593Smuzhiyun static int __init sclp_sdias_init_async(void)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	TRACE("Try asynchronous mode\n");
253*4882a593Smuzhiyun 	sclp_sdias_register.receive_mask = EVTYP_SDIAS_MASK;
254*4882a593Smuzhiyun 	sclp_sdias_register.receiver_fn = sclp_sdias_receiver_fn;
255*4882a593Smuzhiyun 	return sclp_sdias_register_check();
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun 
sclp_sdias_init(void)258*4882a593Smuzhiyun int __init sclp_sdias_init(void)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun 	if (!is_ipl_type_dump())
261*4882a593Smuzhiyun 		return 0;
262*4882a593Smuzhiyun 	sclp_sdias_sccb = (void *) __get_free_page(GFP_KERNEL | GFP_DMA);
263*4882a593Smuzhiyun 	BUG_ON(!sclp_sdias_sccb);
264*4882a593Smuzhiyun 	sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long));
265*4882a593Smuzhiyun 	debug_register_view(sdias_dbf, &debug_sprintf_view);
266*4882a593Smuzhiyun 	debug_set_level(sdias_dbf, 6);
267*4882a593Smuzhiyun 	if (sclp_sdias_init_sync() == 0)
268*4882a593Smuzhiyun 		goto out;
269*4882a593Smuzhiyun 	if (sclp_sdias_init_async() == 0)
270*4882a593Smuzhiyun 		goto out;
271*4882a593Smuzhiyun 	TRACE("init failed\n");
272*4882a593Smuzhiyun 	free_page((unsigned long) sclp_sdias_sccb);
273*4882a593Smuzhiyun 	return -ENODEV;
274*4882a593Smuzhiyun out:
275*4882a593Smuzhiyun 	TRACE("init done\n");
276*4882a593Smuzhiyun 	return 0;
277*4882a593Smuzhiyun }
278