Pull percpu-dtc into release branch
[linux-2.6] / 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 #include <linux/sched.h>
9 #include <asm/sclp.h>
10 #include <asm/debug.h>
11 #include <asm/ipl.h>
12 #include "sclp.h"
13 #include "sclp_rw.h"
14
15 #define TRACE(x...) debug_sprintf_event(sdias_dbf, 1, x)
16 #define ERROR_MSG(x...) printk ( KERN_ALERT "SDIAS: " x )
17
18 #define SDIAS_RETRIES 300
19 #define SDIAS_SLEEP_TICKS 50
20
21 #define EQ_STORE_DATA   0x0
22 #define EQ_SIZE         0x1
23 #define DI_FCP_DUMP     0x0
24 #define ASA_SIZE_32     0x0
25 #define ASA_SIZE_64     0x1
26 #define EVSTATE_ALL_STORED      0x0
27 #define EVSTATE_NO_DATA         0x3
28 #define EVSTATE_PART_STORED     0x10
29
30 static struct debug_info *sdias_dbf;
31
32 static struct sclp_register sclp_sdias_register = {
33         .send_mask = EVTYP_SDIAS_MASK,
34 };
35
36 struct sdias_evbuf {
37         struct  evbuf_header hdr;
38         u8      event_qual;
39         u8      data_id;
40         u64     reserved2;
41         u32     event_id;
42         u16     reserved3;
43         u8      asa_size;
44         u8      event_status;
45         u32     reserved4;
46         u32     blk_cnt;
47         u64     asa;
48         u32     reserved5;
49         u32     fbn;
50         u32     reserved6;
51         u32     lbn;
52         u16     reserved7;
53         u16     dbs;
54 } __attribute__((packed));
55
56 struct sdias_sccb {
57         struct sccb_header  hdr;
58         struct sdias_evbuf  evbuf;
59 } __attribute__((packed));
60
61 static struct sdias_sccb sccb __attribute__((aligned(4096)));
62
63 static int sclp_req_done;
64 static wait_queue_head_t sdias_wq;
65 static DEFINE_MUTEX(sdias_mutex);
66
67 static void sdias_callback(struct sclp_req *request, void *data)
68 {
69         struct sdias_sccb *sccb;
70
71         sccb = (struct sdias_sccb *) request->sccb;
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                 ERROR_MSG("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                         ERROR_MSG("SCLP error: %x\n", sccb.evbuf.event_status);
149                         rc = -EIO;
150                         goto out;
151         }
152         TRACE("%i blocks\n", rc);
153 out:
154         mutex_unlock(&sdias_mutex);
155         return rc;
156 }
157
158 /*
159  * Copy from HSA to absolute storage (not reentrant):
160  *
161  * @dest     : Address of buffer where data should be copied
162  * @start_blk: Start Block (beginning with 1)
163  * @nr_blks  : Number of 4K blocks to copy
164  *
165  * Return Value: 0 : Requested 'number' of blocks of data copied
166  *               <0: ERROR - negative event status
167  */
168 int sclp_sdias_copy(void *dest, int start_blk, int nr_blks)
169 {
170         struct sclp_req request;
171         int rc;
172
173         mutex_lock(&sdias_mutex);
174
175         memset(&sccb, 0, sizeof(sccb));
176         memset(&request, 0, sizeof(request));
177
178         sccb.hdr.length = sizeof(sccb);
179         sccb.evbuf.hdr.length = sizeof(struct sdias_evbuf);
180         sccb.evbuf.hdr.type = EVTYP_SDIAS;
181         sccb.evbuf.hdr.flags = 0;
182         sccb.evbuf.event_qual = EQ_STORE_DATA;
183         sccb.evbuf.data_id = DI_FCP_DUMP;
184         sccb.evbuf.event_id = 4712;
185 #ifdef __s390x__
186         sccb.evbuf.asa_size = ASA_SIZE_64;
187 #else
188         sccb.evbuf.asa_size = ASA_SIZE_32;
189 #endif
190         sccb.evbuf.event_status = 0;
191         sccb.evbuf.blk_cnt = nr_blks;
192         sccb.evbuf.asa = (unsigned long)dest;
193         sccb.evbuf.fbn = start_blk;
194         sccb.evbuf.lbn = 0;
195         sccb.evbuf.dbs = 1;
196
197         request.sccb     = &sccb;
198         request.command  = SCLP_CMDW_WRITE_EVENT_DATA;
199         request.status   = SCLP_REQ_FILLED;
200         request.callback = sdias_callback;
201
202         rc = sdias_sclp_send(&request);
203         if (rc) {
204                 ERROR_MSG("sclp_send failed: %x\n", rc);
205                 goto out;
206         }
207         if (sccb.hdr.response_code != 0x0020) {
208                 TRACE("copy failed: %x\n", sccb.hdr.response_code);
209                 rc = -EIO;
210                 goto out;
211         }
212
213         switch (sccb.evbuf.event_status) {
214                 case EVSTATE_ALL_STORED:
215                         TRACE("all stored\n");
216                 case EVSTATE_PART_STORED:
217                         TRACE("part stored: %i\n", sccb.evbuf.blk_cnt);
218                         break;
219                 case EVSTATE_NO_DATA:
220                         TRACE("no data\n");
221                 default:
222                         ERROR_MSG("Error from SCLP while copying hsa. "
223                                   "Event status = %x\n",
224                                 sccb.evbuf.event_status);
225                         rc = -EIO;
226         }
227 out:
228         mutex_unlock(&sdias_mutex);
229         return rc;
230 }
231
232 int __init sdias_init(void)
233 {
234         int rc;
235
236         if (ipl_info.type != IPL_TYPE_FCP_DUMP)
237                 return 0;
238         sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long));
239         debug_register_view(sdias_dbf, &debug_sprintf_view);
240         debug_set_level(sdias_dbf, 6);
241         rc = sclp_register(&sclp_sdias_register);
242         if (rc) {
243                 ERROR_MSG("sclp register failed\n");
244                 return rc;
245         }
246         init_waitqueue_head(&sdias_wq);
247         TRACE("init done\n");
248         return 0;
249 }
250
251 void __exit sdias_exit(void)
252 {
253         debug_unregister(sdias_dbf);
254         sclp_unregister(&sclp_sdias_register);
255 }