linux/drivers/s390/char/zcore.c
<<
>>
Prefs
   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
  39enum arch_id {
  40        ARCH_S390       = 0,
  41        ARCH_S390X      = 1,
  42};
  43
  44struct ipib_info {
  45        unsigned long   ipib;
  46        u32             checksum;
  47}  __attribute__((packed));
  48
  49static struct debug_info *zcore_dbf;
  50static int hsa_available;
  51static struct dentry *zcore_dir;
  52static struct dentry *zcore_memmap_file;
  53static struct dentry *zcore_reipl_file;
  54static struct dentry *zcore_hsa_file;
  55static struct ipl_parameter_block *ipl_block;
  56
  57static 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 */
  66int 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 */
  96int 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
 118static 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 */
 137static void release_hsa(void)
 138{
 139        diag308(DIAG308_REL_HSA, NULL);
 140        hsa_available = 0;
 141}
 142
 143static 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
 150static 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
 169static int zcore_memmap_release(struct inode *inode, struct file *filp)
 170{
 171        kfree(filp->private_data);
 172        return 0;
 173}
 174
 175static 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
 183static 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
 193static int zcore_reipl_open(struct inode *inode, struct file *filp)
 194{
 195        return nonseekable_open(inode, filp);
 196}
 197
 198static int zcore_reipl_release(struct inode *inode, struct file *filp)
 199{
 200        return 0;
 201}
 202
 203static 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
 211static 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
 223static 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
 238static 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
 246static 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 */
 259static 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
 285static 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
 357fail_reipl_file:
 358        debugfs_remove(zcore_reipl_file);
 359fail_memmap_file:
 360        debugfs_remove(zcore_memmap_file);
 361fail_dir:
 362        debugfs_remove(zcore_dir);
 363fail:
 364        diag308(DIAG308_REL_HSA, NULL);
 365        return rc;
 366}
 367
 368static 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
 380MODULE_AUTHOR("Copyright IBM Corp. 2003,2008");
 381MODULE_DESCRIPTION("zcore module for zfcpdump support");
 382MODULE_LICENSE("GPL");
 383
 384subsys_initcall(zcore_init);
 385module_exit(zcore_exit);
 386