diff options
Diffstat (limited to 'slof/fs/ide.fs')
-rw-r--r-- | slof/fs/ide.fs | 612 |
1 files changed, 612 insertions, 0 deletions
diff --git a/slof/fs/ide.fs b/slof/fs/ide.fs new file mode 100644 index 0000000..93ca766 --- /dev/null +++ b/slof/fs/ide.fs @@ -0,0 +1,612 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ +\ +\ 26.06.2007 added: two devices (Master/Slave) per channel + +1 encode-int s" #address-cells" property +0 encode-int s" #size-cells" property + +: decode-unit 1 hex-decode-unit ; +: encode-unit 1 hex-encode-unit ; + +0 VALUE >ata \ base address for command-block +0 VALUE >ata1 \ base address for control block + +true VALUE no-timeout \ flag that no timeout occured + +0c CONSTANT #cdb-bytes \ command descriptor block (12 bytes) +800 CONSTANT atapi-size +200 CONSTANT ata-size + +\ ***************************** +\ Some register access helpers. +\ ***************************** +: ata-ctrl! 2 >ata1 + io-c! ; \ device control reg +: ata-astat@ 2 >ata1 + io-c@ ; \ read alternate status + +: ata-data@ 0 >ata + io-w@ ; \ data reg +: ata-data! 0 >ata + io-w! ; \ data reg +: ata-err@ 1 >ata + io-c@ ; \ error reg +: ata-feat! 1 >ata + io-c! ; \ feature reg +: ata-cnt@ 2 >ata + io-c@ ; \ sector count reg +: ata-cnt! 2 >ata + io-c! ; \ sector count reg +: ata-lbal! 3 >ata + io-c! ; \ lba low reg +: ata-lbal@ 3 >ata + io-c@ ; \ lba low reg +: ata-lbam! 4 >ata + io-c! ; \ lba mid reg +: ata-lbam@ 4 >ata + io-c@ ; \ lba mid reg +: ata-lbah! 5 >ata + io-c! ; \ lba high reg +: ata-lbah@ 5 >ata + io-c@ ; \ lba high reg +: ata-dev! 6 >ata + io-c! ; \ device reg +: ata-dev@ 6 >ata + io-c@ ; \ device reg +: ata-cmd! 7 >ata + io-c! ; \ command reg +: ata-stat@ 7 >ata + io-c@ ; \ status reg + +\ ********************************************************************** +\ ATA / ATAPI Commands specifications: +\ - AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS) +\ - ATA Packet Interface for CD-ROMs SFF-8020i +\ - ATA/ATAPI Host Adapters Standard (T13/1510D) +\ ********************************************************************** +00 CONSTANT cmd#nop \ ATA and ATAPI +08 CONSTANT cmd#device-reset \ ATAPI only (mandatory) +20 CONSTANT cmd#read-sector \ ATA and ATAPI +90 CONSTANT cmd#execute-device-diagnostic \ ATA and ATAPI +a0 CONSTANT cmd#packet \ ATAPI only (mandatory) +a1 CONSTANT cmd#identify-packet-device \ ATAPI only (mandatory) +ec CONSTANT cmd#identify-device \ ATA and ATAPI + +\ ***************************** +\ Setup Regs for ATA: +\ BAR 0 & 1 : Device 0 +\ BAR 2 & 3 : Device 1 +\ ***************************** +: set-regs ( n -- ) + dup + 01 and \ only Chan 0 or Chan 1 allowed + 3 lshift dup 10 + config-l@ -4 and to >ata + 14 + config-l@ -4 and to >ata1 + 02 ata-ctrl! \ disable interrupts + 02 and + IF + 10 + ELSE + 00 + THEN + ata-dev! +; + +ata-size VALUE block-size +80000 VALUE max-transfer \ Arbitrary, really + +CREATE sector d# 512 allot +CREATE packet-cdb #cdb-bytes allot +CREATE return-buffer atapi-size allot + +scsi-open \ add scsi functions + +\ ******************************** +\ show all ATAPI-registers +\ data-register not read in order +\ to not influence PIO mode +\ ******************************** +: show-regs + cr + cr ." alt. Status: " ata-astat@ . + cr ." Status : " ata-stat@ . + cr ." Device : " ata-dev@ . + cr ." Error-Reg : " ata-err@ . + cr ." Sect-Count : " ata-cnt@ . + cr ." LBA-Low : " ata-lbal@ . + cr ." LBA-Med : " ata-lbam@ . + cr ." LBA-High : " ata-lbah@ . +; + +\ *************************************************** +\ reads ATAPI-Status and displays it if check-bit set +\ *************************************************** +: status-check ( -- ) + ata-stat@ + dup + 01 and \ is 'check' flag set ? + IF + cr + ." - ATAPI-Status: " . + ata-err@ \ retrieve sense code + dup + 60 = \ sense code = 6 ? + IF + ." ( media changed or reset )" \ 'unit attention' + drop \ drop err-reg content + ELSE + dup + ." (Err : " . \ show err-reg content + space + rshift 4 .sense-text \ show text string + 29 emit + THEN + cr + ELSE + drop \ remove unused status + THEN +; + +\ ************************************* +\ Wait for interface ready condition +\ Bit 7 of Status-Register is busy flag +\ new version with abort after 5 sec. +\ ************************************* +: wait-for-ready + get-msecs \ start timer + BEGIN + ata-stat@ 80 and 0<> \ busy flag still set ? + no-timeout and + WHILE \ yes + dup get-msecs swap + - \ calculate timer difference + FFFF AND \ reduce to 65.5 seconds + d# 5000 > \ difference > 5 seconds ? + IF + false to no-timeout + THEN + REPEAT + drop +; + +\ ************************************* +\ wait for specific status bits +\ new version with abort after 5 sec. +\ ************************************* +: wait-for-status ( val mask -- ) + get-msecs \ initial timer value (start) + >r + BEGIN + 2dup \ val mask + ata-stat@ and <> \ expected status ? + no-timeout and \ and no timeout ? + WHILE + get-msecs r@ - \ calculate timer difference + FFFF AND \ mask-off overflow bits + d# 5000 > \ 5 seconds exceeded ? + IF + false to no-timeout \ set global flag + THEN + REPEAT + r> \ clean return stack + 3drop +; + +\ ********************************* +\ remove extra spaces from string end +\ ********************************* +: cut-string ( saddr nul -- ) + swap + over + + swap + 1 rshift \ bytecount -> wordcount + 0 do + /w - + dup ( addr -- addr addr ) + w@ ( addr addr -- addr nuw ) + dup ( addr nuw -- addr nuw nuw ) + 2020 = + IF + drop + 0 + ELSE + LEAVE + THEN + over + w! + LOOP + drop + drop +; + +\ **************************************************** +\ prints model-string received by identify device +\ **************************************************** +: show-model ( dev# chan# -- ) + 2dup + ." CH " . \ channel 0 / 1 + 0= IF ." / MA" \ Master / Slave + ELSE ." / SL" + THEN + swap + 2 * + ." (@" . ." ) : " \ device number + sector 1 + + c@ + 80 AND 0= + IF + ." ATA-Drive " + ELSE + ." ATAPI-Drive " + THEN + + 22 emit \ start string display with " + sector d# 54 + \ string starts 54 bytes from buffer start + dup + d# 40 \ and is 40 chars long + cut-string \ remove all trailing spaces + + BEGIN + dup + w@ + wbflip + wbsplit + dup 0<> \ first char + IF + emit + dup 0<> \ second char + IF + emit + wa1+ \ increment address for next + false + ELSE \ second char = EndOfString + drop + true + THEN + ELSE \ first char = EndOfString + drop + drop + true + THEN + UNTIL \ end of string detected + drop + 22 emit \ end string display + + sector c@ \ get lower byte of first doublet + 80 AND \ check bit 7 + IF + ." (removable media)" + THEN + + sector 1 + + c@ + 80 AND 0= IF \ is this an ATA drive ? + sector d# 120 + \ get word 60 + 61 + rl@-le \ read 32-bit as little endian value + d# 512 \ standard ATA block-size + swap + .capacity-text ( block-size #blocks -- ) + THEN + + sector d# 98 + \ goto word 49 + w@ + wbflip + 200 and 0= IF cr ." ** LBA is not supported " THEN + + sector c@ \ get lower byte of first doublet + 03 AND 01 = \ we use 12-byte packet commands (=00b) + IF + cr ." packet size = 16 ** not supported ! **" + THEN + no-timeout not \ any timeout occured so far ? + IF + cr ." ** timeout **" + THEN +; + +\ **************************** +\ ATA functions +\ **************************** +: pio-sector ( addr -- ) 100 0 DO ata-data@ + over w! wa1+ LOOP drop ; +: pio-sector ( addr -- ) + wait-for-ready pio-sector ; +: pio-sectors ( n addr -- ) swap 0 ?DO dup pio-sector 200 + LOOP drop ; + +: lba! lbsplit + 0f and 40 or \ always set LBA-mode + LBA (27..24) + ata-dev@ 10 and or \ add current device-bit (DEV) + ata-dev! \ set LBA (27..24) + ata-lbah! \ set LBA (23..16) + ata-lbam! \ set LBA (15..8) + ata-lbal! \ set LBA (7..0) +; + +: read-sectors ( lba count addr -- ) + >r dup >r ata-cnt! lba! 20 ata-cmd! r> r> pio-sectors ; + +: read-sectors ( lba count addr dev-nr -- ) + set-regs ( lba count addr ) \ Set ata regs + BEGIN >r dup 100 > WHILE + over 100 r@ read-sectors + >r 100 + r> 100 - r> 20000 + REPEAT + r> read-sectors +; + +: ata-read-blocks ( addr block# #blocks dev# -- #read ) + swap dup >r swap >r rot r> ( addr block# #blocks dev # R: #blocks ) + read-sectors r> ( R: #read ) +; + +\ ******************************* +\ ATAPI functions +\ preset LBA register with maximum +\ allowed block-size (16-bits) +\ ******************************* +: set-lba ( block-length -- ) + lbsplit ( quad -- b1.lo b2 b3 b4.hi ) + drop \ skip upper two bytes + drop + ata-lbah! + ata-lbam! +; + +\ ******************************************* +\ gets byte-count and reads a block of words +\ from data-register to a buffer +\ ******************************************* +: read-pio-block ( buff-addr -- buff-addr-new ) + ata-lbah@ 8 lshift \ get block length High + ata-lbam@ or \ get block length Low + 1 rshift \ bcount -> wcount + dup + 0> IF \ any data to transfer? + 0 DO \ words to read + dup \ buffer-address + ata-data@ swap w! \ write 16-bits + wa1+ \ address of next entry + LOOP + ELSE + drop ( buff-addr wcount -- buff-addr ) + THEN + wait-for-ready +; + +\ ******************************************** +\ ATAPI support +\ Send a command block (12 bytes) in PIO mode +\ read data if requested +\ ******************************************** +: send-atapi-packet ( req-buffer -- ) + >r ( R: req-buffer ) + atapi-size set-lba \ set regs to length limit + 00 ata-feat! + cmd#packet ata-cmd! \ A0 = ATAPI packet command + 48 C8 wait-for-status ( val mask -- ) \ BSY:0 DRDY:1 DRQ:1 + 6 0 do + packet-cdb i 2 * + \ transfer command block (12 bytes) + w@ + ata-data! \ 6 doublets PIO transfer to device + loop \ copy packet to data-reg + status-check ( -- ) \ status err bit set ? -> display + wait-for-ready ( -- ) \ busy released ? + BEGIN + ata-stat@ 08 and 08 = WHILE \ Data-Request-Bit set ? + r> \ get last target buffer address + read-pio-block \ only if from device requested + >r \ start of next block + REPEAT + r> \ original value + drop \ return clean +; + +: atapi-packet-io ( -- ) + return-buffer atapi-size erase \ clear return buffer + return-buffer send-atapi-packet \ send 'packet-cdb' , get 'return-buffer' +; + + + +\ ******************************** +\ ATAPI packet commands +\ ******************************** + +\ Methods to access atapi disk + +: atapi-test ( -- true|false ) + packet-cdb scsi-build-test-unit-ready \ command-code: 00 + atapi-packet-io ( ) \ send CDB, get return-buffer + ata-stat@ 1 and IF false ELSE true THEN +; + +: atapi-sense ( -- ascq asc sense-key ) + d# 252 packet-cdb scsi-build-request-sense ( alloc-len cdb -- ) + atapi-packet-io ( ) \ send CDB, get return-buffer + return-buffer scsi-get-sense-data ( cdb-addr -- ascq asc sense-key ) +; + +: atapi-read-blocks ( address block# #blocks dev# -- #read-blocks ) + set-regs ( address block# #blocks ) + dup >r ( address block# #blocks ) + packet-cdb scsi-build-read-10 ( address block# #blocks cdb -- ) + send-atapi-packet ( address -- ) + r> \ return requested number of blocks +; + +\ *************************************** +\ read capacity of drive medium +\ use SCSI-Support Package +\ *************************************** +: atapi-read-capacity ( -- ) + packet-cdb scsi-build-read-cap-10 \ fill block with command + atapi-packet-io ( ) \ send CDB, get return-buffer + return-buffer scsi-get-capacity-10 ( cdb -- block-size #blocks ) + .capacity-text ( block-size #blocks -- ) + status-check ( -- ) +; + +\ *************************************** +\ read capacity of drive medium +\ use SCSI-Support Package +\ *************************************** +: atapi-read-capacity-ext ( -- ) + packet-cdb scsi-build-read-cap-16 \ fill block with command + atapi-packet-io ( ) \ send CDB, get return-buffer + return-buffer scsi-get-capacity-16 ( cdb -- block-size #blocks ) + .capacity-text ( block-size #blocks -- ) + status-check ( -- ) +; + + +\ *********************************************** +\ wait until media in drive is ready ( max 5 sec) +\ *********************************************** +: wait-for-media-ready ( -- true|false ) + get-msecs \ initial timer value (start) + >r + BEGIN + atapi-test \ unit ready? false if not + not + no-timeout and + WHILE + atapi-sense ( -- ascq asc sense-key ) + 02 = \ sense key 2 = media error + IF \ check add. sense code + 3A = \ asc: device not ready ? + IF + false to no-timeout + ." empty (" . 29 emit \ show asc qualifier + ELSE + drop \ discard asc qualifier + THEN \ medium not present, abort waiting + ELSE + drop \ discard asc + drop \ discard ascq + THEN + get-msecs r@ - \ calculate timer difference + FFFF AND \ mask-off overflow bits + d# 5000 > \ 5 seconds exceeded ? + IF + false to no-timeout \ set global flag + THEN + REPEAT + r> + drop + no-timeout +; + +\ ****************************************************** +\ Method pointer for read-blocks methods +\ controller implements 2 channels (primary / secondary) +\ for 2 devices each (master / slasve) +\ ****************************************************** +\ 2 channels (primary/secondary) per controller +2 CONSTANT #chan + +\ 2 devices (master/slave) per channel +2 CONSTANT #dev + +\ results in a total of devices +\ connected to a controller with +\ two separate channels (4) +: #totaldev #dev #chan * ; + +CREATE read-blocks-xt #totaldev cells allot read-blocks-xt #totaldev cells erase + +\ Execute read-blocks of device +: dev-read-blocks ( address block# #blocks dev# -- #read-blocks ) + dup cells read-blocks-xt + @ execute +; + +\ ********************************************************** +\ Read device type +\ Signature ATAPI ATA +\ --------------------------------------------- +\ Sector Count 01h 01h +\ Sector Number 01h 01h +\ Cylinder Low 14h 00h +\ Cylinder High EBh 00h +\ Device/Head 00h or 10h 00h or 01h +\ see also ATA/ATAPI errata at: +\ http://suif.stanford.edu/~csapuntz/blackmagic.html +\ ********************************************************** +: read-ident ( -- true|false ) + false + 00 ata-lbal! \ clear previous signature + 00 ata-lbam! + 00 ata-lbah! + cmd#identify-device ata-cmd! wait-for-ready \ first try ATA, ATAPI aborts command + ata-stat@ CF and 48 = + IF + drop true \ cmd accepted, this is a ATA + d# 512 set-lba \ set LBA to sector-length + ELSE \ ATAPI sends signature instead + ata-lbam@ 14 = IF \ cylinder low = 14 ? + ata-lbah@ EB = IF \ cylinder high = EB ? + cmd#device-reset ata-cmd! wait-for-ready \ only supported by ATAPI + cmd#identify-packet-device ata-cmd! wait-for-ready \ first try ata + ata-stat@ CF and 48 = IF + drop true \ replace flag + THEN + THEN + THEN + THEN + dup IF + ata-stat@ 8 AND IF \ data requested (as expected) ? + sector read-pio-block + drop \ discard address end + ELSE + drop false + THEN + THEN + + no-timeout not IF \ check without any timeout ? + drop + false \ no, detection discarded + THEN +; + +scsi-close \ remove scsi commands from word list + + +\ ************************************************* +\ Init controller ( chan 0 and 1 ) +\ device 0 (= master) and device 1 ( = slave) +\ #dev #chan Dev-ID +\ ---------------------- +\ 0 0 0 Master of Channel 0 +\ 0 1 1 Master of Channel 1 +\ 1 0 2 Slave of Channel 0 +\ 1 1 3 Slave of Channel 1 +\ ************************************************* +: find-disks ( -- ) + #chan 0 DO \ check 2 channels (primary & secondary) + #dev 0 DO \ check 2 devices per channel (master / slave) + i 2 * j + + set-regs \ set base address and dev-register for register access + ata-stat@ 7f and 7f <> \ Check, if device is connected + IF + true to no-timeout \ preset timeout-flag + read-ident ( -- true|false ) + IF + i j show-model \ print manufacturer + device string + sector 1+ c@ C0 and 80 = \ Check for ata or atapi + IF + wait-for-media-ready \ wait up to 5 sec if not ready + no-timeout and + IF + atapi-read-capacity + atapi-size to block-size \ ATAPI: 2048 bytes + 80000 to max-transfer + ['] atapi-read-blocks i 2 * j + cells read-blocks-xt + ! + s" cdrom" strdup i 2 * j + s" generic-disk.fs" included + ELSE + ." -" \ show hint for not registered + THEN + ELSE + ata-size to block-size \ ATA: 512 bytes + 80000 to max-transfer + ['] ata-read-blocks i 2 * j + cells read-blocks-xt + ! + s" disk" strdup i 2 * j + s" generic-disk.fs" included + THEN + cr + THEN + THEN + i 2 * j + 200 + cp + LOOP + LOOP +; + +find-disks + |