]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/s390/char/zcore.c
Merge remote-tracking branches 'asoc/topic/ab8500', 'asoc/topic/adau17x1', 'asoc...
[karo-tx-linux.git] / drivers / s390 / char / zcore.c
1 /*
2  * zcore module to export memory content and register sets for creating system
3  * dumps on SCSI disks (zfcpdump). The "zcore/mem" debugfs file shows the same
4  * dump format as s390 standalone dumps.
5  *
6  * For more information please refer to Documentation/s390/zfcpdump.txt
7  *
8  * Copyright IBM Corp. 2003, 2008
9  * Author(s): Michael Holzheu
10  */
11
12 #define KMSG_COMPONENT "zdump"
13 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
14
15 #include <linux/init.h>
16 #include <linux/slab.h>
17 #include <linux/miscdevice.h>
18 #include <linux/debugfs.h>
19 #include <linux/module.h>
20 #include <linux/memblock.h>
21
22 #include <asm/asm-offsets.h>
23 #include <asm/ipl.h>
24 #include <asm/sclp.h>
25 #include <asm/setup.h>
26 #include <asm/uaccess.h>
27 #include <asm/debug.h>
28 #include <asm/processor.h>
29 #include <asm/irqflags.h>
30 #include <asm/checksum.h>
31 #include <asm/os_info.h>
32 #include <asm/switch_to.h>
33 #include "sclp.h"
34
35 #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)
36
37 #define CHUNK_INFO_SIZE 34 /* 2 16-byte char, each followed by blank */
38
39 enum arch_id {
40         ARCH_S390       = 0,
41         ARCH_S390X      = 1,
42 };
43
44 struct ipib_info {
45         unsigned long   ipib;
46         u32             checksum;
47 }  __attribute__((packed));
48
49 static struct debug_info *zcore_dbf;
50 static int hsa_available;
51 static struct dentry *zcore_dir;
52 static struct dentry *zcore_memmap_file;
53 static struct dentry *zcore_reipl_file;
54 static struct dentry *zcore_hsa_file;
55 static struct ipl_parameter_block *ipl_block;
56
57 static char hsa_buf[PAGE_SIZE] __aligned(PAGE_SIZE);
58
59 /*
60  * Copy memory from HSA to user memory (not reentrant):
61  *
62  * @dest:  User buffer where memory should be copied to
63  * @src:   Start address within HSA where data should be copied
64  * @count: Size of buffer, which should be copied
65  */
66 int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count)
67 {
68         unsigned long offset, bytes;
69
70         if (!hsa_available)
71                 return -ENODATA;
72
73         while (count) {
74                 if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) {
75                         TRACE("sclp_sdias_copy() failed\n");
76                         return -EIO;
77                 }
78                 offset = src % PAGE_SIZE;
79                 bytes = min(PAGE_SIZE - offset, count);
80                 if (copy_to_user(dest, hsa_buf + offset, bytes))
81                         return -EFAULT;
82                 src += bytes;
83                 dest += bytes;
84                 count -= bytes;
85         }
86         return 0;
87 }
88
89 /*
90  * Copy memory from HSA to kernel memory (not reentrant):
91  *
92  * @dest:  Kernel or user buffer where memory should be copied to
93  * @src:   Start address within HSA where data should be copied
94  * @count: Size of buffer, which should be copied
95  */
96 int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
97 {
98         unsigned long offset, bytes;
99
100         if (!hsa_available)
101                 return -ENODATA;
102
103         while (count) {
104                 if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) {
105                         TRACE("sclp_sdias_copy() failed\n");
106                         return -EIO;
107                 }
108                 offset = src % PAGE_SIZE;
109                 bytes = min(PAGE_SIZE - offset, count);
110                 memcpy(dest, hsa_buf + offset, bytes);
111                 src += bytes;
112                 dest += bytes;
113                 count -= bytes;
114         }
115         return 0;
116 }
117
118 static int __init init_cpu_info(void)
119 {
120         struct save_area *sa;
121
122         /* get info for boot cpu from lowcore, stored in the HSA */
123         sa = save_area_boot_cpu();
124         if (!sa)
125                 return -ENOMEM;
126         if (memcpy_hsa_kernel(hsa_buf, __LC_FPREGS_SAVE_AREA, 512) < 0) {
127                 TRACE("could not copy from HSA\n");
128                 return -EIO;
129         }
130         save_area_add_regs(sa, hsa_buf); /* vx registers are saved in smp.c */
131         return 0;
132 }
133
134 /*
135  * Release the HSA
136  */
137 static void release_hsa(void)
138 {
139         diag308(DIAG308_REL_HSA, NULL);
140         hsa_available = 0;
141 }
142
143 static ssize_t zcore_memmap_read(struct file *filp, char __user *buf,
144                                  size_t count, loff_t *ppos)
145 {
146         return simple_read_from_buffer(buf, count, ppos, filp->private_data,
147                                        memblock.memory.cnt * CHUNK_INFO_SIZE);
148 }
149
150 static int zcore_memmap_open(struct inode *inode, struct file *filp)
151 {
152         struct memblock_region *reg;
153         char *buf;
154         int i = 0;
155
156         buf = kzalloc(memblock.memory.cnt * CHUNK_INFO_SIZE, GFP_KERNEL);
157         if (!buf) {
158                 return -ENOMEM;
159         }
160         for_each_memblock(memory, reg) {
161                 sprintf(buf + (i++ * CHUNK_INFO_SIZE), "%016llx %016llx ",
162                         (unsigned long long) reg->base,
163                         (unsigned long long) reg->size);
164         }
165         filp->private_data = buf;
166         return nonseekable_open(inode, filp);
167 }
168
169 static int zcore_memmap_release(struct inode *inode, struct file *filp)
170 {
171         kfree(filp->private_data);
172         return 0;
173 }
174
175 static const struct file_operations zcore_memmap_fops = {
176         .owner          = THIS_MODULE,
177         .read           = zcore_memmap_read,
178         .open           = zcore_memmap_open,
179         .release        = zcore_memmap_release,
180         .llseek         = no_llseek,
181 };
182
183 static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf,
184                                  size_t count, loff_t *ppos)
185 {
186         if (ipl_block) {
187                 diag308(DIAG308_SET, ipl_block);
188                 diag308(DIAG308_IPL, NULL);
189         }
190         return count;
191 }
192
193 static int zcore_reipl_open(struct inode *inode, struct file *filp)
194 {
195         return nonseekable_open(inode, filp);
196 }
197
198 static int zcore_reipl_release(struct inode *inode, struct file *filp)
199 {
200         return 0;
201 }
202
203 static const struct file_operations zcore_reipl_fops = {
204         .owner          = THIS_MODULE,
205         .write          = zcore_reipl_write,
206         .open           = zcore_reipl_open,
207         .release        = zcore_reipl_release,
208         .llseek         = no_llseek,
209 };
210
211 static ssize_t zcore_hsa_read(struct file *filp, char __user *buf,
212                               size_t count, loff_t *ppos)
213 {
214         static char str[18];
215
216         if (hsa_available)
217                 snprintf(str, sizeof(str), "%lx\n", sclp.hsa_size);
218         else
219                 snprintf(str, sizeof(str), "0\n");
220         return simple_read_from_buffer(buf, count, ppos, str, strlen(str));
221 }
222
223 static ssize_t zcore_hsa_write(struct file *filp, const char __user *buf,
224                                size_t count, loff_t *ppos)
225 {
226         char value;
227
228         if (*ppos != 0)
229                 return -EPIPE;
230         if (copy_from_user(&value, buf, 1))
231                 return -EFAULT;
232         if (value != '0')
233                 return -EINVAL;
234         release_hsa();
235         return count;
236 }
237
238 static const struct file_operations zcore_hsa_fops = {
239         .owner          = THIS_MODULE,
240         .write          = zcore_hsa_write,
241         .read           = zcore_hsa_read,
242         .open           = nonseekable_open,
243         .llseek         = no_llseek,
244 };
245
246 static int __init check_sdias(void)
247 {
248         if (!sclp.hsa_size) {
249                 TRACE("Could not determine HSA size\n");
250                 return -ENODEV;
251         }
252         return 0;
253 }
254
255 /*
256  * Provide IPL parameter information block from either HSA or memory
257  * for future reipl
258  */
259 static int __init zcore_reipl_init(void)
260 {
261         struct ipib_info ipib_info;
262         int rc;
263
264         rc = memcpy_hsa_kernel(&ipib_info, __LC_DUMP_REIPL, sizeof(ipib_info));
265         if (rc)
266                 return rc;
267         if (ipib_info.ipib == 0)
268                 return 0;
269         ipl_block = (void *) __get_free_page(GFP_KERNEL);
270         if (!ipl_block)
271                 return -ENOMEM;
272         if (ipib_info.ipib < sclp.hsa_size)
273                 rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE);
274         else
275                 rc = memcpy_real(ipl_block, (void *) ipib_info.ipib, PAGE_SIZE);
276         if (rc || csum_partial(ipl_block, ipl_block->hdr.len, 0) !=
277             ipib_info.checksum) {
278                 TRACE("Checksum does not match\n");
279                 free_page((unsigned long) ipl_block);
280                 ipl_block = NULL;
281         }
282         return 0;
283 }
284
285 static int __init zcore_init(void)
286 {
287         unsigned char arch;
288         int rc;
289
290         if (ipl_info.type != IPL_TYPE_FCP_DUMP)
291                 return -ENODATA;
292         if (OLDMEM_BASE)
293                 return -ENODATA;
294
295         zcore_dbf = debug_register("zcore", 4, 1, 4 * sizeof(long));
296         debug_register_view(zcore_dbf, &debug_sprintf_view);
297         debug_set_level(zcore_dbf, 6);
298
299         TRACE("devno:  %x\n", ipl_info.data.fcp.dev_id.devno);
300         TRACE("wwpn:   %llx\n", (unsigned long long) ipl_info.data.fcp.wwpn);
301         TRACE("lun:    %llx\n", (unsigned long long) ipl_info.data.fcp.lun);
302
303         rc = sclp_sdias_init();
304         if (rc)
305                 goto fail;
306
307         rc = check_sdias();
308         if (rc)
309                 goto fail;
310         hsa_available = 1;
311
312         rc = memcpy_hsa_kernel(&arch, __LC_AR_MODE_ID, 1);
313         if (rc)
314                 goto fail;
315
316         if (arch == ARCH_S390) {
317                 pr_alert("The 64-bit dump tool cannot be used for a "
318                          "32-bit system\n");
319                 rc = -EINVAL;
320                 goto fail;
321         }
322
323         pr_alert("DETECTED 'S390X (64 bit) OS'\n");
324         rc = init_cpu_info();
325         if (rc)
326                 goto fail;
327
328         rc = zcore_reipl_init();
329         if (rc)
330                 goto fail;
331
332         zcore_dir = debugfs_create_dir("zcore" , NULL);
333         if (!zcore_dir) {
334                 rc = -ENOMEM;
335                 goto fail;
336         }
337         zcore_memmap_file = debugfs_create_file("memmap", S_IRUSR, zcore_dir,
338                                                 NULL, &zcore_memmap_fops);
339         if (!zcore_memmap_file) {
340                 rc = -ENOMEM;
341                 goto fail_dir;
342         }
343         zcore_reipl_file = debugfs_create_file("reipl", S_IRUSR, zcore_dir,
344                                                 NULL, &zcore_reipl_fops);
345         if (!zcore_reipl_file) {
346                 rc = -ENOMEM;
347                 goto fail_memmap_file;
348         }
349         zcore_hsa_file = debugfs_create_file("hsa", S_IRUSR|S_IWUSR, zcore_dir,
350                                              NULL, &zcore_hsa_fops);
351         if (!zcore_hsa_file) {
352                 rc = -ENOMEM;
353                 goto fail_reipl_file;
354         }
355         return 0;
356
357 fail_reipl_file:
358         debugfs_remove(zcore_reipl_file);
359 fail_memmap_file:
360         debugfs_remove(zcore_memmap_file);
361 fail_dir:
362         debugfs_remove(zcore_dir);
363 fail:
364         diag308(DIAG308_REL_HSA, NULL);
365         return rc;
366 }
367
368 static void __exit zcore_exit(void)
369 {
370         debug_unregister(zcore_dbf);
371         sclp_sdias_exit();
372         free_page((unsigned long) ipl_block);
373         debugfs_remove(zcore_hsa_file);
374         debugfs_remove(zcore_reipl_file);
375         debugfs_remove(zcore_memmap_file);
376         debugfs_remove(zcore_dir);
377         diag308(DIAG308_REL_HSA, NULL);
378 }
379
380 MODULE_AUTHOR("Copyright IBM Corp. 2003,2008");
381 MODULE_DESCRIPTION("zcore module for zfcpdump support");
382 MODULE_LICENSE("GPL");
383
384 subsys_initcall(zcore_init);
385 module_exit(zcore_exit);