diff options
author | Michael Holzheu <holzheu@linux.vnet.ibm.com> | 2012-03-11 11:59:29 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-03-11 11:59:28 -0400 |
commit | e3c652b533aab733bf3ffb50654fb82f079c5329 (patch) | |
tree | 9fa45cd1fdd6466a0ceb7e9606c0082194b72e2c /drivers/s390/char | |
parent | b43445ff6c514822979cc9ae02c76f98bf68721c (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/s390/char')
-rw-r--r-- | drivers/s390/char/sclp_sdias.c | 101 |
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 | ||
64 | static struct sdias_sccb sccb __attribute__((aligned(4096))); | 65 | static struct sdias_sccb sccb __attribute__((aligned(4096))); |
66 | static struct sdias_evbuf sdias_evbuf; | ||
65 | 67 | ||
66 | static int sclp_req_done; | 68 | static DECLARE_COMPLETION(evbuf_accepted); |
67 | static wait_queue_head_t sdias_wq; | 69 | static DECLARE_COMPLETION(evbuf_done); |
68 | static DEFINE_MUTEX(sdias_mutex); | 70 | static DEFINE_MUTEX(sdias_mutex); |
69 | 71 | ||
72 | /* | ||
73 | * Called by SCLP base when read event data has been completed (async mode only) | ||
74 | */ | ||
75 | static 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 | */ | ||
70 | static void sdias_callback(struct sclp_req *request, void *data) | 86 | static 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 | } |
228 | out: | 256 | out: |
@@ -230,19 +258,50 @@ out: | |||
230 | return rc; | 258 | return rc; |
231 | } | 259 | } |
232 | 260 | ||
233 | int __init sclp_sdias_init(void) | 261 | static 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 | |||
275 | static 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 | |||
283 | static 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 | |||
291 | int __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; | ||
304 | out: | ||
246 | TRACE("init done\n"); | 305 | TRACE("init done\n"); |
247 | return 0; | 306 | return 0; |
248 | } | 307 | } |