#ifndef _ASM_S390_OS_INFO_H
 #define _ASM_S390_OS_INFO_H
 
+#include <linux/uio.h>
+
 #define OS_INFO_VERSION_MAJOR  1
 #define OS_INFO_VERSION_MINOR  1
 #define OS_INFO_MAGIC          0x4f53494e464f535aULL /* OSINFOSZ */
 
 #ifdef CONFIG_CRASH_DUMP
 void *os_info_old_entry(int nr, unsigned long *size);
-int copy_oldmem_kernel(void *dst, unsigned long src, size_t count);
+size_t copy_oldmem_iter(struct iov_iter *iter, unsigned long src, size_t count);
+
+static inline int copy_oldmem_kernel(void *dst, unsigned long src, size_t count)
+{
+       struct iov_iter iter;
+       struct kvec kvec;
+
+       kvec.iov_base = dst;
+       kvec.iov_len = count;
+       iov_iter_kvec(&iter, WRITE, &kvec, 1, count);
+       if (copy_oldmem_iter(&iter, src, count) < count)
+               return -EFAULT;
+       return 0;
+}
 #else
 static inline void *os_info_old_entry(int nr, unsigned long *size)
 {
 
 #define EXT_SCCB_READ_CPU      (3 * PAGE_SIZE)
 
 #ifndef __ASSEMBLY__
+#include <linux/uio.h>
 #include <asm/chpid.h>
 #include <asm/cpu.h>
 
 int sclp_ap_configure(u32 apid);
 int sclp_ap_deconfigure(u32 apid);
 int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid);
-int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count);
-int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count);
+size_t memcpy_hsa_iter(struct iov_iter *iter, unsigned long src, size_t count);
 void sclp_ocf_cpc_name_copy(char *dst);
 
 static inline int sclp_get_core_info(struct sclp_core_info *info, int early)
 
        memcpy(sa->vxrs_high, vxrs + 16, 16 * sizeof(__vector128));
 }
 
-/*
- * Return physical address for virtual address
- */
-static inline void *load_real_addr(void *addr)
-{
-       unsigned long real_addr;
-
-       asm volatile(
-                  "    lra     %0,0(%1)\n"
-                  "    jz      0f\n"
-                  "    la      %0,0\n"
-                  "0:"
-                  : "=a" (real_addr) : "a" (addr) : "cc");
-       return (void *)real_addr;
-}
-
-/*
- * Copy memory of the old, dumped system to a kernel space virtual address
- */
-int copy_oldmem_kernel(void *dst, unsigned long src, size_t count)
-{
-       unsigned long len;
-       void *ra;
-       int rc;
-
-       while (count) {
-               if (!oldmem_data.start && src < sclp.hsa_size) {
-                       /* Copy from zfcp/nvme dump HSA area */
-                       len = min(count, sclp.hsa_size - src);
-                       rc = memcpy_hsa_kernel(dst, src, len);
-                       if (rc)
-                               return rc;
-               } else {
-                       /* Check for swapped kdump oldmem areas */
-                       if (oldmem_data.start && src - oldmem_data.start < oldmem_data.size) {
-                               src -= oldmem_data.start;
-                               len = min(count, oldmem_data.size - src);
-                       } else if (oldmem_data.start && src < oldmem_data.size) {
-                               len = min(count, oldmem_data.size - src);
-                               src += oldmem_data.start;
-                       } else {
-                               len = count;
-                       }
-                       if (is_vmalloc_or_module_addr(dst)) {
-                               ra = load_real_addr(dst);
-                               len = min(PAGE_SIZE - offset_in_page(ra), len);
-                       } else {
-                               ra = dst;
-                       }
-                       if (memcpy_real(ra, src, len))
-                               return -EFAULT;
-               }
-               dst += len;
-               src += len;
-               count -= len;
-       }
-       return 0;
-}
-
-/*
- * Copy memory from kernel (real) to user (virtual)
- */
-static int copy_to_user_real(void __user *dest, unsigned long src, unsigned long count)
+static size_t copy_to_iter_real(struct iov_iter *iter, unsigned long src, size_t count)
 {
-       unsigned long offs = 0, size;
+       size_t len, copied, res = 0;
 
        mutex_lock(&memcpy_real_mutex);
-       while (offs < count) {
-               size = min(PAGE_SIZE, count - offs);
-               if (memcpy_real(memcpy_real_buf, src + offs, size))
+       while (count) {
+               len = min(PAGE_SIZE, count);
+               if (memcpy_real(memcpy_real_buf, src, len))
                        break;
-               if (copy_to_user(dest + offs, memcpy_real_buf, size))
+               copied = copy_to_iter(memcpy_real_buf, len, iter);
+               count -= copied;
+               src += copied;
+               res += copied;
+               if (copied < len)
                        break;
-               offs += size;
        }
        mutex_unlock(&memcpy_real_mutex);
-       if (offs < count)
-               return -EFAULT;
-       return 0;
+       return res;
 }
 
-/*
- * Copy memory of the old, dumped system to a user space virtual address
- */
-static int copy_oldmem_user(void __user *dst, unsigned long src, size_t count)
+size_t copy_oldmem_iter(struct iov_iter *iter, unsigned long src, size_t count)
 {
-       unsigned long len;
-       int rc;
+       size_t len, copied, res = 0;
 
        while (count) {
                if (!oldmem_data.start && src < sclp.hsa_size) {
                        /* Copy from zfcp/nvme dump HSA area */
                        len = min(count, sclp.hsa_size - src);
-                       rc = memcpy_hsa_user(dst, src, len);
-                       if (rc)
-                               return rc;
+                       copied = memcpy_hsa_iter(iter, src, len);
                } else {
                        /* Check for swapped kdump oldmem areas */
                        if (oldmem_data.start && src - oldmem_data.start < oldmem_data.size) {
                        } else {
                                len = count;
                        }
-                       rc = copy_to_user_real(dst, src, len);
-                       if (rc)
-                               return rc;
+                       copied = copy_to_iter_real(iter, src, len);
                }
-               dst += len;
-               src += len;
-               count -= len;
+               count -= copied;
+               src += copied;
+               res += copied;
+               if (copied < len)
+                       break;
        }
-       return 0;
+       return res;
 }
 
 /*
                         unsigned long offset)
 {
        unsigned long src;
-       int rc;
 
-       if (!(iter_is_iovec(iter) || iov_iter_is_kvec(iter)))
-               return -EINVAL;
-       /* Multi-segment iterators are not supported */
-       if (iter->nr_segs > 1)
-               return -EINVAL;
-       if (!csize)
-               return 0;
        src = pfn_to_phys(pfn) + offset;
-
-       /* XXX: pass the iov_iter down to a common function */
-       if (iter_is_iovec(iter))
-               rc = copy_oldmem_user(iter->iov->iov_base, src, csize);
-       else
-               rc = copy_oldmem_kernel(iter->kvec->iov_base, src, csize);
-       if (rc < 0)
-               return rc;
-       iov_iter_advance(iter, csize);
-       return csize;
+       return copy_oldmem_iter(iter, src, csize);
 }
 
 /*
 
 #include <linux/debugfs.h>
 #include <linux/panic_notifier.h>
 #include <linux/reboot.h>
+#include <linux/uio.h>
 
 #include <asm/asm-offsets.h>
 #include <asm/ipl.h>
 static char hsa_buf[PAGE_SIZE] __aligned(PAGE_SIZE);
 
 /*
- * Copy memory from HSA to user memory (not reentrant):
+ * Copy memory from HSA to iterator (not reentrant):
  *
- * @dest:  User buffer where memory should be copied to
+ * @iter:  Iterator where memory should be copied to
  * @src:   Start address within HSA where data should be copied
  * @count: Size of buffer, which should be copied
  */
-int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count)
+size_t memcpy_hsa_iter(struct iov_iter *iter, unsigned long src, size_t count)
 {
-       unsigned long offset, bytes;
+       size_t bytes, copied, res = 0;
+       unsigned long offset;
 
        if (!hsa_available)
-               return -ENODATA;
+               return 0;
 
        mutex_lock(&hsa_buf_mutex);
        while (count) {
                if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) {
                        TRACE("sclp_sdias_copy() failed\n");
-                       mutex_unlock(&hsa_buf_mutex);
-                       return -EIO;
+                       break;
                }
                offset = src % PAGE_SIZE;
                bytes = min(PAGE_SIZE - offset, count);
-               if (copy_to_user(dest, hsa_buf + offset, bytes)) {
-                       mutex_unlock(&hsa_buf_mutex);
-                       return -EFAULT;
-               }
-               src += bytes;
-               dest += bytes;
-               count -= bytes;
+               copied = copy_to_iter(hsa_buf + offset, bytes, iter);
+               count -= copied;
+               src += copied;
+               res += copied;
+               if (copied < bytes)
+                       break;
        }
        mutex_unlock(&hsa_buf_mutex);
-       return 0;
+       return res;
 }
 
 /*
  * @src:   Start address within HSA where data should be copied
  * @count: Size of buffer, which should be copied
  */
-int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
+static inline int memcpy_hsa_kernel(void *dst, unsigned long src, size_t count)
 {
-       unsigned long offset, bytes;
+       struct iov_iter iter;
+       struct kvec kvec;
 
-       if (!hsa_available)
-               return -ENODATA;
-
-       mutex_lock(&hsa_buf_mutex);
-       while (count) {
-               if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) {
-                       TRACE("sclp_sdias_copy() failed\n");
-                       mutex_unlock(&hsa_buf_mutex);
-                       return -EIO;
-               }
-               offset = src % PAGE_SIZE;
-               bytes = min(PAGE_SIZE - offset, count);
-               memcpy(dest, hsa_buf + offset, bytes);
-               src += bytes;
-               dest += bytes;
-               count -= bytes;
-       }
-       mutex_unlock(&hsa_buf_mutex);
+       kvec.iov_base = dst;
+       kvec.iov_len = count;
+       iov_iter_kvec(&iter, WRITE, &kvec, 1, count);
+       if (memcpy_hsa_iter(&iter, src, count) < count)
+               return -EIO;
        return 0;
 }