aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/char')
-rw-r--r--drivers/s390/char/sclp_sdias.c101
1 files changed, 80 insertions, 21 deletions
diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c
index fa733ecd3d70..69e6c50d4cfb 100644
--- a/drivers/s390/char/sclp_sdias.c
+++ b/drivers/s390/char/sclp_sdias.c
@@ -8,6 +8,7 @@
8#define KMSG_COMPONENT "sclp_sdias" 8#define KMSG_COMPONENT "sclp_sdias"
9#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 9#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
10 10
11#include <linux/completion.h>
11#include <linux/sched.h> 12#include <linux/sched.h>
12#include <asm/sclp.h> 13#include <asm/sclp.h>
13#include <asm/debug.h> 14#include <asm/debug.h>
@@ -62,15 +63,29 @@ struct sdias_sccb {
62} __attribute__((packed)); 63} __attribute__((packed));
63 64
64static struct sdias_sccb sccb __attribute__((aligned(4096))); 65static struct sdias_sccb sccb __attribute__((aligned(4096)));
66static struct sdias_evbuf sdias_evbuf;
65 67
66static int sclp_req_done; 68static DECLARE_COMPLETION(evbuf_accepted);
67static wait_queue_head_t sdias_wq; 69static DECLARE_COMPLETION(evbuf_done);
68static DEFINE_MUTEX(sdias_mutex); 70static DEFINE_MUTEX(sdias_mutex);
69 71
72/*
73 * Called by SCLP base when read event data has been completed (async mode only)
74 */
75static void sclp_sdias_receiver_fn(struct evbuf_header *evbuf)
76{
77 memcpy(&sdias_evbuf, evbuf,
78 min_t(unsigned long, sizeof(sdias_evbuf), evbuf->length));
79 complete(&evbuf_done);
80 TRACE("sclp_sdias_receiver_fn done\n");
81}
82
83/*
84 * Called by SCLP base when sdias event has been accepted
85 */
70static void sdias_callback(struct sclp_req *request, void *data) 86static void sdias_callback(struct sclp_req *request, void *data)
71{ 87{
72 sclp_req_done = 1; 88 complete(&evbuf_accepted);
73 wake_up(&sdias_wq); /* Inform caller, that request is complete */
74 TRACE("callback done\n"); 89 TRACE("callback done\n");
75} 90}
76 91
@@ -80,7 +95,6 @@ static int sdias_sclp_send(struct sclp_req *req)
80 int rc; 95 int rc;
81 96
82 for (retries = SDIAS_RETRIES; retries; retries--) { 97 for (retries = SDIAS_RETRIES; retries; retries--) {
83 sclp_req_done = 0;
84 TRACE("add request\n"); 98 TRACE("add request\n");
85 rc = sclp_add_request(req); 99 rc = sclp_add_request(req);
86 if (rc) { 100 if (rc) {
@@ -91,16 +105,31 @@ static int sdias_sclp_send(struct sclp_req *req)
91 continue; 105 continue;
92 } 106 }
93 /* initiated, wait for completion of service call */ 107 /* initiated, wait for completion of service call */
94 wait_event(sdias_wq, (sclp_req_done == 1)); 108 wait_for_completion(&evbuf_accepted);
95 if (req->status == SCLP_REQ_FAILED) { 109 if (req->status == SCLP_REQ_FAILED) {
96 TRACE("sclp request failed\n"); 110 TRACE("sclp request failed\n");
97 rc = -EIO;
98 continue; 111 continue;
99 } 112 }
113 /* if not accepted, retry */
114 if (!(sccb.evbuf.hdr.flags & 0x80)) {
115 TRACE("sclp request failed: flags=%x\n",
116 sccb.evbuf.hdr.flags);
117 continue;
118 }
119 /*
120 * for the sync interface the response is in the initial sccb
121 */
122 if (!sclp_sdias_register.receiver_fn) {
123 memcpy(&sdias_evbuf, &sccb.evbuf, sizeof(sdias_evbuf));
124 TRACE("sync request done\n");
125 return 0;
126 }
127 /* otherwise we wait for completion */
128 wait_for_completion(&evbuf_done);
100 TRACE("request done\n"); 129 TRACE("request done\n");
101 break; 130 return 0;
102 } 131 }
103 return rc; 132 return -EIO;
104} 133}
105 134
106/* 135/*
@@ -140,13 +169,12 @@ int sclp_sdias_blk_count(void)
140 goto out; 169 goto out;
141 } 170 }
142 171
143 switch (sccb.evbuf.event_status) { 172 switch (sdias_evbuf.event_status) {
144 case 0: 173 case 0:
145 rc = sccb.evbuf.blk_cnt; 174 rc = sdias_evbuf.blk_cnt;
146 break; 175 break;
147 default: 176 default:
148 pr_err("SCLP error: %x\n", 177 pr_err("SCLP error: %x\n", sdias_evbuf.event_status);
149 sccb.evbuf.event_status);
150 rc = -EIO; 178 rc = -EIO;
151 goto out; 179 goto out;
152 } 180 }
@@ -211,18 +239,18 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks)
211 goto out; 239 goto out;
212 } 240 }
213 241
214 switch (sccb.evbuf.event_status) { 242 switch (sdias_evbuf.event_status) {
215 case EVSTATE_ALL_STORED: 243 case EVSTATE_ALL_STORED:
216 TRACE("all stored\n"); 244 TRACE("all stored\n");
217 case EVSTATE_PART_STORED: 245 case EVSTATE_PART_STORED:
218 TRACE("part stored: %i\n", sccb.evbuf.blk_cnt); 246 TRACE("part stored: %i\n", sdias_evbuf.blk_cnt);
219 break; 247 break;
220 case EVSTATE_NO_DATA: 248 case EVSTATE_NO_DATA:
221 TRACE("no data\n"); 249 TRACE("no data\n");
222 default: 250 default:
223 pr_err("Error from SCLP while copying hsa. " 251 pr_err("Error from SCLP while copying hsa. "
224 "Event status = %x\n", 252 "Event status = %x\n",
225 sccb.evbuf.event_status); 253 sdias_evbuf.event_status);
226 rc = -EIO; 254 rc = -EIO;
227 } 255 }
228out: 256out:
@@ -230,19 +258,50 @@ out:
230 return rc; 258 return rc;
231} 259}
232 260
233int __init sclp_sdias_init(void) 261static int __init sclp_sdias_register_check(void)
234{ 262{
235 int rc; 263 int rc;
236 264
265 rc = sclp_register(&sclp_sdias_register);
266 if (rc)
267 return rc;
268 if (sclp_sdias_blk_count() == 0) {
269 sclp_unregister(&sclp_sdias_register);
270 return -ENODEV;
271 }
272 return 0;
273}
274
275static int __init sclp_sdias_init_sync(void)
276{
277 TRACE("Try synchronous mode\n");
278 sclp_sdias_register.receive_mask = 0;
279 sclp_sdias_register.receiver_fn = NULL;
280 return sclp_sdias_register_check();
281}
282
283static int __init sclp_sdias_init_async(void)
284{
285 TRACE("Try asynchronous mode\n");
286 sclp_sdias_register.receive_mask = EVTYP_SDIAS_MASK;
287 sclp_sdias_register.receiver_fn = sclp_sdias_receiver_fn;
288 return sclp_sdias_register_check();
289}
290
291int __init sclp_sdias_init(void)
292{
237 if (ipl_info.type != IPL_TYPE_FCP_DUMP) 293 if (ipl_info.type != IPL_TYPE_FCP_DUMP)
238 return 0; 294 return 0;
239 sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long)); 295 sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long));
240 debug_register_view(sdias_dbf, &debug_sprintf_view); 296 debug_register_view(sdias_dbf, &debug_sprintf_view);
241 debug_set_level(sdias_dbf, 6); 297 debug_set_level(sdias_dbf, 6);
242 rc = sclp_register(&sclp_sdias_register); 298 if (sclp_sdias_init_sync() == 0)
243 if (rc) 299 goto out;
244 return rc; 300 if (sclp_sdias_init_async() == 0)
245 init_waitqueue_head(&sdias_wq); 301 goto out;
302 TRACE("init failed\n");
303 return -ENODEV;
304out:
246 TRACE("init done\n"); 305 TRACE("init done\n");
247 return 0; 306 return 0;
248} 307}