]>
Commit | Line | Data |
---|---|---|
411ed322 MH |
1 | /* |
2 | * Sclp "store data in absolut storage" | |
3 | * | |
4 | * Copyright IBM Corp. 2003,2007 | |
5 | * Author(s): Michael Holzheu | |
6 | */ | |
7 | ||
b3ff088b MS |
8 | #define KMSG_COMPONENT "sclp_sdias" |
9 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | |
10 | ||
411ed322 MH |
11 | #include <linux/sched.h> |
12 | #include <asm/sclp.h> | |
13 | #include <asm/debug.h> | |
14 | #include <asm/ipl.h> | |
b3ff088b | 15 | |
411ed322 MH |
16 | #include "sclp.h" |
17 | #include "sclp_rw.h" | |
18 | ||
19 | #define TRACE(x...) debug_sprintf_event(sdias_dbf, 1, x) | |
411ed322 MH |
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 = { | |
6d4740c8 | 36 | .send_mask = EVTYP_SDIAS_MASK, |
411ed322 MH |
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 | { | |
763968e2 | 72 | struct sdias_sccb *cbsccb; |
411ed322 | 73 | |
763968e2 | 74 | cbsccb = (struct sdias_sccb *) request->sccb; |
411ed322 MH |
75 | sclp_req_done = 1; |
76 | wake_up(&sdias_wq); /* Inform caller, that request is complete */ | |
77 | TRACE("callback done\n"); | |
78 | } | |
79 | ||
80 | static int sdias_sclp_send(struct sclp_req *req) | |
81 | { | |
82 | int retries; | |
83 | int rc; | |
84 | ||
85 | for (retries = SDIAS_RETRIES; retries; retries--) { | |
86 | sclp_req_done = 0; | |
87 | TRACE("add request\n"); | |
88 | rc = sclp_add_request(req); | |
89 | if (rc) { | |
90 | /* not initiated, wait some time and retry */ | |
91 | set_current_state(TASK_INTERRUPTIBLE); | |
92 | TRACE("add request failed: rc = %i\n",rc); | |
93 | schedule_timeout(SDIAS_SLEEP_TICKS); | |
94 | continue; | |
95 | } | |
96 | /* initiated, wait for completion of service call */ | |
97 | wait_event(sdias_wq, (sclp_req_done == 1)); | |
98 | if (req->status == SCLP_REQ_FAILED) { | |
99 | TRACE("sclp request failed\n"); | |
100 | rc = -EIO; | |
101 | continue; | |
102 | } | |
103 | TRACE("request done\n"); | |
104 | break; | |
105 | } | |
106 | return rc; | |
107 | } | |
108 | ||
109 | /* | |
110 | * Get number of blocks (4K) available in the HSA | |
111 | */ | |
112 | int sclp_sdias_blk_count(void) | |
113 | { | |
114 | struct sclp_req request; | |
115 | int rc; | |
116 | ||
117 | mutex_lock(&sdias_mutex); | |
118 | ||
119 | memset(&sccb, 0, sizeof(sccb)); | |
120 | memset(&request, 0, sizeof(request)); | |
121 | ||
122 | sccb.hdr.length = sizeof(sccb); | |
123 | sccb.evbuf.hdr.length = sizeof(struct sdias_evbuf); | |
6d4740c8 | 124 | sccb.evbuf.hdr.type = EVTYP_SDIAS; |
411ed322 MH |
125 | sccb.evbuf.event_qual = EQ_SIZE; |
126 | sccb.evbuf.data_id = DI_FCP_DUMP; | |
127 | sccb.evbuf.event_id = 4712; | |
128 | sccb.evbuf.dbs = 1; | |
129 | ||
130 | request.sccb = &sccb; | |
131 | request.command = SCLP_CMDW_WRITE_EVENT_DATA; | |
132 | request.status = SCLP_REQ_FILLED; | |
133 | request.callback = sdias_callback; | |
134 | ||
135 | rc = sdias_sclp_send(&request); | |
136 | if (rc) { | |
b3ff088b | 137 | pr_err("sclp_send failed for get_nr_blocks\n"); |
411ed322 MH |
138 | goto out; |
139 | } | |
140 | if (sccb.hdr.response_code != 0x0020) { | |
141 | TRACE("send failed: %x\n", sccb.hdr.response_code); | |
142 | rc = -EIO; | |
143 | goto out; | |
144 | } | |
145 | ||
146 | switch (sccb.evbuf.event_status) { | |
147 | case 0: | |
148 | rc = sccb.evbuf.blk_cnt; | |
149 | break; | |
150 | default: | |
b3ff088b MS |
151 | pr_err("SCLP error: %x\n", |
152 | sccb.evbuf.event_status); | |
411ed322 MH |
153 | rc = -EIO; |
154 | goto out; | |
155 | } | |
156 | TRACE("%i blocks\n", rc); | |
157 | out: | |
158 | mutex_unlock(&sdias_mutex); | |
159 | return rc; | |
160 | } | |
161 | ||
162 | /* | |
163 | * Copy from HSA to absolute storage (not reentrant): | |
164 | * | |
165 | * @dest : Address of buffer where data should be copied | |
166 | * @start_blk: Start Block (beginning with 1) | |
167 | * @nr_blks : Number of 4K blocks to copy | |
168 | * | |
169 | * Return Value: 0 : Requested 'number' of blocks of data copied | |
170 | * <0: ERROR - negative event status | |
171 | */ | |
172 | int sclp_sdias_copy(void *dest, int start_blk, int nr_blks) | |
173 | { | |
174 | struct sclp_req request; | |
175 | int rc; | |
176 | ||
177 | mutex_lock(&sdias_mutex); | |
178 | ||
179 | memset(&sccb, 0, sizeof(sccb)); | |
180 | memset(&request, 0, sizeof(request)); | |
181 | ||
182 | sccb.hdr.length = sizeof(sccb); | |
183 | sccb.evbuf.hdr.length = sizeof(struct sdias_evbuf); | |
6d4740c8 | 184 | sccb.evbuf.hdr.type = EVTYP_SDIAS; |
411ed322 MH |
185 | sccb.evbuf.hdr.flags = 0; |
186 | sccb.evbuf.event_qual = EQ_STORE_DATA; | |
187 | sccb.evbuf.data_id = DI_FCP_DUMP; | |
188 | sccb.evbuf.event_id = 4712; | |
189 | #ifdef __s390x__ | |
190 | sccb.evbuf.asa_size = ASA_SIZE_64; | |
191 | #else | |
192 | sccb.evbuf.asa_size = ASA_SIZE_32; | |
193 | #endif | |
194 | sccb.evbuf.event_status = 0; | |
195 | sccb.evbuf.blk_cnt = nr_blks; | |
196 | sccb.evbuf.asa = (unsigned long)dest; | |
197 | sccb.evbuf.fbn = start_blk; | |
198 | sccb.evbuf.lbn = 0; | |
199 | sccb.evbuf.dbs = 1; | |
200 | ||
201 | request.sccb = &sccb; | |
202 | request.command = SCLP_CMDW_WRITE_EVENT_DATA; | |
203 | request.status = SCLP_REQ_FILLED; | |
204 | request.callback = sdias_callback; | |
205 | ||
206 | rc = sdias_sclp_send(&request); | |
207 | if (rc) { | |
b3ff088b | 208 | pr_err("sclp_send failed: %x\n", rc); |
411ed322 MH |
209 | goto out; |
210 | } | |
211 | if (sccb.hdr.response_code != 0x0020) { | |
212 | TRACE("copy failed: %x\n", sccb.hdr.response_code); | |
213 | rc = -EIO; | |
214 | goto out; | |
215 | } | |
216 | ||
217 | switch (sccb.evbuf.event_status) { | |
218 | case EVSTATE_ALL_STORED: | |
219 | TRACE("all stored\n"); | |
220 | case EVSTATE_PART_STORED: | |
221 | TRACE("part stored: %i\n", sccb.evbuf.blk_cnt); | |
222 | break; | |
223 | case EVSTATE_NO_DATA: | |
224 | TRACE("no data\n"); | |
225 | default: | |
b3ff088b MS |
226 | pr_err("Error from SCLP while copying hsa. " |
227 | "Event status = %x\n", | |
228 | sccb.evbuf.event_status); | |
411ed322 MH |
229 | rc = -EIO; |
230 | } | |
231 | out: | |
232 | mutex_unlock(&sdias_mutex); | |
233 | return rc; | |
234 | } | |
235 | ||
763968e2 | 236 | int __init sclp_sdias_init(void) |
411ed322 MH |
237 | { |
238 | int rc; | |
239 | ||
240 | if (ipl_info.type != IPL_TYPE_FCP_DUMP) | |
241 | return 0; | |
242 | sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long)); | |
243 | debug_register_view(sdias_dbf, &debug_sprintf_view); | |
244 | debug_set_level(sdias_dbf, 6); | |
245 | rc = sclp_register(&sclp_sdias_register); | |
a12c53f4 | 246 | if (rc) |
411ed322 | 247 | return rc; |
411ed322 MH |
248 | init_waitqueue_head(&sdias_wq); |
249 | TRACE("init done\n"); | |
250 | return 0; | |
251 | } | |
252 | ||
763968e2 | 253 | void __exit sclp_sdias_exit(void) |
411ed322 MH |
254 | { |
255 | debug_unregister(sdias_dbf); | |
256 | sclp_unregister(&sclp_sdias_register); | |
257 | } |