Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / slof / fs / scsi-support.fs
diff --git a/qemu/roms/SLOF/slof/fs/scsi-support.fs b/qemu/roms/SLOF/slof/fs/scsi-support.fs
new file mode 100644 (file)
index 0000000..3e65c87
--- /dev/null
@@ -0,0 +1,847 @@
+\ *****************************************************************************
+\ * 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
+\ ****************************************************************************/
+
+\ ************************************************
+\ create a new scsi word-list named 'scsi-words'
+\ ************************************************
+vocabulary scsi-words                  \ create new word list named 'scsi-words'
+also scsi-words  definitions           \ place next definitions into new list
+
+\ for some commands specific parameters are used, which normally
+\ need not to be altered. These values are preset at include time
+\ or explicit by a call of 'scsi-supp-init'
+false  value   scsi-param-debug        \ common debugging flag
+d# 0   value   scsi-param-size         \ length of CDB processed last
+h# 0   value   scsi-param-control      \ control word for CDBs as defined in SAM-4
+d# 0   value   scsi-param-errors       \ counter for detected errors
+
+\ utility to increment error counter
+: scsi-inc-errors
+   scsi-param-errors 1 + to scsi-param-errors
+;
+
+\ ***************************************************************************
+\ SCSI-Command: TEST UNIT READY
+\         Type: Primary Command (SPC-3 clause 6.33)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-test-unit-ready    ( cdb -- )
+\ ***************************************************************************
+\ checks if a device is ready to receive commands
+\ ***************************************************************************
+\ command code:
+00 CONSTANT scsi-cmd-test-unit-ready
+\ CDB structure:
+STRUCT
+       /c      FIELD test-unit-ready>operation-code     \ 00h
+       4       FIELD test-unit-ready>reserved           \ unused
+       /c      FIELD test-unit-ready>control            \ control byte as specified in SAM-4
+CONSTANT scsi-length-test-unit-ready
+
+\ cdb build:
+\ all fields are zeroed
+: scsi-build-test-unit-ready  ( cdb -- )
+   dup scsi-length-test-unit-ready erase  ( cdb )
+   scsi-param-control swap test-unit-ready>control c!  ( )
+   scsi-length-test-unit-ready to scsi-param-size   \ update CDB length
+;
+
+\ ***************************************************************************
+\ SCSI-Command: REPORT LUNS
+\         Type: Primary Command
+\ ***************************************************************************
+\ Forth Word:   scsi-build-report-luns    ( cdb -- )
+\ ***************************************************************************
+\ report all LUNs supported by a device
+\ ***************************************************************************
+\ command code:
+a0 CONSTANT scsi-cmd-report-luns
+\ CDB structure:
+STRUCT
+       /c      FIELD report-luns>operation-code     \ a0h
+       1       FIELD report-luns>reserved           \ unused
+        /c      FIELD report-luns>select-report      \ report select byte
+        3       FIELD report-luns>reserved2          \ unused
+        /l      FIELD report-luns>alloc-length       \ report length
+       1       FIELD report-luns>reserved3          \ unused
+       /c      FIELD report-luns>control            \ control byte
+CONSTANT scsi-length-report-luns
+
+\ cdb build:
+\ all fields are zeroed
+: scsi-build-report-luns ( alloc-len cdb -- )
+   dup scsi-length-report-luns erase              \ 12 bytes CDB
+       scsi-cmd-report-luns over                 ( alloc-len cdb cmd cdb )
+       report-luns>operation-code c!             ( alloc-len cdb )
+   scsi-param-control over report-luns>control c! ( alloc-len cdb )
+       report-luns>alloc-length l!       \ size of Data-In Buffer
+   scsi-length-report-luns to scsi-param-size     \ update CDB length
+;
+
+\ ***************************************************************************
+\ SCSI-Command: REQUEST SENSE
+\         Type: Primary Command (SPC-3 clause 6.27)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-request-sense    ( cdb -- )
+\ ***************************************************************************
+\ for return data a buffer of at least 252 bytes must be present!
+\ see spec: SPC-3 (r23) / clauses 4.5 and 6.27
+\ ***************************************************************************
+\ command code:
+03 CONSTANT scsi-cmd-request-sense
+\ CDB structure:
+STRUCT
+       /c      FIELD request-sense>operation-code     \ 03h
+       3       FIELD request-sense>reserved           \ unused
+       /c      FIELD request-sense>allocation-length  \ buffer-length for data response
+       /c      FIELD request-sense>control            \ control byte as specified in SAM-4
+CONSTANT scsi-length-request-sense
+
+\ cdb build:
+: scsi-build-request-sense    ( alloc-len cdb -- )
+   >r                         ( alloc-len )  ( R: -- cdb )
+   r@ scsi-length-request-sense erase  ( alloc-len )
+   scsi-cmd-request-sense r@           ( alloc-len cmd cdb )
+   request-sense>operation-code c!     ( alloc-len )
+   dup d# 252 >                        \ buffer length too big ?
+   IF
+      scsi-inc-errors
+      drop d# 252                      \ replace with 252
+   ELSE
+      dup d# 18 <                      \ allocated buffer too small ?
+      IF
+         scsi-inc-errors
+         drop 0                        \ reject return data
+      THEN
+   THEN                                      ( alloclen )
+   r@ request-sense>allocation-length c!     (  )
+   scsi-param-control r> request-sense>control c!  ( alloc-len cdb )  ( R: cdb -- )
+   scsi-length-request-sense to scsi-param-size  \ update CDB length
+;
+
+\ ----------------------------------------
+\ SCSI-Response: SENSE_DATA
+\ ----------------------------------------
+70 CONSTANT scsi-response(request-sense-0)
+71 CONSTANT scsi-response(request-sense-1)
+
+STRUCT
+   /c FIELD sense-data>response-code   \ 70h (current errors) or 71h (deferred errors)
+   /c FIELD sense-data>obsolete
+   /c FIELD sense-data>sense-key       \ D3..D0 = sense key, D7 = EndOfMedium
+   /l FIELD sense-data>info
+   /c FIELD sense-data>alloc-length    \ <= 244 (for max size)
+   /l FIELD sense-data>command-info
+   /c FIELD sense-data>asc             \ additional sense key
+   /c FIELD sense-data>ascq            \ additional sense key qualifier
+   /c FIELD sense-data>unit-code
+   3  FIELD sense-data>key-specific
+   /c FIELD sense-data>add-sense-bytes \ start of appended extra bytes
+CONSTANT scsi-length-sense-data
+
+\ ----------------------------------------
+\ get from SCSI response block:
+\  - Additional Sense Code Qualifier
+\  - Additional Sense Code
+\  - sense-key
+\ ----------------------------------------
+\ Forth Word:   scsi-get-sense-data  ( addr -- ascq asc sense-key )
+\ ----------------------------------------
+: scsi-get-sense-data                  ( addr -- ascq asc sense-key )   
+   >r                                  ( R: -- addr )
+   r@ sense-data>response-code c@ 7f and 72 >= IF
+     r@ 3 + c@                           ( ascq )
+     r@ 2 + c@                           ( ascq asc ) 
+     r> 1 + c@ 0f and                    ( ascq asc sense-key )
+   ELSE
+     r@ sense-data>ASCQ c@               ( ascq )
+     r@ sense-data>ASC c@                ( ascq asc )
+     r> sense-data>sense-key c@ 0f and   ( ascq asc sense-key ) ( R: addr -- )
+   THEN
+;
+
+\ --------------------------------------------------------------------------
+\ Forth Word:   scsi-get-sense-data?  ( addr -- false | ascq asc sense-key true )
+\ --------------------------------------------------------------------------
+: scsi-get-sense-data?                 ( addr -- false | ascq asc sense-key true )
+   dup
+   sense-data>response-code c@
+   7e AND dup 70 = swap 72 = or         \ Response code (some devices have MSB set)
+   IF
+      scsi-get-sense-data TRUE
+   ELSE
+      drop FALSE        \ drop addr
+   THEN
+
+;
+
+\ --------------------------------------------------------------------------
+\ Forth Word:   scsi-get-sense-ID?  ( addr -- false | sense-ID true )
+\ same as scsi-get-sense-data? but returns
+\ a single word composed of: sense-key<<16 | asc<<8 | ascq
+\ --------------------------------------------------------------------------
+: scsi-get-sense-ID?                 ( addr -- false | ascq asc sense-key true )
+   dup
+   sense-data>response-code c@
+   7e AND 70 =          \ Response code (some devices have MSB set)
+   IF
+      scsi-get-sense-data        ( ascq asc sense-key )
+      10 lshift                  ( ascq asc sense-key16 )
+      swap 8 lshift or           ( ascq sense-key+asc )
+      swap or                    \ 24-bit sense-ID ( sense-key+asc+ascq )
+      TRUE
+   ELSE
+      drop FALSE        \ drop addr
+   THEN
+;
+
+\ ***************************************************************************
+\ SCSI-Command: INQUIRY
+\         Type: Primary Command (SPC-3 clause 6.4)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-inquiry    ( alloc-len cdb -- )
+\ ***************************************************************************
+\ command code:
+12 CONSTANT scsi-cmd-inquiry
+
+\ CDB structure
+STRUCT
+       /c      FIELD inquiry>operation-code     \ 0x12
+       /c      FIELD inquiry>reserved           \ + EVPD-Bit (vital product data)
+       /c      FIELD inquiry>page-code          \ page code for vital product data (if used)
+       /w      FIELD inquiry>allocation-length  \ length of Data-In-Buffer
+       /c      FIELD inquiry>control            \ control byte as specified in SAM-4
+CONSTANT scsi-length-inquiry
+
+\ Setup command INQUIRY
+: scsi-build-inquiry                   ( alloc-len cdb -- )
+   dup scsi-length-inquiry erase       \ 6 bytes CDB
+       scsi-cmd-inquiry over                              ( alloc-len cdb cmd cdb )
+       inquiry>operation-code c!                ( alloc-len cdb )
+   scsi-param-control over inquiry>control c! ( alloc-len cdb )
+       inquiry>allocation-length w!          \ size of Data-In Buffer
+   scsi-length-inquiry to scsi-param-size    \ update CDB length
+;
+
+\ ----------------------------------------
+\ block structure of inquiry return data:
+\ ----------------------------------------
+STRUCT
+       /c         FIELD inquiry-data>peripheral       \ qualifier and device type
+       /c         FIELD inquiry-data>reserved1
+       /c         FIELD inquiry-data>version          \ supported SCSI version (1,2,3)
+       /c         FIELD inquiry-data>data-format
+       /c         FIELD inquiry-data>add-length       \ total block length - 4
+       /c         FIELD inquiry-data>flags1
+       /c         FIELD inquiry-data>flags2
+       /c         FIELD inquiry-data>flags3
+       d# 8    FIELD inquiry-data>vendor-ident     \ vendor string
+       d# 16   FIELD inquiry-data>product-ident    \ device string
+       /l      FIELD inquiry-data>product-revision \ revision string
+       d# 20   FIELD inquiry-data>vendor-specific  \ optional params
+\ can be increased by vendor specific fields
+CONSTANT scsi-length-inquiry-data
+
+\ ***************************************************************************
+\ SCSI-Command: READ CAPACITY (10)
+\         Type: Block Command (SBC-3 clause 5.12)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-read-capacity-10    ( cdb -- )
+\ ***************************************************************************
+25 CONSTANT scsi-cmd-read-capacity-10  \ command code
+
+STRUCT                                 \ SCSI 10-byte CDB structure
+       /c      FIELD read-cap-10>operation-code
+       /c      FIELD read-cap-10>reserved1
+       /l      FIELD read-cap-10>lba
+       /w      FIELD read-cap-10>reserved2
+       /c      FIELD read-cap-10>reserved3
+       /c      FIELD read-cap-10>control
+CONSTANT scsi-length-read-cap-10
+
+\ Setup READ CAPACITY (10) command
+: scsi-build-read-cap-10                     ( cdb -- )
+   dup scsi-length-read-cap-10 erase         ( cdb )
+       scsi-cmd-read-capacity-10 over            ( cdb cmd cdb )
+       read-cap-10>operation-code c!             ( cdb )
+   scsi-param-control swap read-cap-10>control c! ( )
+   scsi-length-read-cap-10 to scsi-param-size    \ update CDB length
+;
+
+\ ----------------------------------------
+\ get from SCSI response block:
+\  - Additional Sense Code Qualifier
+\  - Additional Sense Code
+\  - sense-key
+\ ----------------------------------------
+\ Forth Word:   scsi-get-capacity-10  ( addr -- block-size #blocks )
+\ ----------------------------------------
+\ Block structure
+STRUCT
+       /l      FIELD read-cap-10-data>max-lba
+       /l      FIELD read-cap-10-data>block-size
+CONSTANT scsi-length-read-cap-10-data
+
+\ get data-block
+: scsi-get-capacity-10                 ( addr -- block-size #blocks )
+   >r                                  ( addr -- ) ( R: -- addr )
+   r@ read-cap-10-data>block-size l@   ( block-size )
+   r> read-cap-10-data>max-lba l@      ( block-size #blocks ) ( R: addr -- )
+;
+
+\ ***************************************************************************
+\ SCSI-Command: READ CAPACITY (16)
+\         Type: Block Command (SBC-3 clause 5.13)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-read-capacity-16    ( cdb -- )
+\ ***************************************************************************
+9e CONSTANT scsi-cmd-read-capacity-16        \ command code
+
+STRUCT                                       \ SCSI 16-byte CDB structure
+       /c      FIELD read-cap-16>operation-code
+       /c      FIELD read-cap-16>service-action
+       /l      FIELD read-cap-16>lba-high
+       /l      FIELD read-cap-16>lba-low
+       /l      FIELD read-cap-16>allocation-length    \ should be 32
+       /c      FIELD read-cap-16>reserved
+       /c      FIELD read-cap-16>control
+CONSTANT scsi-length-read-cap-16
+
+\ Setup READ CAPACITY (16) command
+: scsi-build-read-cap-16  ( cdb -- )
+   >r r@                                     ( R: -- cdb )
+   scsi-length-read-cap-16 erase             (  )
+       scsi-cmd-read-capacity-16                 ( code )
+       r@ read-cap-16>operation-code c!          (  )
+   10 r@ read-cap-16>service-action c!
+   d# 32                                     \ response size 32 bytes
+   r@ read-cap-16>allocation-length l!       (  )
+   scsi-param-control r> read-cap-16>control c! ( R: cdb -- )
+   scsi-length-read-cap-16 to scsi-param-size \ update CDB length
+;
+
+\ ----------------------------------------
+\ get from SCSI response block:
+\  - Block Size (in Bytes)
+\  - Number of Blocks
+\ ----------------------------------------
+\ Forth Word:   scsi-get-capacity-16  ( addr -- block-size #blocks )
+\ ----------------------------------------
+\ Block structure for return data
+STRUCT
+       /l      FIELD read-cap-16-data>max-lba-high    \ upper quadlet of Max-LBA
+       /l      FIELD read-cap-16-data>max-lba-low     \ lower quadlet of Max-LBA
+       /l      FIELD read-cap-16-data>block-size      \ logical block length in bytes
+   /c  FIELD read-cap-16-data>protect         \ type of protection (4 bits)
+   /c  FIELD read-cap-16-data>exponent        \ logical blocks per physical blocks
+   /w  FIELD read-cap-16-data>lowest-aligned  \ first LBA of a phsy. block
+   10 FIELD read-cap-16-data>reserved        \ 16 reserved bytes
+CONSTANT scsi-length-read-cap-16-data        \ results in 32
+
+\ get data-block
+: scsi-get-capacity-16                       ( addr -- block-size #blocks )
+   >r                                        ( R: -- addr )
+   r@ read-cap-16-data>block-size l@         ( block-size )
+   r@ read-cap-16-data>max-lba-high l@       ( block-size #blocks-high )
+   d# 32 lshift                              ( block-size #blocks-upper )
+   r> read-cap-16-data>max-lba-low l@ +      ( block-size #blocks ) ( R: addr -- )
+;
+
+\ ***************************************************************************
+\ SCSI-Command: MODE SENSE (10)
+\         Type: Primary Command (SPC-3 clause 6.10)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-mode-sense-10  ( alloc-len subpage page cdb -- )
+\ ***************************************************************************
+5a CONSTANT scsi-cmd-mode-sense-10
+
+\ CDB structure
+STRUCT
+       /c      FIELD mode-sense-10>operation-code
+       /c      FIELD mode-sense-10>res-llbaa-dbd-res
+       /c      FIELD mode-sense-10>pc-page-code       \ page code + page control
+       /c      FIELD mode-sense-10>sub-page-code
+       3       FIELD mode-sense-10>reserved2
+       /w      FIELD mode-sense-10>allocation-length
+       /c      FIELD mode-sense-10>control
+CONSTANT scsi-length-mode-sense-10
+
+: scsi-build-mode-sense-10                   ( alloc-len subpage page cdb -- )
+   >r                                        ( alloc-len subpage page ) ( R: -- cdb )
+   r@ scsi-length-mode-sense-10 erase        \ 10 bytes CDB
+       scsi-cmd-mode-sense-10                    ( alloc-len subpage page cmd )
+   r@  mode-sense-10>operation-code c!            ( alloc-len subpage page )
+   10 r@ mode-sense-10>res-llbaa-dbd-res c!  \ long LBAs accepted
+       r@ mode-sense-10>pc-page-code c!                 ( alloc-len subpage )
+       r@ mode-sense-10>sub-page-code c!             ( alloc-len )
+       r@ mode-sense-10>allocation-length w!     ( )
+
+   scsi-param-control r> mode-sense-10>control c!  ( R: cdb -- )
+   scsi-length-mode-sense-10 to scsi-param-size  \ update CDB length
+;
+
+\ return data processing
+\ (see spec: SPC-3 clause 7.4.3)
+
+STRUCT
+       /w      FIELD mode-sense-10-data>head-length
+       /c      FIELD mode-sense-10-data>head-medium
+       /c      FIELD mode-sense-10-data>head-param
+       /c      FIELD mode-sense-10-data>head-longlba
+       /c      FIELD mode-sense-10-data>head-reserved
+       /w      FIELD mode-sense-10-data>head-descr-len
+CONSTANT scsi-length-mode-sense-10-data
+
+\ ****************************************
+\ This function shows the mode page header
+\ helpful for further analysis
+\ ****************************************
+: .mode-sense-data   ( addr -- )
+   cr
+   dup mode-sense-10-data>head-length
+   w@ ." Mode Length: " .d space
+   dup mode-sense-10-data>head-medium
+   c@ ." / Medium Type: " .d space
+   dup mode-sense-10-data>head-longlba
+   c@ ." / Long LBA: " .d space
+   mode-sense-10-data>head-descr-len
+   w@ ." / Descr. Length: " .d
+;
+
+\ ***************************************************************************
+\ SCSI-Command: READ (6)
+\         Type: Block Command (SBC-3 clause 5.7)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-read-6  ( block# #blocks cdb -- )
+\ ***************************************************************************
+\ this SCSI command uses 21 bits to represent start LBA
+\ and 8 bits to specify the numbers of blocks to read
+\ The value of 0 blocks is interpreted as 256 blocks
+\
+\ command code
+08 CONSTANT scsi-cmd-read-6
+
+\ CDB structure
+STRUCT
+   /c FIELD read-6>operation-code      \ 08h
+   /c FIELD read-6>block-address-msb   \ upper 5 bits
+   /w FIELD read-6>block-address       \ lower 16 bits
+   /c FIELD read-6>length              \ number of blocks to read
+   /c FIELD read-6>control             \ CDB control
+CONSTANT scsi-length-read-6
+
+: scsi-build-read-6                    ( block# #blocks cdb -- )
+   >r                                  ( block# #blocks ) ( R: -- cdb )
+   r@ scsi-length-read-6 erase         \ 6 bytes CDB
+       scsi-cmd-read-6 r@ read-6>operation-code c! ( block# #blocks )
+
+   \ check block count to read (#blocks)
+   dup d# 255 >                        \ #blocks exceeded limit ?
+   IF
+      scsi-inc-errors
+      drop 1                           \ replace with any valid number
+   THEN
+   r@ read-6>length c!                 \ set #blocks to read
+
+   \ check starting block number (block#)
+   dup 1fffff >                        \ check address upper limit
+   IF
+      scsi-inc-errors
+      drop                             \ remove original block#
+      1fffff                           \ replace with any valid address
+   THEN
+   dup d# 16 rshift
+   r@ read-6>block-address-msb c!      \ set upper 5 bits
+   ffff and
+   r@ read-6>block-address w!                \ set lower 16 bits
+   scsi-param-control r> read-6>control c!   ( R: cdb -- )
+   scsi-length-read-6 to scsi-param-size     \ update CDB length
+;
+
+\ ***************************************************************************
+\ SCSI-Command: READ (10)
+\         Type: Block Command (SBC-3 clause 5.8)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-read-10  ( block# #blocks cdb -- )
+\ ***************************************************************************
+\ command code
+28 CONSTANT scsi-cmd-read-10
+
+\ CDB structure
+STRUCT
+   /c FIELD read-10>operation-code
+   /c FIELD read-10>protect
+   /l FIELD read-10>block-address      \ logical block address (32bits)
+   /c FIELD read-10>group
+   /w FIELD read-10>length             \ transfer length (16-bits)
+   /c FIELD read-10>control
+CONSTANT scsi-length-read-10
+
+: scsi-build-read-10                         ( block# #blocks cdb -- )
+   >r                                        ( block# #blocks )  ( R: -- cdb )
+   r@ scsi-length-read-10 erase             \ 10 bytes CDB
+       scsi-cmd-read-10 r@ read-10>operation-code c! ( block# #blocks )
+   r@ read-10>length w!                      ( block# )
+   r@ read-10>block-address l!               (  )
+   scsi-param-control r> read-10>control c!  ( R: cdb -- )
+   scsi-length-read-10 to scsi-param-size    \ update CDB length
+;
+
+\ ***************************************************************************
+\ SCSI-Command: READ (12)
+\         Type: Block Command (SBC-3 clause 5.9)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-read-12  ( block# #blocks cdb -- )
+\ ***************************************************************************
+\ command code
+a8 CONSTANT scsi-cmd-read-12
+
+\ CDB structure
+STRUCT
+   /c FIELD read-12>operation-code     \ code: a8
+   /c FIELD read-12>protect            \ RDPROTECT, DPO, FUA, FUA_NV
+   /l FIELD read-12>block-address      \ lba
+   /l FIELD read-12>length             \ transfer length (32bits)
+   /c FIELD read-12>group              \ group number
+   /c FIELD read-12>control
+CONSTANT scsi-length-read-12
+
+: scsi-build-read-12                         ( block# #blocks cdb -- )
+   >r                                        ( block# #blocks )  ( R: -- cdb )
+   r@ scsi-length-read-12 erase             \ 12 bytes CDB
+       scsi-cmd-read-12 r@ read-12>operation-code c! ( block# #blocks )
+   r@ read-12>length l!                      ( block# )
+   r@ read-12>block-address l!               (  )
+   scsi-param-control r> read-12>control c!  ( R: cdb -- )
+   scsi-length-read-12 to scsi-param-size    \ update CDB length
+;
+
+\ ***************************************************************************
+\ SCSI-Command: READ with autodetection of required command
+\               read(10) or read(12) depending on parameter size
+\               (read(6) removed because obsolete in some cases (USB))
+\         Type: Block Command
+\ ***************************************************************************
+\ Forth Word:   scsi-build-read?    ( block# #blocks cdb -- )
+\
+\                         +----------------+---------------------------|
+\                         |  block# (lba)  |  #block (transfer-length) |
+\             +-----------+----------------+---------------------------|
+\             | read-6    |  16-Bits       |  8  Bits                  |
+\             | read-10   |  32-Bits       |  16 Bits                  |
+\             | read-12   |  32-Bits       |  32 Bits                  |
+\ ***************************************************************************
+: scsi-build-read?   ( block# #blocks cdb -- length )
+   over              ( block# #blocks cdb #blocks )
+   fffe >            \ tx-length (#blocks) exceeds 16-bit limit ?
+   IF
+      scsi-build-read-12   ( block# #blocks cdb -- )
+      scsi-length-read-12  ( length )
+   ELSE                    ( block# #blocks cdb )
+      scsi-build-read-10   ( block# #blocks cdb -- )
+      scsi-length-read-10  ( length )
+   THEN
+;
+
+\ ***************************************************************************
+\ SCSI-Command: START STOP UNIT
+\         Type: Block Command (SBC-3 clause 5.19)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-start-stop-unit  ( state# cdb -- )
+\ ***************************************************************************
+\ command code
+1b CONSTANT scsi-cmd-start-stop-unit
+
+\ CDB structure
+STRUCT
+   /c FIELD start-stop-unit>operation-code
+   /c FIELD start-stop-unit>immed
+   /w FIELD start-stop-unit>reserved
+   /c FIELD start-stop-unit>pow-condition
+   /c FIELD start-stop-unit>control
+CONSTANT scsi-length-start-stop-unit
+
+\ START/STOP constants
+\ (see spec: SBC-3 clause 5.19)
+f1 CONSTANT scsi-const-active-power    \ param used for start-stop-unit
+f2 CONSTANT scsi-const-idle-power      \ param used for start-stop-unit
+f3 CONSTANT scsi-const-standby-power   \ param used for start-stop-unit
+3  CONSTANT scsi-const-load            \ param used for start-stop-unit
+2  CONSTANT scsi-const-eject           \ param used for start-stop-unit
+1  CONSTANT scsi-const-start
+0  CONSTANT scsi-const-stop
+
+: scsi-build-start-stop-unit                 ( state# cdb -- )
+   >r                                        ( state# )  ( R: -- cdb )
+   r@ scsi-length-start-stop-unit erase      \ 6 bytes CDB
+       scsi-cmd-start-stop-unit r@ start-stop-unit>operation-code c!
+   dup 3 >
+   IF
+      4 lshift                         \ shift to upper nibble
+   THEN                                ( state )
+   r@ start-stop-unit>pow-condition c!       (  )
+   scsi-param-control r> start-stop-unit>control c!  ( R: cdb -- )
+   scsi-length-start-stop-unit to scsi-param-size  \ update CDB length
+;
+
+\ ***************************************************************************
+\ SCSI-Command: SEEK(10)
+\         Type: Block Command (obsolete)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-seek  ( state# cdb -- )
+\ Obsolete function (last listed in spec SBC / Nov. 1997)
+\ implemented only for the sake of completeness
+\ ***************************************************************************
+\ command code
+2b CONSTANT scsi-cmd-seek
+
+\ CDB structure
+STRUCT
+   /c FIELD seek>operation-code
+   /c FIELD seek>reserved1
+   /l FIELD seek>lba
+   3  FIELD seek>reserved2
+   /c FIELD seek>control
+CONSTANT scsi-length-seek
+
+: scsi-build-seek  ( lba cdb -- )
+   >r              ( lba )  ( R: -- cdb )
+   r@ scsi-length-seek erase           \ 10 bytes CDB
+       scsi-cmd-seek r@ seek>operation-code c!
+   r> seek>lba l!  (  )  ( R: cdb -- )
+   scsi-length-seek to scsi-param-size \ update CDB length
+;
+
+\ ****************************************************************************
+\ CDROM media event stuff
+\ ****************************************************************************
+
+STRUCT
+    /w FIELD media-event-data-len
+    /c FIELD media-event-nea-class
+    /c FIELD media-event-supp-class
+    /l FIELD media-event-data
+CONSTANT scsi-length-media-event
+
+: scsi-build-get-media-event                     ( cdb -- )
+   dup c erase                                  ( cdb )
+   4a over c!                                   ( cdb )
+   01 over 1 + c!
+   10 over 4 + c!
+   08 over 8 + c!
+   drop
+;
+
+
+
+\ ***************************************************************************
+\ SCSI-Utility: .sense-code
+\ ***************************************************************************
+\ this utility prints a string associated to the sense code
+\ see specs: SPC-3/r23 clause 4.5.6
+\ ***************************************************************************
+: .sense-text ( scode -- )
+   case
+      0    OF s" OK"               ENDOF
+      1    OF s" RECOVERED ERR"    ENDOF
+      2    OF s" NOT READY"        ENDOF
+      3    OF s" MEDIUM ERROR"     ENDOF
+      4    OF s" HARDWARE ERR"     ENDOF
+      5    OF s" ILLEGAL REQUEST"  ENDOF
+      6    OF s" UNIT ATTENTION"   ENDOF
+      7    OF s" DATA PROTECT"     ENDOF
+      8    OF s" BLANK CHECK"      ENDOF
+      9    OF s" VENDOR SPECIFIC"  ENDOF
+      a    OF s" COPY ABORTED"     ENDOF
+      b    OF s" ABORTED COMMAND"  ENDOF
+      d    OF s" VOLUME OVERFLOW"  ENDOF
+      e    OF s" MISCOMPARE"       ENDOF
+      dup  OF s" UNKNOWN"          ENDOF
+   endcase
+   5b emit type 5d emit
+;
+
+\ ***************************************************************************
+\ SCSI-Utility: .status-code
+\ ***************************************************************************
+\ this utility prints a string associated to the status code
+\ see specs: SAM-3/r14 clause 5.3
+\ ***************************************************************************
+: .status-text  ( stat -- )
+   case
+      00  OF s" GOOD"                  ENDOF
+      02  OF s" CHECK CONDITION"       ENDOF
+      04  OF s" CONDITION MET"         ENDOF
+      08  OF s" BUSY"                  ENDOF
+      18  OF s" RESERVATION CONFLICT"  ENDOF
+      28  OF s" TASK SET FULL"         ENDOF
+      30  OF s" ACA ACTIVE"            ENDOF
+      40  OF s" TASK ABORTED"          ENDOF
+      dup OF s" UNKNOWN"               ENDOF
+   endcase
+   5b emit type 5d emit
+;
+
+\ ***************************************************************************
+\ SCSI-Utility: .capacity-text
+\ ***************************************************************************
+\ utility that shows total capacity on screen by use of the return data
+\ from read-capacity calculation is SI conform (base 10)
+\ ***************************************************************************
+\ sub function to print a 3 digit decimal
+\ number with 2 post decimal positions xxx.yy
+: .dec3-2 ( prenum postnum -- )
+   swap
+   base @ >r                           \ save actual base setting
+   decimal                             \ show decimal values
+   4 .r 2e emit
+   dup 9 <= IF 30 emit THEN .d         \ 3 pre-decimal, right aligned
+   r> base !                           \ restore base
+;
+
+: .capacity-text  ( block-size #blocks -- )
+   scsi-param-debug                    \ debugging flag set ?
+   IF                                  \ show additional info
+      2dup
+      cr
+      ." LBAs: " .d                    \ highest logical block number
+      ." / Block-Size: " .d
+      ." / Total Capacity: "
+   THEN
+   *                                   \ calculate total capacity
+   dup d# 1000000000000 >=             \ check terabyte limit
+   IF
+      d# 1000000000000 /mod
+      swap
+      d# 10000000000 /                 \ limit remainder to two digits
+      .dec3-2 ." TB"                   \ show terabytes as xxx.yy
+   ELSE
+      dup d# 1000000000 >=             \ check gigabyte limit
+      IF
+         d# 1000000000 /mod
+         swap
+         d# 10000000 /
+         .dec3-2 ." GB"                \ show gigabytes as xxx.yy
+      ELSE
+         dup d# 1000000 >=
+         IF
+            d# 1000000 /mod            \ check mega byte limit
+            swap
+            d# 10000 /
+            .dec3-2 ." MB"             \ show megabytes as xxx.yy
+         ELSE
+            dup d# 1000 >=             \ check kilo byte limit
+            IF
+               d# 1000 /mod
+               swap
+               d# 10 /
+               .dec3-2 ." kB"
+            ELSE
+               .d ."  Bytes"
+            THEN
+         THEN
+      THEN
+   THEN
+;
+
+\ ***************************************************************************
+\ SCSI-Utility: .inquiry-text  ( addr -- )
+\ ***************************************************************************
+\ utility that shows:
+\     vendor-ident product-ident and revision
+\ from an inquiry return data block (addr)
+\ ***************************************************************************
+: .inquiry-text  ( addr -- )
+   22 emit     \ enclose text with "
+   dup inquiry-data>vendor-ident      8 type space
+   dup inquiry-data>product-ident    10 type space
+       inquiry-data>product-revision  4 type
+   22 emit
+;
+
+\ ***************************************************************************
+\ SCSI-Utility: scsi-supp-init  ( -- )
+\ ***************************************************************************
+\ utility that helps to ensure that parameters are set to valid values
+: scsi-supp-init  ( -- )
+   false   to scsi-param-debug         \ no debug strings
+   h# 0   to scsi-param-size
+   h# 0   to scsi-param-control        \ common CDB control byte
+   d# 0   to scsi-param-errors         \ local errors (param limits)
+;
+
+\ ***************************************************************************
+\ Constants used by SCSI controller's execute-scsi-command
+\ ***************************************************************************
+true  CONSTANT scsi-dir-read
+false CONSTANT scsi-dir-write
+
+
+\ ***************************************************************************
+\ scsi loader
+\ ***************************************************************************
+0 VALUE scsi-context                   \ addr of word list on top
+
+
+\ ****************************************************************************
+\ open scsi-support by adding a new word list on top of search path
+\   precondition: scsi-support.fs must have been included
+\ ****************************************************************************
+: scsi-init  ( -- )
+   also scsi-words                     \ append scsi word-list
+   context  to scsi-context            \ save for close process
+   scsi-supp-init                      \ preset all scsi-param-xxx values
+   scsi-param-debug
+   IF
+      space ." SCSI-SUPPORT OPENED" cr
+      .wordlists
+   THEN
+;
+
+\ ****************************************************************************
+\ close scsi-session and remove scsi word list (if exists)
+\ ****************************************************************************
+\ if 'previous' is used without a preceding 'also' all forth words are lost !
+\ ****************************************************************************
+: scsi-close  ( -- )
+\ FIXME This only works if scsi-words is the last vocabulary on the stack
+\       Instead we could use get-order to find us on the "wordlist stack",
+\       remove us and write the wordlist stack back with set-order.
+\       BUT: Is this worth the effort?
+
+   scsi-param-debug
+   IF
+      space ." Closing SCSI-SUPPORT .. " cr
+   THEN
+   context scsi-context =              \ scsi word list still active ?
+   IF
+      scsi-param-errors 0<>          \ any errors occurred ?
+      IF
+         cr ." ** WARNING: " scsi-param-errors .d
+         ." SCSI Errors occurred ** " cr
+      THEN
+      previous                         \ remove scsi word list on top
+      0 to scsi-context                \ prevent from being misinterpreted
+   ELSE
+      cr ." ** WARNING: Trying to close non-open SCSI-SUPPORT (1) ** " cr
+   THEN
+   scsi-param-debug
+   IF
+     .wordlists
+   THEN
+;
+
+
+s" scsi-init" $find drop               \ return execution pointer, when included
+
+previous                               \ remove scsi word list from search path
+definitions                            \ place next definitions into previous list
+