Merge branches 'core-fixes-for-linus' and 'irq-fixes-for-linus' of git://git.kernel...
[pandora-kernel.git] / drivers / s390 / char / sclp_sdias.c
1 /*
2  * Sclp "store data in absolut storage"
3  *
4  * Copyright IBM Corp. 2003,2007
5  * Author(s): Michael Holzheu
6  */
7
8 #define KMSG_COMPONENT "sclp_sdias"
9 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
10
11 #include <linux/sched.h>
12 #include <asm/sclp.h>
13 #include <asm/debug.h>
14 #include <asm/ipl.h>
15
16 #include "sclp.h"
17 #include "sclp_rw.h"
18
19 #define TRACE(x...) debug_sprintf_event(sdias_dbf, 1, x)
20
21 #define SDIAS_RETRIES 300
22 #define SDIAS_SLEEP_TICKS 50
23
24 #define EQ_STORE_DATA   0x0
25 #define EQ_SIZE         0x1
26 #define DI_FCP_DUMP     0x0
27 #define ASA_SIZE_32     0x0
28 #define ASA_SIZE_64     0x1
29 #define EVSTATE_ALL_STORED      0x0
30 #define EVSTATE_NO_DATA         0x3
31 #define EVSTATE_PART_STORED     0x10
32
33 static struct debug_info *sdias_dbf;
34
35 static struct sclp_register sclp_sdias_register = {
36         .send_mask = EVTYP_SDIAS_MASK,
37 };
38
39 struct sdias_evbuf {
40         struct  evbuf_header hdr;
41         u8      event_qual;
42         u8      data_id;
43         u64     reserved2;
44         u32     event_id;
45         u16     reserved3;
46         u8      asa_size;
47         u8      event_status;
48         u32     reserved4;
49         u32     blk_cnt;
50         u64     asa;
51         u32     reserved5;
52         u32     fbn;
53         u32     reserved6;
54         u32     lbn;
55         u16     reserved7;
56         u16     dbs;
57 } __attribute__((packed));
58
59 struct sdias_sccb {
60         struct sccb_header  hdr;
61         struct sdias_evbuf  evbuf;
62 } __attribute__((packed));
63
64 static struct sdias_sccb sccb __attribute__((aligned(4096)));
65
66 static int sclp_req_done;
67 static wait_queue_head_t sdias_wq;
68 static DEFINE_MUTEX(sdias_mutex);
69
70 static void sdias_callback(struct sclp_req *request, void *data)
71 {
72         sclp_req_done = 1;
73         wake_up(&sdias_wq); /* Inform caller, that request is complete */
74         TRACE("callback done\n");
75 }
76
77 static int sdias_sclp_send(struct sclp_req *req)
78 {
79         int retries;
80         int rc;
81
82         for (retries = SDIAS_RETRIES; retries; retries--) {
83                 sclp_req_done = 0;
84                 TRACE("add request\n");
85                 rc = sclp_add_request(req);
86                 if (rc) {
87                         /* not initiated, wait some time and retry */
88                         set_current_state(TASK_INTERRUPTIBLE);
89                         TRACE("add request failed: rc = %i\n",rc);
90                         schedule_timeout(SDIAS_SLEEP_TICKS);
91                         continue;
92                 }
93                 /* initiated, wait for completion of service call */
94                 wait_event(sdias_wq, (sclp_req_done == 1));
95                 if (req->status == SCLP_REQ_FAILED) {
96                         TRACE("sclp request failed\n");
97                         rc = -EIO;
98                         continue;
99                 }
100                 TRACE("request done\n");
101                 break;
102         }
103         return rc;
104 }
105
106 /*
107  * Get number of blocks (4K) available in the HSA
108  */
109 int sclp_sdias_blk_count(void)
110 {
111         struct sclp_req request;
112         int rc;
113
114         mutex_lock(&sdias_mutex);
115
116         memset(&sccb, 0, sizeof(sccb));
117         memset(&request, 0, sizeof(request));
118
119         sccb.hdr.length = sizeof(sccb);
120         sccb.evbuf.hdr.length = sizeof(struct sdias_evbuf);
121         sccb.evbuf.hdr.type = EVTYP_SDIAS;
122         sccb.evbuf.event_qual = EQ_SIZE;
123         sccb.evbuf.data_id = DI_FCP_DUMP;
124         sccb.evbuf.event_id = 4712;
125         sccb.evbuf.dbs = 1;
126
127         request.sccb = &sccb;
128         request.command = SCLP_CMDW_WRITE_EVENT_DATA;
129         request.status = SCLP_REQ_FILLED;
130         request.callback = sdias_callback;
131
132         rc = sdias_sclp_send(&request);
133         if (rc) {
134                 pr_err("sclp_send failed for get_nr_blocks\n");
135                 goto out;
136         }
137         if (sccb.hdr.response_code != 0x0020) {
138                 TRACE("send failed: %x\n", sccb.hdr.response_code);
139                 rc = -EIO;
140                 goto out;
141         }
142
143         switch (sccb.evbuf.event_status) {
144                 case 0:
145                         rc = sccb.evbuf.blk_cnt;
146                         break;
147                 default:
148                         pr_err("SCLP error: %x\n",
149                                sccb.evbuf.event_status);
150                         rc = -EIO;
151                         goto out;
152         }
153         TRACE("%i blocks\n", rc);
154 out:
155         mutex_unlock(&sdias_mutex);
156         return rc;
157 }
158
159 /*
160  * Copy from HSA to absolute storage (not reentrant):
161  *
162  * @dest     : Address of buffer where data should be copied
163  * @start_blk: Start Block (beginning with 1)
164  * @nr_blks  : Number of 4K blocks to copy
165  *
166  * Return Value: 0 : Requested 'number' of blocks of data copied
167  *               <0: ERROR - negative event status
168  */
169 int sclp_sdias_copy(void *dest, int start_blk, int nr_blks)
170 {
171         struct sclp_req request;
172         int rc;
173
174         mutex_lock(&sdias_mutex);
175
176         memset(&sccb, 0, sizeof(sccb));
177         memset(&request, 0, sizeof(request));
178
179         sccb.hdr.length = sizeof(sccb);
180         sccb.evbuf.hdr.length = sizeof(struct sdias_evbuf);
181         sccb.evbuf.hdr.type = EVTYP_SDIAS;
182         sccb.evbuf.hdr.flags = 0;
183         sccb.evbuf.event_qual = EQ_STORE_DATA;
184         sccb.evbuf.data_id = DI_FCP_DUMP;
185         sccb.evbuf.event_id = 4712;
186 #ifdef __s390x__
187         sccb.evbuf.asa_size = ASA_SIZE_64;
188 #else
189         sccb.evbuf.asa_size = ASA_SIZE_32;
190 #endif
191         sccb.evbuf.event_status = 0;
192         sccb.evbuf.blk_cnt = nr_blks;
193         sccb.evbuf.asa = (unsigned long)dest;
194         sccb.evbuf.fbn = start_blk;
195         sccb.evbuf.lbn = 0;
196         sccb.evbuf.dbs = 1;
197
198         request.sccb     = &sccb;
199         request.command  = SCLP_CMDW_WRITE_EVENT_DATA;
200         request.status   = SCLP_REQ_FILLED;
201         request.callback = sdias_callback;
202
203         rc = sdias_sclp_send(&request);
204         if (rc) {
205                 pr_err("sclp_send failed: %x\n", rc);
206                 goto out;
207         }
208         if (sccb.hdr.response_code != 0x0020) {
209                 TRACE("copy failed: %x\n", sccb.hdr.response_code);
210                 rc = -EIO;
211                 goto out;
212         }
213
214         switch (sccb.evbuf.event_status) {
215                 case EVSTATE_ALL_STORED:
216                         TRACE("all stored\n");
217                 case EVSTATE_PART_STORED:
218                         TRACE("part stored: %i\n", sccb.evbuf.blk_cnt);
219                         break;
220                 case EVSTATE_NO_DATA:
221                         TRACE("no data\n");
222                 default:
223                         pr_err("Error from SCLP while copying hsa. "
224                                "Event status = %x\n",
225                                sccb.evbuf.event_status);
226                         rc = -EIO;
227         }
228 out:
229         mutex_unlock(&sdias_mutex);
230         return rc;
231 }
232
233 int __init sclp_sdias_init(void)
234 {
235         int rc;
236
237         if (ipl_info.type != IPL_TYPE_FCP_DUMP)
238                 return 0;
239         sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long));
240         debug_register_view(sdias_dbf, &debug_sprintf_view);
241         debug_set_level(sdias_dbf, 6);
242         rc = sclp_register(&sclp_sdias_register);
243         if (rc)
244                 return rc;
245         init_waitqueue_head(&sdias_wq);
246         TRACE("init done\n");
247         return 0;
248 }
249
250 void __exit sclp_sdias_exit(void)
251 {
252         debug_unregister(sdias_dbf);
253         sclp_unregister(&sclp_sdias_register);
254 }