aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMichael Holzheu <holzheu@linux.vnet.ibm.com>2012-03-11 11:59:29 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-03-11 11:59:28 -0400
commite3c652b533aab733bf3ffb50654fb82f079c5329 (patch)
tree9fa45cd1fdd6466a0ceb7e9606c0082194b72e2c /drivers
parentb43445ff6c514822979cc9ae02c76f98bf68721c (diff)
[S390] zfcpdump: Implement async sdias event processing
There are two different ways to do the "store data in absolute storage" SCLP event processing, synchronous and asynchrounous. This patch adds the asynchronous variant. Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers')
-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}