| .. | .. |
|---|
| 1 | 1 | // SPDX-License-Identifier: GPL-1.0+ |
|---|
| 2 | 2 | /* |
|---|
| 3 | 3 | * zcore module to export memory content and register sets for creating system |
|---|
| 4 | | - * dumps on SCSI disks (zfcpdump). The "zcore/mem" debugfs file shows the same |
|---|
| 5 | | - * dump format as s390 standalone dumps. |
|---|
| 4 | + * dumps on SCSI/NVMe disks (zfcp/nvme dump). |
|---|
| 6 | 5 | * |
|---|
| 7 | | - * For more information please refer to Documentation/s390/zfcpdump.txt |
|---|
| 6 | + * For more information please refer to Documentation/s390/zfcpdump.rst |
|---|
| 8 | 7 | * |
|---|
| 9 | 8 | * Copyright IBM Corp. 2003, 2008 |
|---|
| 10 | 9 | * Author(s): Michael Holzheu |
|---|
| .. | .. |
|---|
| 16 | 15 | #include <linux/init.h> |
|---|
| 17 | 16 | #include <linux/slab.h> |
|---|
| 18 | 17 | #include <linux/debugfs.h> |
|---|
| 19 | | -#include <linux/memblock.h> |
|---|
| 20 | 18 | |
|---|
| 21 | 19 | #include <asm/asm-offsets.h> |
|---|
| 22 | 20 | #include <asm/ipl.h> |
|---|
| .. | .. |
|---|
| 33 | 31 | |
|---|
| 34 | 32 | #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x) |
|---|
| 35 | 33 | |
|---|
| 36 | | -#define CHUNK_INFO_SIZE 34 /* 2 16-byte char, each followed by blank */ |
|---|
| 37 | | - |
|---|
| 38 | 34 | enum arch_id { |
|---|
| 39 | 35 | ARCH_S390 = 0, |
|---|
| 40 | 36 | ARCH_S390X = 1, |
|---|
| .. | .. |
|---|
| 48 | 44 | static struct debug_info *zcore_dbf; |
|---|
| 49 | 45 | static int hsa_available; |
|---|
| 50 | 46 | static struct dentry *zcore_dir; |
|---|
| 51 | | -static struct dentry *zcore_memmap_file; |
|---|
| 52 | 47 | static struct dentry *zcore_reipl_file; |
|---|
| 53 | 48 | static struct dentry *zcore_hsa_file; |
|---|
| 54 | | -static struct ipl_parameter_block *ipl_block; |
|---|
| 49 | +static struct ipl_parameter_block *zcore_ipl_block; |
|---|
| 55 | 50 | |
|---|
| 51 | +static DEFINE_MUTEX(hsa_buf_mutex); |
|---|
| 56 | 52 | static char hsa_buf[PAGE_SIZE] __aligned(PAGE_SIZE); |
|---|
| 57 | 53 | |
|---|
| 58 | 54 | /* |
|---|
| .. | .. |
|---|
| 69 | 65 | if (!hsa_available) |
|---|
| 70 | 66 | return -ENODATA; |
|---|
| 71 | 67 | |
|---|
| 68 | + mutex_lock(&hsa_buf_mutex); |
|---|
| 72 | 69 | while (count) { |
|---|
| 73 | 70 | if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) { |
|---|
| 74 | 71 | TRACE("sclp_sdias_copy() failed\n"); |
|---|
| 72 | + mutex_unlock(&hsa_buf_mutex); |
|---|
| 75 | 73 | return -EIO; |
|---|
| 76 | 74 | } |
|---|
| 77 | 75 | offset = src % PAGE_SIZE; |
|---|
| 78 | 76 | bytes = min(PAGE_SIZE - offset, count); |
|---|
| 79 | | - if (copy_to_user(dest, hsa_buf + offset, bytes)) |
|---|
| 77 | + if (copy_to_user(dest, hsa_buf + offset, bytes)) { |
|---|
| 78 | + mutex_unlock(&hsa_buf_mutex); |
|---|
| 80 | 79 | return -EFAULT; |
|---|
| 80 | + } |
|---|
| 81 | 81 | src += bytes; |
|---|
| 82 | 82 | dest += bytes; |
|---|
| 83 | 83 | count -= bytes; |
|---|
| 84 | 84 | } |
|---|
| 85 | + mutex_unlock(&hsa_buf_mutex); |
|---|
| 85 | 86 | return 0; |
|---|
| 86 | 87 | } |
|---|
| 87 | 88 | |
|---|
| .. | .. |
|---|
| 99 | 100 | if (!hsa_available) |
|---|
| 100 | 101 | return -ENODATA; |
|---|
| 101 | 102 | |
|---|
| 103 | + mutex_lock(&hsa_buf_mutex); |
|---|
| 102 | 104 | while (count) { |
|---|
| 103 | 105 | if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) { |
|---|
| 104 | 106 | TRACE("sclp_sdias_copy() failed\n"); |
|---|
| 107 | + mutex_unlock(&hsa_buf_mutex); |
|---|
| 105 | 108 | return -EIO; |
|---|
| 106 | 109 | } |
|---|
| 107 | 110 | offset = src % PAGE_SIZE; |
|---|
| .. | .. |
|---|
| 111 | 114 | dest += bytes; |
|---|
| 112 | 115 | count -= bytes; |
|---|
| 113 | 116 | } |
|---|
| 117 | + mutex_unlock(&hsa_buf_mutex); |
|---|
| 114 | 118 | return 0; |
|---|
| 115 | 119 | } |
|---|
| 116 | 120 | |
|---|
| .. | .. |
|---|
| 139 | 143 | hsa_available = 0; |
|---|
| 140 | 144 | } |
|---|
| 141 | 145 | |
|---|
| 142 | | -static ssize_t zcore_memmap_read(struct file *filp, char __user *buf, |
|---|
| 143 | | - size_t count, loff_t *ppos) |
|---|
| 144 | | -{ |
|---|
| 145 | | - return simple_read_from_buffer(buf, count, ppos, filp->private_data, |
|---|
| 146 | | - memblock.memory.cnt * CHUNK_INFO_SIZE); |
|---|
| 147 | | -} |
|---|
| 148 | | - |
|---|
| 149 | | -static int zcore_memmap_open(struct inode *inode, struct file *filp) |
|---|
| 150 | | -{ |
|---|
| 151 | | - struct memblock_region *reg; |
|---|
| 152 | | - char *buf; |
|---|
| 153 | | - int i = 0; |
|---|
| 154 | | - |
|---|
| 155 | | - buf = kcalloc(memblock.memory.cnt, CHUNK_INFO_SIZE, GFP_KERNEL); |
|---|
| 156 | | - if (!buf) { |
|---|
| 157 | | - return -ENOMEM; |
|---|
| 158 | | - } |
|---|
| 159 | | - for_each_memblock(memory, reg) { |
|---|
| 160 | | - sprintf(buf + (i++ * CHUNK_INFO_SIZE), "%016llx %016llx ", |
|---|
| 161 | | - (unsigned long long) reg->base, |
|---|
| 162 | | - (unsigned long long) reg->size); |
|---|
| 163 | | - } |
|---|
| 164 | | - filp->private_data = buf; |
|---|
| 165 | | - return nonseekable_open(inode, filp); |
|---|
| 166 | | -} |
|---|
| 167 | | - |
|---|
| 168 | | -static int zcore_memmap_release(struct inode *inode, struct file *filp) |
|---|
| 169 | | -{ |
|---|
| 170 | | - kfree(filp->private_data); |
|---|
| 171 | | - return 0; |
|---|
| 172 | | -} |
|---|
| 173 | | - |
|---|
| 174 | | -static const struct file_operations zcore_memmap_fops = { |
|---|
| 175 | | - .owner = THIS_MODULE, |
|---|
| 176 | | - .read = zcore_memmap_read, |
|---|
| 177 | | - .open = zcore_memmap_open, |
|---|
| 178 | | - .release = zcore_memmap_release, |
|---|
| 179 | | - .llseek = no_llseek, |
|---|
| 180 | | -}; |
|---|
| 181 | | - |
|---|
| 182 | 146 | static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf, |
|---|
| 183 | 147 | size_t count, loff_t *ppos) |
|---|
| 184 | 148 | { |
|---|
| 185 | | - if (ipl_block) { |
|---|
| 186 | | - diag308(DIAG308_SET, ipl_block); |
|---|
| 149 | + if (zcore_ipl_block) { |
|---|
| 150 | + diag308(DIAG308_SET, zcore_ipl_block); |
|---|
| 187 | 151 | diag308(DIAG308_LOAD_CLEAR, NULL); |
|---|
| 188 | 152 | } |
|---|
| 189 | 153 | return count; |
|---|
| .. | .. |
|---|
| 191 | 155 | |
|---|
| 192 | 156 | static int zcore_reipl_open(struct inode *inode, struct file *filp) |
|---|
| 193 | 157 | { |
|---|
| 194 | | - return nonseekable_open(inode, filp); |
|---|
| 158 | + return stream_open(inode, filp); |
|---|
| 195 | 159 | } |
|---|
| 196 | 160 | |
|---|
| 197 | 161 | static int zcore_reipl_release(struct inode *inode, struct file *filp) |
|---|
| .. | .. |
|---|
| 265 | 229 | return rc; |
|---|
| 266 | 230 | if (ipib_info.ipib == 0) |
|---|
| 267 | 231 | return 0; |
|---|
| 268 | | - ipl_block = (void *) __get_free_page(GFP_KERNEL); |
|---|
| 269 | | - if (!ipl_block) |
|---|
| 232 | + zcore_ipl_block = (void *) __get_free_page(GFP_KERNEL); |
|---|
| 233 | + if (!zcore_ipl_block) |
|---|
| 270 | 234 | return -ENOMEM; |
|---|
| 271 | 235 | if (ipib_info.ipib < sclp.hsa_size) |
|---|
| 272 | | - rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE); |
|---|
| 236 | + rc = memcpy_hsa_kernel(zcore_ipl_block, ipib_info.ipib, |
|---|
| 237 | + PAGE_SIZE); |
|---|
| 273 | 238 | else |
|---|
| 274 | | - rc = memcpy_real(ipl_block, (void *) ipib_info.ipib, PAGE_SIZE); |
|---|
| 275 | | - if (rc || (__force u32)csum_partial(ipl_block, ipl_block->hdr.len, 0) != |
|---|
| 239 | + rc = memcpy_real(zcore_ipl_block, (void *) ipib_info.ipib, |
|---|
| 240 | + PAGE_SIZE); |
|---|
| 241 | + if (rc || (__force u32)csum_partial(zcore_ipl_block, zcore_ipl_block->hdr.len, 0) != |
|---|
| 276 | 242 | ipib_info.checksum) { |
|---|
| 277 | 243 | TRACE("Checksum does not match\n"); |
|---|
| 278 | | - free_page((unsigned long) ipl_block); |
|---|
| 279 | | - ipl_block = NULL; |
|---|
| 244 | + free_page((unsigned long) zcore_ipl_block); |
|---|
| 245 | + zcore_ipl_block = NULL; |
|---|
| 280 | 246 | } |
|---|
| 281 | 247 | return 0; |
|---|
| 282 | 248 | } |
|---|
| .. | .. |
|---|
| 286 | 252 | unsigned char arch; |
|---|
| 287 | 253 | int rc; |
|---|
| 288 | 254 | |
|---|
| 289 | | - if (ipl_info.type != IPL_TYPE_FCP_DUMP) |
|---|
| 255 | + if (!is_ipl_type_dump()) |
|---|
| 290 | 256 | return -ENODATA; |
|---|
| 291 | 257 | if (OLDMEM_BASE) |
|---|
| 292 | 258 | return -ENODATA; |
|---|
| .. | .. |
|---|
| 295 | 261 | debug_register_view(zcore_dbf, &debug_sprintf_view); |
|---|
| 296 | 262 | debug_set_level(zcore_dbf, 6); |
|---|
| 297 | 263 | |
|---|
| 298 | | - TRACE("devno: %x\n", ipl_info.data.fcp.dev_id.devno); |
|---|
| 299 | | - TRACE("wwpn: %llx\n", (unsigned long long) ipl_info.data.fcp.wwpn); |
|---|
| 300 | | - TRACE("lun: %llx\n", (unsigned long long) ipl_info.data.fcp.lun); |
|---|
| 264 | + if (ipl_info.type == IPL_TYPE_FCP_DUMP) { |
|---|
| 265 | + TRACE("type: fcp\n"); |
|---|
| 266 | + TRACE("devno: %x\n", ipl_info.data.fcp.dev_id.devno); |
|---|
| 267 | + TRACE("wwpn: %llx\n", (unsigned long long) ipl_info.data.fcp.wwpn); |
|---|
| 268 | + TRACE("lun: %llx\n", (unsigned long long) ipl_info.data.fcp.lun); |
|---|
| 269 | + } else if (ipl_info.type == IPL_TYPE_NVME_DUMP) { |
|---|
| 270 | + TRACE("type: nvme\n"); |
|---|
| 271 | + TRACE("fid: %x\n", ipl_info.data.nvme.fid); |
|---|
| 272 | + TRACE("nsid: %x\n", ipl_info.data.nvme.nsid); |
|---|
| 273 | + } |
|---|
| 301 | 274 | |
|---|
| 302 | 275 | rc = sclp_sdias_init(); |
|---|
| 303 | 276 | if (rc) |
|---|
| .. | .. |
|---|
| 333 | 306 | rc = -ENOMEM; |
|---|
| 334 | 307 | goto fail; |
|---|
| 335 | 308 | } |
|---|
| 336 | | - zcore_memmap_file = debugfs_create_file("memmap", S_IRUSR, zcore_dir, |
|---|
| 337 | | - NULL, &zcore_memmap_fops); |
|---|
| 338 | | - if (!zcore_memmap_file) { |
|---|
| 339 | | - rc = -ENOMEM; |
|---|
| 340 | | - goto fail_dir; |
|---|
| 341 | | - } |
|---|
| 342 | 309 | zcore_reipl_file = debugfs_create_file("reipl", S_IRUSR, zcore_dir, |
|---|
| 343 | 310 | NULL, &zcore_reipl_fops); |
|---|
| 344 | 311 | if (!zcore_reipl_file) { |
|---|
| 345 | 312 | rc = -ENOMEM; |
|---|
| 346 | | - goto fail_memmap_file; |
|---|
| 313 | + goto fail_dir; |
|---|
| 347 | 314 | } |
|---|
| 348 | 315 | zcore_hsa_file = debugfs_create_file("hsa", S_IRUSR|S_IWUSR, zcore_dir, |
|---|
| 349 | 316 | NULL, &zcore_hsa_fops); |
|---|
| .. | .. |
|---|
| 355 | 322 | |
|---|
| 356 | 323 | fail_reipl_file: |
|---|
| 357 | 324 | debugfs_remove(zcore_reipl_file); |
|---|
| 358 | | -fail_memmap_file: |
|---|
| 359 | | - debugfs_remove(zcore_memmap_file); |
|---|
| 360 | 325 | fail_dir: |
|---|
| 361 | 326 | debugfs_remove(zcore_dir); |
|---|
| 362 | 327 | fail: |
|---|