Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / slof / fs / ide.fs
1 \ *****************************************************************************
2 \ * Copyright (c) 2004, 2008 IBM Corporation
3 \ * All rights reserved.
4 \ * This program and the accompanying materials
5 \ * are made available under the terms of the BSD License
6 \ * which accompanies this distribution, and is available at
7 \ * http://www.opensource.org/licenses/bsd-license.php
8 \ *
9 \ * Contributors:
10 \ *     IBM Corporation - initial implementation
11 \ ****************************************************************************/
12 \
13 \ 26.06.2007  added: two devices (Master/Slave) per channel
14
15 1 encode-int s" #address-cells" property
16 0 encode-int s" #size-cells" property
17
18 : decode-unit  1 hex-decode-unit ;
19 : encode-unit  1 hex-encode-unit ;
20
21 0 VALUE >ata                                 \ base address for command-block
22 0 VALUE >ata1                                \ base address for control block
23
24 true VALUE no-timeout                        \ flag that no timeout occurred
25
26 0c  CONSTANT #cdb-bytes                      \ command descriptor block (12 bytes)
27 800 CONSTANT atapi-size
28 200 CONSTANT ata-size
29
30 \ *****************************
31 \ Some register access helpers.
32 \ *****************************
33 : ata-ctrl! 2 >ata1 + io-c! ;                      \ device control reg
34 : ata-astat@ 2 >ata1 + io-c@ ;                     \ read alternate status
35                                                    
36 : ata-data@ 0 >ata + io-w@ ;                       \ data reg
37 : ata-data! 0 >ata + io-w! ;                       \ data reg
38 : ata-err@  1 >ata + io-c@ ;                       \ error reg
39 : ata-feat! 1 >ata + io-c! ;                       \ feature reg
40 : ata-cnt@  2 >ata + io-c@ ;                       \ sector count reg
41 : ata-cnt!  2 >ata + io-c! ;                       \ sector count reg
42 : ata-lbal! 3 >ata + io-c! ;                       \ lba low reg
43 : ata-lbal@ 3 >ata + io-c@ ;                       \ lba low reg
44 : ata-lbam! 4 >ata + io-c! ;                       \ lba mid reg
45 : ata-lbam@ 4 >ata + io-c@ ;                       \ lba mid reg
46 : ata-lbah! 5 >ata + io-c! ;                       \ lba high reg
47 : ata-lbah@ 5 >ata + io-c@ ;                       \ lba high reg
48 : ata-dev!  6 >ata + io-c! ;                       \ device reg
49 : ata-dev@  6 >ata + io-c@ ;                       \ device reg
50 : ata-cmd!  7 >ata + io-c! ;                       \ command reg
51 : ata-stat@ 7 >ata + io-c@ ;                       \ status reg
52
53 \ **********************************************************************
54 \ ATA / ATAPI Commands specifications:
55 \ - AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS)
56 \ - ATA Packet Interface for CD-ROMs SFF-8020i
57 \ - ATA/ATAPI Host Adapters Standard (T13/1510D)
58 \ **********************************************************************
59 00 CONSTANT cmd#nop                                \ ATA and ATAPI
60 08 CONSTANT cmd#device-reset                       \ ATAPI only (mandatory)
61 20 CONSTANT cmd#read-sector                        \ ATA and ATAPI
62 90 CONSTANT cmd#execute-device-diagnostic          \ ATA and ATAPI
63 a0 CONSTANT cmd#packet                             \ ATAPI only (mandatory)
64 a1 CONSTANT cmd#identify-packet-device             \ ATAPI only (mandatory)
65 ec CONSTANT cmd#identify-device                    \ ATA and ATAPI
66
67 \ *****************************
68 \ Setup Regs for ATA:
69 \ BAR 0 & 1 : Device 0
70 \ BAR 2 & 3 : Device 1
71 \ *****************************
72 : set-regs ( n -- )
73    dup
74    01 and                                    \ only Chan 0 or Chan 1 allowed
75    3 lshift dup 10 + config-l@ -4 and to >ata
76    14 + config-l@ -4 and to >ata1
77    02 ata-ctrl!                              \ disable interrupts
78    02 and
79    IF
80       10
81    ELSE
82       00
83    THEN
84    ata-dev!
85 ;
86
87 ata-size VALUE block-size
88 80000    VALUE max-transfer            \ Arbitrary, really
89
90 CREATE sector d# 512 allot
91 CREATE packet-cdb #cdb-bytes allot
92 CREATE return-buffer atapi-size allot
93
94 scsi-open                             \ add scsi functions
95
96 \ ********************************
97 \ show all ATAPI-registers
98 \ data-register not read in order
99 \ to not influence PIO mode
100 \ ********************************
101 : show-regs
102    cr
103    cr ." alt. Status: " ata-astat@ .
104    cr ." Status     : " ata-stat@ .
105    cr ." Device     : " ata-dev@ .
106    cr ." Error-Reg  : " ata-err@ .
107    cr ." Sect-Count : " ata-cnt@ .
108    cr ." LBA-Low    : " ata-lbal@ .
109    cr ." LBA-Med    : " ata-lbam@ .
110    cr ." LBA-High   : " ata-lbah@ .
111 ;
112
113 \ ***************************************************
114 \ reads ATAPI-Status and displays it if check-bit set
115 \ ***************************************************
116 : status-check               ( -- )
117    ata-stat@
118    dup   
119    01 and                                    \ is 'check' flag set ?
120    IF
121       cr
122       ."    - ATAPI-Status: " .
123       ata-err@                               \ retrieve sense code
124       dup
125       60 =                                   \ sense code = 6 ?
126       IF
127          ." ( media changed or reset )"      \ 'unit attention'
128          drop                                \ drop err-reg content
129       ELSE
130          dup
131          ." (Err : " .                       \ show err-reg content
132          space
133          rshift 4 .sense-text                \ show text string
134          29 emit
135       THEN
136       cr
137    ELSE
138       drop                                   \ remove unused status      
139    THEN      
140 ;
141
142 \ *************************************
143 \ Wait for interface ready condition
144 \ Bit 7 of Status-Register is busy flag
145 \ new version with abort after 5 sec.
146 \ *************************************
147 : wait-for-ready
148    get-msecs                                 \ start timer
149    BEGIN
150       ata-stat@ 80 and 0<>                   \ busy flag still set ?
151       no-timeout and
152       WHILE                                  \ yes
153          dup get-msecs swap
154          -                                   \ calculate timer difference
155          FFFF AND                            \ reduce to 65.5 seconds
156          d# 5000 >                           \ difference > 5 seconds ?
157          IF
158             false to no-timeout
159          THEN
160       REPEAT
161    drop
162 ;
163
164 \ *************************************
165 \ wait for specific status bits
166 \ new version with abort after 5 sec.
167 \ *************************************
168 : wait-for-status          ( val mask -- )
169    get-msecs                                 \ initial timer value (start)
170    >r
171    BEGIN
172       2dup                                   \ val mask
173       ata-stat@ and <>                       \ expected status ?
174       no-timeout and                         \ and no timeout ?
175       WHILE      
176       get-msecs r@ -                         \ calculate timer difference
177       FFFF AND                               \ mask-off overflow bits
178       d# 5000 >                              \ 5 seconds exceeded ?
179       IF
180          false to no-timeout                 \ set global flag
181       THEN      
182    REPEAT                  
183    r>                                        \ clean return stack
184    3drop
185 ;
186
187 \ *********************************    
188 \ remove extra spaces from string end
189 \ *********************************    
190 : cut-string      ( saddr nul -- )
191    swap
192    over +
193    swap   
194    1 rshift                                  \ bytecount -> wordcount
195    0 do
196       /w -
197       dup               ( addr -- addr addr )
198       w@                ( addr addr -- addr nuw )
199       dup               ( addr nuw -- addr nuw nuw )
200       2020 =
201       IF
202          drop
203          0 
204       ELSE
205          LEAVE         
206       THEN
207       over         
208       w!
209    LOOP
210    drop
211    drop
212
213
214 \ ****************************************************
215 \ prints model-string received by identify device
216 \ ****************************************************
217 : show-model          ( dev# chan# -- )
218    2dup
219    ."    CH " .                  \ channel 0 / 1
220    0= IF ." / MA"                \ Master / Slave
221    ELSE  ." / SL"
222    THEN
223    swap
224    2 * + ."  (@" . ." ) : "      \ device number
225    sector 1 +
226    c@
227    80 AND 0=
228    IF
229       ." ATA-Drive    "
230    ELSE
231       ." ATAPI-Drive  "
232    THEN
233
234    22 emit                       \ start string display with "
235    sector d# 54 +                \ string starts 54 bytes from buffer start
236    dup
237    d# 40                         \ and is 40 chars long
238    cut-string                    \ remove all trailing spaces
239    
240    BEGIN
241       dup
242       w@
243       wbflip
244       wbsplit
245       dup 0<>                    \ first char
246       IF                   
247          emit
248          dup 0<>                 \ second char
249          IF
250             emit
251             wa1+                 \ increment address for next
252             false
253          ELSE                    \ second char = EndOfString
254             drop
255             true
256          THEN   
257       ELSE                       \ first char = EndOfString
258          drop
259          drop
260          true
261       THEN
262    UNTIL                         \ end of string detected
263    drop
264    22 emit                       \ end string display
265                                                   
266    sector c@                     \ get lower byte of first doublet
267    80 AND                        \ check bit 7
268    IF
269       ."  (removable media)"
270    THEN
271    
272    sector 1 +
273    c@
274    80 AND 0= IF                  \ is this an ATA drive ?
275       sector d# 120 +            \ get word 60 + 61
276       rl@-le                     \ read 32-bit as little endian value
277       d# 512                     \ standard ATA block-size
278       swap
279       .capacity-text ( block-size #blocks -- )
280    THEN
281    
282     sector d# 98 +               \ goto word 49
283     w@
284     wbflip
285     200 and 0= IF cr ."    ** LBA is not supported " THEN   
286
287    sector c@                     \ get lower byte of first doublet
288    03 AND 01 =                   \ we use 12-byte packet commands (=00b)
289    IF
290       cr ."    packet size = 16 ** not supported ! **"
291    THEN
292    no-timeout not                \ any timeout occurred so far ?
293    IF
294       cr   ."    ** timeout **"
295    THEN
296 ;
297
298 \ ****************************
299 \ ATA functions
300 \ ****************************
301 : pio-sector ( addr -- )  100 0 DO ata-data@
302    over w! wa1+ LOOP drop ;
303 : pio-sector ( addr -- ) 
304   wait-for-ready pio-sector ;
305 : pio-sectors ( n addr -- )  swap 0 ?DO dup pio-sector 200 + LOOP drop ;
306
307 : lba!  lbsplit   
308    0f and 40 or                  \ always set LBA-mode + LBA (27..24)
309    ata-dev@ 10 and or            \ add current device-bit (DEV)
310    ata-dev!                      \ set LBA (27..24)
311    ata-lbah!                     \ set LBA (23..16)
312    ata-lbam!                     \ set LBA (15..8)
313    ata-lbal!                     \ set LBA (7..0)
314 ;
315
316 : read-sectors ( lba count addr -- ) 
317   >r dup >r ata-cnt! lba! 20 ata-cmd! r> r> pio-sectors ;
318
319 : read-sectors ( lba count addr dev-nr -- )
320     set-regs             ( lba count addr ) \ Set ata regs 
321     BEGIN >r dup 100 > WHILE
322        over 100 r@ read-sectors
323        >r 100 + r> 100 - r> 20000 + REPEAT
324     r> read-sectors
325 ;
326
327 : ata-read-blocks                ( addr block# #blocks dev# -- #read )
328    swap dup >r swap >r rot r>    ( addr block# #blocks dev # R: #blocks )
329    read-sectors r>               ( R: #read )
330 ;    
331
332 \ *******************************
333 \ ATAPI functions
334 \ preset LBA register with maximum
335 \ allowed block-size (16-bits)
336 \ *******************************
337 : set-lba                              ( block-length -- )
338    lbsplit                             ( quad -- b1.lo b2 b3 b4.hi )
339    drop                                \ skip upper two bytes
340    drop
341    ata-lbah!
342    ata-lbam!
343 ;
344    
345 \ *******************************************
346 \ gets byte-count and reads a block of words
347 \ from data-register to a buffer
348 \ *******************************************
349 : read-pio-block                        ( buff-addr -- buff-addr-new )
350    ata-lbah@ 8 lshift                  \ get block length High
351    ata-lbam@ or                        \ get block length Low
352    1 rshift                            \ bcount -> wcount
353    dup
354    0> IF                               \ any data to transfer?
355       0 DO                             \ words to read
356          dup                           \ buffer-address
357          ata-data@ swap w!             \ write 16-bits
358          wa1+                          \ address of next entry
359          LOOP
360       ELSE
361          drop                          ( buff-addr wcount -- buff-addr )
362       THEN
363    wait-for-ready
364 ;
365
366 \ ********************************************
367 \ ATAPI support
368 \ Send a command block (12 bytes) in PIO mode
369 \ read data if requested
370 \ ********************************************
371 : send-atapi-packet                    ( req-buffer -- )
372    >r                                  (   R: req-buffer )
373    atapi-size set-lba                  \ set regs to length limit
374    00 ata-feat!
375    cmd#packet ata-cmd!                 \ A0 = ATAPI packet command
376    48 C8  wait-for-status     ( val mask -- )  \ BSY:0 DRDY:1 DRQ:1
377    6 0  do
378       packet-cdb i 2 * +                \ transfer command block (12 bytes)
379       w@
380       ata-data!                        \ 6 doublets PIO transfer to device
381       loop                             \ copy packet to data-reg
382    status-check                        ( -- ) \ status err bit set ? -> display
383    wait-for-ready                      ( -- ) \ busy released ?
384    BEGIN
385    ata-stat@ 08 and 08 = WHILE         \ Data-Request-Bit set ?
386       r>                               \ get last target buffer address
387       read-pio-block                   \ only if from device requested
388       >r                               \ start of next block
389       REPEAT
390    r>                                  \ original value
391    drop                                \ return clean
392 ;   
393
394 : atapi-packet-io                      ( -- )
395    return-buffer atapi-size erase      \ clear return buffer
396    return-buffer send-atapi-packet     \ send 'packet-cdb' , get 'return-buffer'
397 ;
398
399
400
401 \ ********************************
402 \ ATAPI packet commands
403 \ ********************************
404
405 \ Methods to access atapi disk
406
407 : atapi-test ( -- true|false )
408    packet-cdb scsi-build-test-unit-ready     \ command-code: 00
409    atapi-packet-io                           ( )  \ send CDB, get return-buffer
410    ata-stat@ 1 and IF false ELSE true THEN
411 ;
412
413 : atapi-sense ( -- ascq asc sense-key )
414    d# 252 packet-cdb scsi-build-request-sense ( alloc-len cdb -- )
415    atapi-packet-io                           ( )  \ send CDB, get return-buffer
416    return-buffer scsi-get-sense-data         ( cdb-addr -- ascq asc sense-key )
417 ;
418
419 : atapi-read-blocks                    ( address block# #blocks dev# -- #read-blocks )
420    set-regs                            ( address block# #blocks )
421    dup >r                              ( address block# #blocks )
422    packet-cdb scsi-build-read-10       ( address block# #blocks cdb -- )
423    send-atapi-packet                   ( address -- )
424    r>                                  \ return requested number of blocks
425 ;
426
427 \ ***************************************
428 \ read capacity of drive medium
429 \ use SCSI-Support Package
430 \ ***************************************
431 : atapi-read-capacity                        ( -- )
432    packet-cdb scsi-build-read-cap-10         \ fill block with command
433    atapi-packet-io                           ( )  \ send CDB, get return-buffer
434    return-buffer scsi-get-capacity-10        ( cdb -- block-size #blocks )
435    .capacity-text                            ( block-size #blocks -- )
436    status-check                              ( -- )
437 ;
438
439 \ ***************************************
440 \ read capacity of drive medium
441 \ use SCSI-Support Package
442 \ ***************************************
443 : atapi-read-capacity-ext                    ( -- )
444    packet-cdb scsi-build-read-cap-16         \ fill block with command
445    atapi-packet-io                           ( )  \ send CDB, get return-buffer
446    return-buffer scsi-get-capacity-16        ( cdb -- block-size #blocks )
447    .capacity-text                            ( block-size #blocks -- )
448    status-check                              ( -- )
449 ;
450
451
452 \ ***********************************************
453 \ wait until media in drive is ready ( max 5 sec)
454 \ ***********************************************
455 : wait-for-media-ready                 ( -- true|false )
456    get-msecs                                 \ initial timer value (start)
457    >r
458    BEGIN
459       atapi-test                             \ unit ready? false if not      
460       not
461       no-timeout and
462       WHILE
463          atapi-sense  ( -- ascq asc sense-key )
464          02 =                                \ sense key 2 = media error
465          IF                                  \ check add. sense code
466             3A =                             \ asc: device not ready ?
467             IF
468                false to no-timeout
469                ."  empty (" . 29 emit        \ show asc qualifier
470             ELSE
471                drop                          \ discard asc qualifier
472             THEN                             \ medium not present, abort waiting
473          ELSE
474             drop                             \ discard asc
475             drop                             \ discard ascq
476          THEN
477          get-msecs r@ -                      \ calculate timer difference
478          FFFF AND                            \ mask-off overflow bits
479          d# 5000 >                           \ 5 seconds exceeded ?
480          IF
481             false to no-timeout              \ set global flag
482          THEN      
483    REPEAT
484    r>
485    drop
486    no-timeout
487 ;
488
489 \ ******************************************************
490 \ Method pointer for read-blocks methods
491 \ controller implements 2 channels (primary / secondary)
492 \ for 2 devices each (master / slasve)
493 \ ******************************************************
494 \ 2 channels (primary/secondary) per controller
495 2 CONSTANT #chan 
496
497 \ 2 devices (master/slave) per channel
498 2 CONSTANT #dev
499
500 \ results in a total of devices
501 \ connected to a controller with
502 \ two separate channels (4)
503 : #totaldev #dev #chan * ;
504  
505 CREATE read-blocks-xt #totaldev cells allot read-blocks-xt #totaldev cells erase
506
507 \ Execute read-blocks of device
508 : dev-read-blocks  ( address block# #blocks dev# -- #read-blocks )
509    dup cells read-blocks-xt + @ execute
510 ;
511
512 \ **********************************************************
513 \ Read device type
514 \ Signature      ATAPI             ATA
515 \ ---------------------------------------------
516 \ Sector Count    01h              01h
517 \ Sector Number   01h              01h
518 \ Cylinder Low    14h              00h
519 \ Cylinder High   EBh              00h
520 \ Device/Head     00h or 10h       00h or 01h
521 \ see also ATA/ATAPI errata at:
522 \ http://suif.stanford.edu/~csapuntz/blackmagic.html
523 \ **********************************************************
524 : read-ident  ( -- true|false )
525    false
526    00 ata-lbal!                              \ clear previous signature
527    00 ata-lbam!
528    00 ata-lbah!
529    cmd#identify-device ata-cmd! wait-for-ready \ first try ATA, ATAPI aborts command
530    ata-stat@ CF and 48 =
531    IF
532       drop true                                          \ cmd accepted, this is a ATA
533       d# 512 set-lba                                     \ set LBA to sector-length
534    ELSE                                                  \ ATAPI sends signature instead
535       ata-lbam@ 14 = IF                                  \ cylinder low  = 14 ?
536          ata-lbah@ EB = IF                               \ cylinder high = EB ?
537             cmd#device-reset ata-cmd! wait-for-ready     \ only supported by ATAPI
538             cmd#identify-packet-device ata-cmd! wait-for-ready                     \ first try ata
539             ata-stat@ CF and 48 = IF               
540                drop true                                 \ replace flag
541                THEN
542             THEN
543          THEN
544       THEN
545    dup IF
546       ata-stat@ 8 AND IF                        \ data requested (as expected) ?      
547          sector read-pio-block 
548          drop                                   \ discard address end 
549          ELSE
550          drop false
551          THEN
552       THEN
553    
554    no-timeout not IF                            \ check without any timeout ?
555       drop
556       false                                     \ no, detection discarded
557       THEN
558 ;
559
560 scsi-close                             \ remove scsi commands from word list
561
562
563 \ *************************************************
564 \ Init controller ( chan 0 and 1 )
565 \ device 0 (= master) and device 1 ( = slave)
566 \  #dev  #chan   Dev-ID
567 \ ----------------------
568 \   0      0        0          Master of Channel 0
569 \   0      1        1          Master of Channel 1
570 \   1      0        2          Slave  of Channel 0
571 \   1      1        3          Slave  of Channel 1
572 \ *************************************************
573 : find-disks      ( -- )   
574    #chan 0 DO                                      \ check 2 channels (primary & secondary)
575       #dev 0 DO                                    \ check 2 devices per channel (master / slave)
576          i 2 * j +
577          set-regs                                  \ set base address and dev-register for register access
578          ata-stat@ 7f and 7f <>                    \ Check, if device is connected
579          IF
580             true to no-timeout                     \ preset timeout-flag
581             read-ident        ( -- true|false )
582             IF
583                i j show-model                      \ print manufacturer + device string
584                sector 1+ c@ C0 and 80 =            \ Check for ata or atapi
585                IF
586                   wait-for-media-ready             \ wait up to 5 sec if not ready
587                   no-timeout and
588                   IF
589                      atapi-read-capacity
590                      atapi-size to block-size      \ ATAPI: 2048 bytes
591                      80000 to max-transfer
592                      ['] atapi-read-blocks i 2 * j + cells read-blocks-xt + !
593                      s" cdrom" strdup i 2 * j + s" generic-disk.fs" included
594                   ELSE
595                      ."  -"                        \ show hint for not registered
596                   THEN    
597                ELSE
598                   ata-size to block-size           \ ATA: 512 bytes
599                   80000 to max-transfer
600                   ['] ata-read-blocks i 2 * j + cells read-blocks-xt + !
601                   s" disk" strdup i 2 * j + s" generic-disk.fs" included
602                THEN
603             cr
604             THEN    
605          THEN
606          i 2 * j + 200 + cp
607       LOOP
608    LOOP
609 ;
610
611 find-disks
612