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
10 \ * IBM Corporation - initial implementation
11 \ ****************************************************************************/
13 \ 26.06.2007 added: two devices (Master/Slave) per channel
15 1 encode-int s" #address-cells" property
16 0 encode-int s" #size-cells" property
18 : decode-unit 1 hex-decode-unit ;
19 : encode-unit 1 hex-encode-unit ;
21 0 VALUE >ata \ base address for command-block
22 0 VALUE >ata1 \ base address for control block
24 true VALUE no-timeout \ flag that no timeout occurred
26 0c CONSTANT #cdb-bytes \ command descriptor block (12 bytes)
27 800 CONSTANT atapi-size
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
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
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
67 \ *****************************
69 \ BAR 0 & 1 : Device 0
70 \ BAR 2 & 3 : Device 1
71 \ *****************************
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
87 ata-size VALUE block-size
88 80000 VALUE max-transfer \ Arbitrary, really
90 CREATE sector d# 512 allot
91 CREATE packet-cdb #cdb-bytes allot
92 CREATE return-buffer atapi-size allot
94 scsi-open \ add scsi functions
96 \ ********************************
97 \ show all ATAPI-registers
98 \ data-register not read in order
99 \ to not influence PIO mode
100 \ ********************************
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@ .
113 \ ***************************************************
114 \ reads ATAPI-Status and displays it if check-bit set
115 \ ***************************************************
116 : status-check ( -- )
119 01 and \ is 'check' flag set ?
122 ." - ATAPI-Status: " .
123 ata-err@ \ retrieve sense code
125 60 = \ sense code = 6 ?
127 ." ( media changed or reset )" \ 'unit attention'
128 drop \ drop err-reg content
131 ." (Err : " . \ show err-reg content
133 rshift 4 .sense-text \ show text string
138 drop \ remove unused status
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 \ *************************************
148 get-msecs \ start timer
150 ata-stat@ 80 and 0<> \ busy flag still set ?
154 - \ calculate timer difference
155 FFFF AND \ reduce to 65.5 seconds
156 d# 5000 > \ difference > 5 seconds ?
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)
173 ata-stat@ and <> \ expected status ?
174 no-timeout and \ and no timeout ?
176 get-msecs r@ - \ calculate timer difference
177 FFFF AND \ mask-off overflow bits
178 d# 5000 > \ 5 seconds exceeded ?
180 false to no-timeout \ set global flag
183 r> \ clean return stack
187 \ *********************************
188 \ remove extra spaces from string end
189 \ *********************************
190 : cut-string ( saddr nul -- )
194 1 rshift \ bytecount -> wordcount
197 dup ( addr -- addr addr )
198 w@ ( addr addr -- addr nuw )
199 dup ( addr nuw -- addr nuw nuw )
214 \ ****************************************************
215 \ prints model-string received by identify device
216 \ ****************************************************
217 : show-model ( dev# chan# -- )
219 ." CH " . \ channel 0 / 1
220 0= IF ." / MA" \ Master / Slave
224 2 * + ." (@" . ." ) : " \ device number
234 22 emit \ start string display with "
235 sector d# 54 + \ string starts 54 bytes from buffer start
237 d# 40 \ and is 40 chars long
238 cut-string \ remove all trailing spaces
248 dup 0<> \ second char
251 wa1+ \ increment address for next
253 ELSE \ second char = EndOfString
257 ELSE \ first char = EndOfString
262 UNTIL \ end of string detected
264 22 emit \ end string display
266 sector c@ \ get lower byte of first doublet
269 ." (removable media)"
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
279 .capacity-text ( block-size #blocks -- )
282 sector d# 98 + \ goto word 49
285 200 and 0= IF cr ." ** LBA is not supported " THEN
287 sector c@ \ get lower byte of first doublet
288 03 AND 01 = \ we use 12-byte packet commands (=00b)
290 cr ." packet size = 16 ** not supported ! **"
292 no-timeout not \ any timeout occurred so far ?
298 \ ****************************
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 ;
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)
316 : read-sectors ( lba count addr -- )
317 >r dup >r ata-cnt! lba! 20 ata-cmd! r> r> pio-sectors ;
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
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 )
332 \ *******************************
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
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
354 0> IF \ any data to transfer?
357 ata-data@ swap w! \ write 16-bits
358 wa1+ \ address of next entry
361 drop ( buff-addr wcount -- buff-addr )
366 \ ********************************************
368 \ Send a command block (12 bytes) in PIO mode
369 \ read data if requested
370 \ ********************************************
371 : send-atapi-packet ( req-buffer -- )
373 atapi-size set-lba \ set regs to length limit
375 cmd#packet ata-cmd! \ A0 = ATAPI packet command
376 48 C8 wait-for-status ( val mask -- ) \ BSY:0 DRDY:1 DRQ:1
378 packet-cdb i 2 * + \ transfer command block (12 bytes)
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 ?
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
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'
401 \ ********************************
402 \ ATAPI packet commands
403 \ ********************************
405 \ Methods to access atapi disk
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
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 )
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
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 -- )
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 -- )
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)
459 atapi-test \ unit ready? false if not
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 ?
469 ." empty (" . 29 emit \ show asc qualifier
471 drop \ discard asc qualifier
472 THEN \ medium not present, abort waiting
477 get-msecs r@ - \ calculate timer difference
478 FFFF AND \ mask-off overflow bits
479 d# 5000 > \ 5 seconds exceeded ?
481 false to no-timeout \ set global flag
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
497 \ 2 devices (master/slave) per channel
500 \ results in a total of devices
501 \ connected to a controller with
502 \ two separate channels (4)
503 : #totaldev #dev #chan * ;
505 CREATE read-blocks-xt #totaldev cells allot read-blocks-xt #totaldev cells erase
507 \ Execute read-blocks of device
508 : dev-read-blocks ( address block# #blocks dev# -- #read-blocks )
509 dup cells read-blocks-xt + @ execute
512 \ **********************************************************
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 )
526 00 ata-lbal! \ clear previous signature
529 cmd#identify-device ata-cmd! wait-for-ready \ first try ATA, ATAPI aborts command
530 ata-stat@ CF and 48 =
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
546 ata-stat@ 8 AND IF \ data requested (as expected) ?
547 sector read-pio-block
548 drop \ discard address end
554 no-timeout not IF \ check without any timeout ?
556 false \ no, detection discarded
560 scsi-close \ remove scsi commands from word list
563 \ *************************************************
564 \ Init controller ( chan 0 and 1 )
565 \ device 0 (= master) and device 1 ( = slave)
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 \ *************************************************
574 #chan 0 DO \ check 2 channels (primary & secondary)
575 #dev 0 DO \ check 2 devices per channel (master / slave)
577 set-regs \ set base address and dev-register for register access
578 ata-stat@ 7f and 7f <> \ Check, if device is connected
580 true to no-timeout \ preset timeout-flag
581 read-ident ( -- true|false )
583 i j show-model \ print manufacturer + device string
584 sector 1+ c@ C0 and 80 = \ Check for ata or atapi
586 wait-for-media-ready \ wait up to 5 sec if not ready
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
595 ." -" \ show hint for not registered
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