/*
 *  arch/s390/boot/ipldump.S
 *
 *  S390 version
 *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
 *
 *  Tape dump ipl record. Put it on a tape and ipl from it and it will
 *  write a dump of the real storage after the ipl record on that tape.
 */

#include <linux/config.h>
#include <asm/setup.h>
#include <asm/lowcore.h>

#define IPL_BS 1024
        .org   0
        .long  0x00080000,0x80000000+_start    # The first 24 bytes are loaded
        .long  0x07000000,0x60000001           # by ipl to addresses 0-23.
        .long  0x02000000,0x20000000+IPL_BS    # (a PSW and two CCWs).
        .long  0x00000000,0x00000000
        .long  0x00000000,0x00000000           # svc old psw
        .long  0x00000000,0x00000000           # program check old psw
        .long  0x00000000,0x00000000           # machine check old psw
        .long  0x00000000,0x00000000           # io old psw
        .long  0x00000000,0x00000000
        .long  0x00000000,0x00000000
        .long  0x00000000,0x00000000
        .long  0x000a0000,0x00000058           # external new psw
        .long  0x000a0000,0x00000060           # svc new psw
        .long  0x000a0000,0x00000068           # program check new psw
        .long  0x000a0000,0x00000070           # machine check new psw
        .long  0x00080000,0x80000000+.Lioint   # io new psw

        .org   0x100
        .globl _start
_start:
	l     %r1,0xb8                         # load ipl subchannel number
#
# find out memory size
#
        mvc   104(8,0),.Lpcmem0          # setup program check handler
        slr   %r3,%r3
        lhi   %r2,1
        sll   %r2,20
.Lloop0:
        l     %r0,0(%r3)                 # test page
        ar    %r3,%r2                    # add 1M
        jnm   .Lloop0                    # r1 < 0x80000000 -> loop
.Lchkmem0:
        n     %r3,.L4malign0             # align to multiples of 4M
        st    %r3,.Lmemsize              # store memory size
.Lmemok:

#
# first write a tape mark
#
        bras  %r14,.Ltapemark
#
# write real storage to tape
#	
 	slr   %r2,%r2                          # start at address 0
        bras  %r14,.Lwriter                    # load ramdisk
#
# write another tape mark
#
        bras  %r14,.Ltapemark
#
# everything written, stop processor
#
        lpsw  .Lstopped
#
# subroutine for writing to tape
# Paramters:	
#  R1 = device number
#  R2 = start address
#  R3 = length
.Lwriter:	
        st    %r14,.Lldret
        la    %r12,.Lorbread                   # r12 = address of orb 
	la    %r5,.Lirb                        # r5 = address of irb
        st    %r2,.Lccwwrite+4                 # initialize CCW data addresses
        lctl  %c6,%c6,.Lcr6               
        slr   %r2,%r2
.Lldlp:
        lhi   %r6,3                            # 3 retries
.Lssch:
        ssch  0(%r12)                          # write chunk of IPL_BS bytes
        jnz   .Llderr
.Lw4end:
        bras  %r14,.Lwait4io
        tm    8(%r5),0x82                      # do we have a problem ?
        jnz   .Lrecov
        l     %r0,.Lccwwrite+4                 # update CCW data addresses
        ahi   %r0,IPL_BS
        st    %r0,.Lccwwrite+4
        clr   %r0,%r3                          # enough ?
        jl    .Lldlp
.Ldone:
        l     %r14,.Lldret
        br    %r14                             # r2 contains the total size
.Lrecov:
        bras  %r14,.Lsense                     # do the sensing
        brct  %r6,.Lssch                       # dec. retry count & branch
        j     .Llderr
.Ltapemark:
        st    %r14,.Lldret
        la    %r12,.Lorbmark                   # r12 = address of orb
        la    %r5,.Lirb                        # r5 = address of irb
        lctl  %c6,%c6,.Lcr6
        ssch  0(%r12)                          # write a tape mark
        jnz   .Llderr
        bras  %r14,.Lwait4io
        l     %r14,.Lldret
        br    %r14
#
# Sense subroutine
#
.Lsense:
        st    %r14,.Lsnsret
        la    %r7,.Lorbsense              
        ssch  0(%r7)                           # start sense command
        jnz   .Llderr
        bras  %r14,.Lwait4io
        l     %r14,.Lsnsret
        tm    8(%r5),0x82                      # do we have a problem ?
        jnz   .Llderr
        br    %r14
#
# Wait for interrupt subroutine
#
.Lwait4io:
        lpsw  .Lwaitpsw                 
.Lioint:
        c     %r1,0xb8                         # compare subchannel number
        jne   .Lwait4io
        tsch  0(%r5)
        slr   %r0,%r0
        tm    8(%r5),0x82                      # do we have a problem ?
        jnz   .Lwtexit
        tm    8(%r5),0x04                      # got device end ?
        jz    .Lwait4io
.Lwtexit:
        br    %r14
.Llderr:
        lpsw  .Lcrash              

        .align 8
.Lorbread:
	.long  0x00000000,0x0080ff00,.Lccwwrite
        .align 8
.Lorbsense:
        .long  0x00000000,0x0080ff00,.Lccwsense
        .align 8
.Lorbmark:
        .long  0x00000000,0x0080ff00,.Lccwmark
        .align 8
.Lccwwrite:
        .long  0x01200000+IPL_BS,0x00000000
.Lccwsense:
        .long  0x04200001,0x00000000
.Lccwmark:
        .long  0x1f200001,0x00000000
.Lwaitpsw:
	.long  0x020a0000,0x80000000+.Lioint

.Lirb:	.long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.Lcr6:  .long  0xff000000
        .align 8
.Lcrash:.long  0x000a0000,0x00000000
.Lstopped: .long 0x000a0000,0x00001234
.Lpcmem0:.long  0x00080000,0x80000000 + .Lchkmem0
.L4malign0:.long 0xffc00000
.Lmemsize:.long 0
.Lldret:.long  0
.Lsnsret: .long 0

         .org IPL_BS

