diff options
Diffstat (limited to 'drivers/s390/char/sclp_sdias.c')
-rw-r--r-- | drivers/s390/char/sclp_sdias.c | 107 |
1 files changed, 23 insertions, 84 deletions
diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c index b1032931a1c..fa733ecd3d7 100644 --- a/drivers/s390/char/sclp_sdias.c +++ b/drivers/s390/char/sclp_sdias.c | |||
@@ -1,14 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * Sclp "store data in absolut storage" | 2 | * Sclp "store data in absolut storage" |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2003, 2007 | 4 | * Copyright IBM Corp. 2003,2007 |
5 | * Author(s): Michael Holzheu | 5 | * Author(s): Michael Holzheu |
6 | */ | 6 | */ |
7 | 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> | ||
12 | #include <linux/sched.h> | 11 | #include <linux/sched.h> |
13 | #include <asm/sclp.h> | 12 | #include <asm/sclp.h> |
14 | #include <asm/debug.h> | 13 | #include <asm/debug.h> |
@@ -63,29 +62,15 @@ struct sdias_sccb { | |||
63 | } __attribute__((packed)); | 62 | } __attribute__((packed)); |
64 | 63 | ||
65 | static struct sdias_sccb sccb __attribute__((aligned(4096))); | 64 | static struct sdias_sccb sccb __attribute__((aligned(4096))); |
66 | static struct sdias_evbuf sdias_evbuf; | ||
67 | 65 | ||
68 | static DECLARE_COMPLETION(evbuf_accepted); | 66 | static int sclp_req_done; |
69 | static DECLARE_COMPLETION(evbuf_done); | 67 | static wait_queue_head_t sdias_wq; |
70 | static DEFINE_MUTEX(sdias_mutex); | 68 | static DEFINE_MUTEX(sdias_mutex); |
71 | 69 | ||
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 | */ | ||
86 | static void sdias_callback(struct sclp_req *request, void *data) | 70 | static void sdias_callback(struct sclp_req *request, void *data) |
87 | { | 71 | { |
88 | complete(&evbuf_accepted); | 72 | sclp_req_done = 1; |
73 | wake_up(&sdias_wq); /* Inform caller, that request is complete */ | ||
89 | TRACE("callback done\n"); | 74 | TRACE("callback done\n"); |
90 | } | 75 | } |
91 | 76 | ||
@@ -95,6 +80,7 @@ static int sdias_sclp_send(struct sclp_req *req) | |||
95 | int rc; | 80 | int rc; |
96 | 81 | ||
97 | for (retries = SDIAS_RETRIES; retries; retries--) { | 82 | for (retries = SDIAS_RETRIES; retries; retries--) { |
83 | sclp_req_done = 0; | ||
98 | TRACE("add request\n"); | 84 | TRACE("add request\n"); |
99 | rc = sclp_add_request(req); | 85 | rc = sclp_add_request(req); |
100 | if (rc) { | 86 | if (rc) { |
@@ -105,31 +91,16 @@ static int sdias_sclp_send(struct sclp_req *req) | |||
105 | continue; | 91 | continue; |
106 | } | 92 | } |
107 | /* initiated, wait for completion of service call */ | 93 | /* initiated, wait for completion of service call */ |
108 | wait_for_completion(&evbuf_accepted); | 94 | wait_event(sdias_wq, (sclp_req_done == 1)); |
109 | if (req->status == SCLP_REQ_FAILED) { | 95 | if (req->status == SCLP_REQ_FAILED) { |
110 | TRACE("sclp request failed\n"); | 96 | TRACE("sclp request failed\n"); |
97 | rc = -EIO; | ||
111 | continue; | 98 | continue; |
112 | } | 99 | } |
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); | ||
129 | TRACE("request done\n"); | 100 | TRACE("request done\n"); |
130 | return 0; | 101 | break; |
131 | } | 102 | } |
132 | return -EIO; | 103 | return rc; |
133 | } | 104 | } |
134 | 105 | ||
135 | /* | 106 | /* |
@@ -169,12 +140,13 @@ int sclp_sdias_blk_count(void) | |||
169 | goto out; | 140 | goto out; |
170 | } | 141 | } |
171 | 142 | ||
172 | switch (sdias_evbuf.event_status) { | 143 | switch (sccb.evbuf.event_status) { |
173 | case 0: | 144 | case 0: |
174 | rc = sdias_evbuf.blk_cnt; | 145 | rc = sccb.evbuf.blk_cnt; |
175 | break; | 146 | break; |
176 | default: | 147 | default: |
177 | pr_err("SCLP error: %x\n", sdias_evbuf.event_status); | 148 | pr_err("SCLP error: %x\n", |
149 | sccb.evbuf.event_status); | ||
178 | rc = -EIO; | 150 | rc = -EIO; |
179 | goto out; | 151 | goto out; |
180 | } | 152 | } |
@@ -211,7 +183,7 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks) | |||
211 | sccb.evbuf.event_qual = EQ_STORE_DATA; | 183 | sccb.evbuf.event_qual = EQ_STORE_DATA; |
212 | sccb.evbuf.data_id = DI_FCP_DUMP; | 184 | sccb.evbuf.data_id = DI_FCP_DUMP; |
213 | sccb.evbuf.event_id = 4712; | 185 | sccb.evbuf.event_id = 4712; |
214 | #ifdef CONFIG_64BIT | 186 | #ifdef __s390x__ |
215 | sccb.evbuf.asa_size = ASA_SIZE_64; | 187 | sccb.evbuf.asa_size = ASA_SIZE_64; |
216 | #else | 188 | #else |
217 | sccb.evbuf.asa_size = ASA_SIZE_32; | 189 | sccb.evbuf.asa_size = ASA_SIZE_32; |
@@ -239,20 +211,18 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks) | |||
239 | goto out; | 211 | goto out; |
240 | } | 212 | } |
241 | 213 | ||
242 | switch (sdias_evbuf.event_status) { | 214 | switch (sccb.evbuf.event_status) { |
243 | case EVSTATE_ALL_STORED: | 215 | case EVSTATE_ALL_STORED: |
244 | TRACE("all stored\n"); | 216 | TRACE("all stored\n"); |
245 | break; | ||
246 | case EVSTATE_PART_STORED: | 217 | case EVSTATE_PART_STORED: |
247 | TRACE("part stored: %i\n", sdias_evbuf.blk_cnt); | 218 | TRACE("part stored: %i\n", sccb.evbuf.blk_cnt); |
248 | break; | 219 | break; |
249 | case EVSTATE_NO_DATA: | 220 | case EVSTATE_NO_DATA: |
250 | TRACE("no data\n"); | 221 | TRACE("no data\n"); |
251 | /* fall through */ | ||
252 | default: | 222 | default: |
253 | pr_err("Error from SCLP while copying hsa. " | 223 | pr_err("Error from SCLP while copying hsa. " |
254 | "Event status = %x\n", | 224 | "Event status = %x\n", |
255 | sdias_evbuf.event_status); | 225 | sccb.evbuf.event_status); |
256 | rc = -EIO; | 226 | rc = -EIO; |
257 | } | 227 | } |
258 | out: | 228 | out: |
@@ -260,50 +230,19 @@ out: | |||
260 | return rc; | 230 | return rc; |
261 | } | 231 | } |
262 | 232 | ||
263 | static int __init sclp_sdias_register_check(void) | 233 | int __init sclp_sdias_init(void) |
264 | { | 234 | { |
265 | int rc; | 235 | int rc; |
266 | 236 | ||
267 | rc = sclp_register(&sclp_sdias_register); | ||
268 | if (rc) | ||
269 | return rc; | ||
270 | if (sclp_sdias_blk_count() == 0) { | ||
271 | sclp_unregister(&sclp_sdias_register); | ||
272 | return -ENODEV; | ||
273 | } | ||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | static int __init sclp_sdias_init_sync(void) | ||
278 | { | ||
279 | TRACE("Try synchronous mode\n"); | ||
280 | sclp_sdias_register.receive_mask = 0; | ||
281 | sclp_sdias_register.receiver_fn = NULL; | ||
282 | return sclp_sdias_register_check(); | ||
283 | } | ||
284 | |||
285 | static int __init sclp_sdias_init_async(void) | ||
286 | { | ||
287 | TRACE("Try asynchronous mode\n"); | ||
288 | sclp_sdias_register.receive_mask = EVTYP_SDIAS_MASK; | ||
289 | sclp_sdias_register.receiver_fn = sclp_sdias_receiver_fn; | ||
290 | return sclp_sdias_register_check(); | ||
291 | } | ||
292 | |||
293 | int __init sclp_sdias_init(void) | ||
294 | { | ||
295 | if (ipl_info.type != IPL_TYPE_FCP_DUMP) | 237 | if (ipl_info.type != IPL_TYPE_FCP_DUMP) |
296 | return 0; | 238 | return 0; |
297 | sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long)); | 239 | sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long)); |
298 | debug_register_view(sdias_dbf, &debug_sprintf_view); | 240 | debug_register_view(sdias_dbf, &debug_sprintf_view); |
299 | debug_set_level(sdias_dbf, 6); | 241 | debug_set_level(sdias_dbf, 6); |
300 | if (sclp_sdias_init_sync() == 0) | 242 | rc = sclp_register(&sclp_sdias_register); |
301 | goto out; | 243 | if (rc) |
302 | if (sclp_sdias_init_async() == 0) | 244 | return rc; |
303 | goto out; | 245 | init_waitqueue_head(&sdias_wq); |
304 | TRACE("init failed\n"); | ||
305 | return -ENODEV; | ||
306 | out: | ||
307 | TRACE("init done\n"); | 246 | TRACE("init done\n"); |
308 | return 0; | 247 | return 0; |
309 | } | 248 | } |