kmem_cache_free(mcesa_cache, __va(*mcesad & MCESA_ORIGIN_MASK));
 }
 
+static __always_inline char *nmi_puts(char *dest, const char *src)
+{
+       while (*src)
+               *dest++ = *src++;
+       *dest = 0;
+       return dest;
+}
+
+static __always_inline char *u64_to_hex(char *dest, u64 val)
+{
+       int i, num;
+
+       for (i = 1; i <= 16; i++) {
+               num = (val >> (64 - 4 * i)) & 0xf;
+               if (num >= 10)
+                       *dest++ = 'A' + num - 10;
+               else
+                       *dest++ = '0' + num;
+       }
+       *dest = 0;
+       return dest;
+}
+
 static notrace void s390_handle_damage(void)
 {
+       union ctlreg0 cr0, cr0_new;
+       char message[100];
+       psw_t psw_save;
+       char *ptr;
+
        smp_emergency_stop();
+       diag_amode31_ops.diag308_reset();
+       ptr = nmi_puts(message, "System stopped due to unrecoverable machine check, code: 0x");
+       u64_to_hex(ptr, S390_lowcore.mcck_interruption_code);
+
+       /*
+        * Disable low address protection and make machine check new PSW a
+        * disabled wait PSW. Any additional machine check cannot be handled.
+        */
+       __ctl_store(cr0.val, 0, 0);
+       cr0_new = cr0;
+       cr0_new.lap = 0;
+       __ctl_load(cr0_new.val, 0, 0);
+       psw_save = S390_lowcore.mcck_new_psw;
+       psw_bits(S390_lowcore.mcck_new_psw).io = 0;
+       psw_bits(S390_lowcore.mcck_new_psw).ext = 0;
+       psw_bits(S390_lowcore.mcck_new_psw).wait = 1;
+       sclp_emergency_printk(message);
+
+       /*
+        * Restore machine check new PSW and control register 0 to original
+        * values. This makes possible system dump analysis easier.
+        */
+       S390_lowcore.mcck_new_psw = psw_save;
+       __ctl_load(cr0.val, 0, 0);
        disabled_wait();
        while (1);
 }