1# 2# arch/s390/boot/ipleckd.S 3# IPL record for 3380/3390 DASD 4# 5# S390 version 6# Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation 7# Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com> 8# 9# 10# FIXME: should use the countarea to determine the blocksize 11# FIXME: should insert zeroes into memory when filling holes 12# FIXME: calculate blkpertrack from rdc data and blksize 13 14# change 09/20/00 removed obsolete store of ipldevice to textesegment 15 16# Usage of registers 17# r1: ipl subchannel ( general use, dont overload without save/restore !) 18# r10: 19# r13: base register index to 0x0000 20# r14: callers address 21# r15: temporary save register (we have no stack!) 22 23# storage layout: 24 25#include <asm/lowcore.h> 26 27 .org 0 28.psw: .long 0x00080000,0x80000000+_start 29.ccw1: .long 0x06000000,0x00001000 # Re-Read enough of bootsector to start 30.ccw2: .long 0x00000000,0x00000000 # read countarea of record 1 to s/w. 31 32 .org 0x58 33.Lextn: .long 0x000a0000,0x00000000+.Lextn 34.Lsvcn: .long 0x000a0000,0x00000000+.Lsvcn 35.Lprgn: .long 0x00080000,0x00000000+.Lecs 36.Lmcn: .long 0x000a0000,0x00000000+.Lmcn 37.Lion: .long 0x00080000,0x80000000+.Lionewaddr 38 39 .org 0xe0 40.Llstad:.long 0x00000000,0x00000000 # sectorno + ct of bootlist 41 42 .org 0xf0 # Lets start now... 43_start: .globl _start 44 l %r1,__LC_SUBCHANNEL_ID # get IPL-subchannel from lowcore 45 st %r1,__LC_IPLDEV # keep it for reipl 46 stsch .Lrdcdata 47 oi .Lrdcdata+5,0x84 # enable ssch and multipath mode 48.Lecs: xi .Lrdcdata+27,0x01 # enable concurrent sense 49 msch .Lrdcdata 50 xi .Lprgn,6 # restore Wait and d/a bit in PCnew PSW 51 l %r2,.Lparm 52 mvc 0x0(8,%r2),.Lnull # set parmarea to null 53 lctl %c6,%c6,.Lc6 # enable all interrupts 54.Lrdc: # read device characteristics 55 la %r6,.Lrdcccw 56 st %r6,.Lorb+8 # store cp-address to orb 57 bras %r15,.Lssch # start I/O 58 oi .Llodata+1,0x80 59 lh %r5,.Lcountarea+6 # init r5 from countarea 60 stcm %r5,3,.Lrdccw+2 # and store into rd template *FIXME* 61 stcm %r5,3,.Llodata+14 # and store into lodata *FIXME* 62.Lbootlist: 63 l %r2,.Llstad 64 l %r3,.Lblklst 65 lhi %r4,1 66 bras %r14,.Lreadblks 67.Lloader: 68 l %r10,.Lblklst # r10 is index to bootlist 69 lhi %r5,4 # r5: skip 4 blocks = firstpage.... 70.Lkloop: 71 clc .Lnull(8),0(%r10) # test blocklist 72 jz .Lchkparm # end of list? 73 l %r2,0(%r10) # get startblock to r2 74 slr %r4,%r4 # erase r4 75 icm %r4,1,7(%r10) # get blockcount 76 slr %r3,%r3 # get address to r3 77 icm %r3,0xe,4(%r10) 78 chi %r5,0 # still blocks to skip? 79 jz .Ldoread # no: start reading 80 cr %r5,%r4 # #skipblocks >= blockct? 81 jm .L007 # no: skip the blocks one by one 82.L006: 83 sr %r5,%r4 # decrease number of blocks to skip 84 j .Lkcont # advance to next entry 85.L007: 86 ahi %r2,1 # skip 1 block... 87 bctr %r4,0 # update blockct 88 ah %r3,.Lcountarea+6 # increment address 89 bct %r5,.L007 # 4 blocks skipped? 90.Ldoread: 91 ltr %r2,%r2 # test startblock 92 jz .Lzeroes # startblocks is zero (hole) 93.Ldiskread: 94 bras %r14,.Lreadblks 95 j .Lkcont 96.Lzeroes: 97 lr %r2,%r3 98.L001: slr %r3,%r3 99 icm %r3,3,.Lcountarea+6 # get blocksize 100 slr %r5,%r5 # no bytes to move 101.L008: mvcle %r2,%r4,0 # fill zeroes to storage 102 jo .L008 # until block is filled 103 brct %r4,.L001 # skip to next block 104.Lkcont: 105 ahi %r10,8 106 j .Lkloop 107.Lchkparm: 108 lm %r3,%r4,.Lstart # load .Lstart and .Lparm 109 clc 0x0(4,%r4),.Lnull 110 je .Lrunkern 111 mvc 0x480(128,%r3),0(%r4) # move 1k-0x80 to parmarea 112 mvc 0x500(256,%r3),0x80(%r4) 113 mvc 0x600(256,%r3),0x180(%r4) 114 mvc 0x700(256,%r3),0x280(%r4) 115.Lrunkern: 116# lhi %r2,17 117# sll %r2,12 118# st %r1,0xc6c(%r2) # store iplsubchannel to lowcore 119# st %r1,0xc6c # store iplsubchannel to lowcore 120 br %r3 121# This function does the start IO 122# r2: number of first block to read ( input by caller ) 123# r3: address to read data to ( input by caller ) 124# r4: number of blocks to read ( input by caller ) 125# r5: destroyed 126# r6: blocks per track ( input by caller ) 127# r7: number of heads 128# r8: 129# r9: 130# r10: 131# r11: temporary register 132# r12: local use for base address 133# r13: base address for module 134# r14: address of caller for subroutine 135# r15: temporary save register (since we have no stack) 136.Lreadblks: 137 la %r12,.Ldeccw 138 st %r12,8+.Lorb # store cpaddr to orb 139 ahi %r12,0x10 # increment r12 to point to rdccw 140 oi 1(%r12),0x40 # set CC in rd template 141 # first setup the read CCWs 142 lr %r15,%r4 # save number or blocks 143 slr %r7,%r7 144 icm %r7,3,.Lrdcdata+14 # load heads to r7 145 lhi %r6,9 146 clc .Lrdcdata+3(2),.L9345 147 je .L011 148 lhi %r6,10 149 clc .Lrdcdata+3(2),.L3380 150 je .L011 151 lhi %r6,12 152 clc .Lrdcdata+3(2),.L3390 153 je .L011 154 bras %r14,.Ldisab 155.L011: 156 # loop for nbl times 157.Lrdloop: 158 mvc 0(8,%r12),.Lrdccw # copy template to this ccw 159 st %r3,4(%r12) # store target address to this ccw 160 bct %r4,.L005 # decrement no of blks still to do 161 ni 1(%r12),0x3f # delete CC from last ccw 162 lr %r4,%r15 # restore number of blocks 163 # read CCWs are setup now 164 stcm %r4,3,.Llodata+2 # store blockno to lodata clears r4 165 ar %r4,%r2 # r4 (clear): ebl = blk + nbl 166 bctr %r4,0 # decrement r4 ( last blk touched 167 srda %r2,32 # trk = blk / bpt, bot = blk % bpt 168 dr %r2,%r6 # r3: trk, r2: bot 169 ahi %r2,1 # bot++ ( we start counting at 1 ) 170 stcm %r2,1,.Llodata+12 # store bot to lodata 171 xr %r2,%r2 # cy = trk / heads, hd = trk % heads 172 dr %r2,%r7 # r3: cy, r2: hd 173 sll %r3,16 # combine to CCHH in r3 174 or %r3,%r2 175 st %r3,.Ldedata+8 # store cchh to dedata 176 st %r3,.Llodata+4 # store cchh to lodata 177 st %r3,.Llodata+8 # store cchh to lodata 178 lr %r15,%r5 # save r5 179 srda %r4,32 # tr2 = ebl / bpt 180 dr %r4,%r6 # r5: tr2, r4: bot2 181 xr %r4,%r4 # cy2 = tr2 / heads, hd2 = hd2 % heads 182 dr %r4,%r7 # r5: cy2, r4: hd2 183 stcm %r5,3,.Ldedata+12 # store cy2,hd2 to dedata 184 stcm %r4,3,.Ldedata+14 # store cy2,hd2 to dedata 185 lr %r5,%r15 # restore r5 186 # CCWs are setup now, arent they? 187 bras %r15,.Lssch # start I/O 188 br %r14 # return to caller 189.L005: 190 ah %r3,.Lcountarea+6 # add blocksize to target address 191 ahi %r12,8 # add sizeof(ccw) to base address 192 j .Lrdloop 193# end of function 194# This function does the start IO 195# r1: Subchannel number 196# r8: ORB address 197# r9: IRB address 198.Lssch: 199 lhi %r13,10 # initialize retries 200.L012: 201 ssch .Lorb # start I/O 202 jz .Ltpi # ok? 203 bras %r14,.Ldisab # error 204.Ltpi: 205 lpsw .Lwaitpsw # load wait-PSW 206.Lionewaddr: 207 c %r1,0xb8 # compare to ipl subhchannel 208 jnz .Ltpi # not equal: loop 209 clc 0xbc(4),.Lorb # cross check the intparm 210 jnz .Ltpi # not equal: loop 211 tsch .Lirb # get status 212 tm .Lirb+9,0xff # channel status ? 213 jz .L003 # CS == 0x00 214 bras %r14,.Ldisab # error 215.L003: 216 tm .Lirb+8,0xf3 # DS different from CE/DE 217 jz .L004 # ok ? 218 bct %r13,.L012 # retries <= 5 ? 219 bras %r14,.Ldisab # error 220.L004: 221 tm .Lirb+8,0x04 # DE set? 222 jz .Ltpi # DE not set, loop 223.Lsschend: 224 br %r15 # return to caller 225# end of function 226# In case of error goto disabled wait with %r14 containing the caller 227.Ldisab: 228 st %r14,.Ldisabpsw+4 229 lpsw .Ldisabpsw 230 231# FIXME pre-initialized data should be listed first 232# NULLed storage can be taken from anywhere ;) 233.Lblklst: 234 .long 0x00002000 235 .align 8 236.Ldisabpsw: 237 .long 0x000a0000,0x00000000 238.Lwaitpsw: 239 .long 0x020a0000,0x00000000+.Ltpi 240.Lorb: 241 .long 0x0049504c,0x0080ff00 # intparm is " IPL" 242.Lc6: .long 0xff000000 243.Lstart: 244 .long 0x00010000 # do not separate .Lstart and .Lparm 245.Lparm: 246 .long 0x00008000 # they are loaded with a LM 247.L3390: 248 .word 0x3390 249.L9345: 250 .word 0x9345 251.L3380: 252 .word 0x3380 253.Lnull: 254 .long 0x00000000,0x00000000 255 .align 4 256.Lrdcdata: 257 .long 0x00000000,0x00000000 258 .long 0x00000000,0x00000000 259 .long 0x00000000,0x00000000 260 .long 0x00000000,0x00000000 261 .long 0x00000000,0x00000000 262 .long 0x00000000,0x00000000 263 .long 0x00000000,0x00000000 264 .long 0x00000000,0x00000000 265.Lirb: 266 .long 0x00000000,0x00000000 267 .long 0x00000000,0x00000000 268 .long 0x00000000,0x00000000 269 .long 0x00000000,0x00000000 270 .long 0x00000000,0x00000000 271 .long 0x00000000,0x00000000 272 .long 0x00000000,0x00000000 273 .long 0x00000000,0x00000000 274.Lcountarea: 275 .word 0x0000 # cyl; 276 .word 0x0000 # head; 277 .byte 0x00 # record; 278 .byte 0x00 # key length; 279 .word 0x0000 # data length == blocksize; 280.Ldedata: 281 .long 0x40c00000,0x00000000 282 .long 0x00000000,0x00000000 283.Llodata: 284 .long 0x06000001,0x00000000 285 .long 0x00000000,0x01000000 286 .long 0x12345678 287 .org 0x7c8 288.Lrdcccw: # CCW read device characteristics 289 .long 0x64400040,0x00000000+.Lrdcdata 290 .long 0x63400010,0x00000000+.Ldedata 291 .long 0x47400010,0x00000000+.Llodata 292 .long 0x12000008,0x00000000+.Lcountarea 293.Ldeccw: 294 .long 0x63400010,0x00000000+.Ldedata 295.Lloccw: 296 .long 0x47400010,0x00000000+.Llodata 297.Lrdccw: 298 .long 0x86400000,0x00000000 299 .org 0x800 300# end of pre initialized data is here CCWarea follows 301# from here we load 1k blocklist 302# end of function 303 304