diff options
Diffstat (limited to 'qemu/roms/SLOF/slof/fs/scsi-host-helpers.fs')
-rw-r--r-- | qemu/roms/SLOF/slof/fs/scsi-host-helpers.fs | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/qemu/roms/SLOF/slof/fs/scsi-host-helpers.fs b/qemu/roms/SLOF/slof/fs/scsi-host-helpers.fs new file mode 100644 index 000000000..579ce37f9 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/scsi-host-helpers.fs @@ -0,0 +1,127 @@ +\ This file is meant to be included by SCSI hosts to provide +\ helpers such as retry-scsi-command + +\ Returns 1 for retry, 0 for return with no error and +\ -1 for return with an error +\ +: check-retry-sense? ( sense-buf sense-len -- retry? ) + \ Check if the sense-len is at least 8 bytes + 8 < IF -1 EXIT THEN + + \ Fixed sense record, look for filemark etc... + dup sense-data>response-code c@ 7e and 70 = IF + dup sense-data>sense-key c@ e0 and IF drop -1 EXIT THEN + THEN + + \ Get sense data + scsi-get-sense-data? IF ( ascq asc sense-key ) + \ No sense or recoverable, return success + dup 2 < IF 3drop 0 EXIT THEN + \ not ready and unit attention, retry + dup 2 = swap 6 = or nip nip IF 1 EXIT THEN + THEN + \ Return failure + -1 +; + +\ This is almost as the standard retry-command but returns +\ additionally the length of the returned sense information +\ +\ The hw-err? field is gone, stat is -1 for a HW error, and +\ the sense data is provided iff stat is CHECK_CONDITION (02) +\ +\ Additionally we wait 10ms between retries +\ +0 INSTANCE VALUE rcmd-buf-addr +0 INSTANCE VALUE rcmd-buf-len +0 INSTANCE VALUE rcmd-dir +0 INSTANCE VALUE rcmd-cmd-addr +0 INSTANCE VALUE rcmd-cmd-len + +: retry-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len #retries -- ... ) + ( ... 0 | [ sense-buf sense-len ] stat ) + >r \ stash #retries + to rcmd-cmd-len to rcmd-cmd-addr to rcmd-dir to rcmd-buf-len to rcmd-buf-addr + 0 \ dummy status & sense + r> \ retreive #retries ( stat #retries ) + 0 DO + \ drop previous status & sense + 0<> IF 2drop THEN + + \ Restore arguments + rcmd-buf-addr + rcmd-buf-len + rcmd-dir + rcmd-cmd-addr + rcmd-cmd-len + + \ Send command + execute-scsi-command ( [ sense-buf sense-len ] stat ) + + \ Success ? + dup 0= IF LEAVE THEN + + \ HW error ? + dup -1 = IF LEAVE THEN + + \ Check condition ? + dup 2 = IF ( sense-buf sense-len stat ) + >r \ stash stat ( sense-buf sense len ) + 2dup + check-retry-sense? ( sense-buf sense-len retry? ) + r> swap \ unstash stat ( sense-buf sense-len stat retry? ) + \ Check retry? result + CASE + 0 OF 3drop 0 LEAVE ENDOF \ Swallow error, return 0 + -1 OF LEAVE ENDOF \ No retry + ENDCASE + ELSE \ Anything other than busy -> exit + dup 8 <> IF LEAVE THEN + THEN + a ms + LOOP +; + +\ ----------------------------------------------------------- +\ Some command helpers +\ ----------------------------------------------------------- +\ +\ TODO: Get rid of global "sector" and instead return an +\ allocated block for the caller to free + +CREATE sector d# 512 allot +CREATE cdb 10 allot + +: (inquiry) ( size -- buffer | NULL ) + dup cdb scsi-build-inquiry + \ 16 retries for inquiry to flush out any UAs + sector swap scsi-dir-read cdb scsi-param-size 10 retry-scsi-command + \ Success ? + 0= IF sector ELSE 2drop 0 THEN +; + +\ Read the initial 36bytes and then decide how much more is to be read +: inquiry ( -- buffer | NULL ) + d# 36 (inquiry) 0= IF 0 EXIT THEN + sector inquiry-data>add-length c@ 5 + + (inquiry) +; + +: report-luns ( -- [ sector ] true | false ) + 200 cdb scsi-build-report-luns + \ 16 retries to flush out any UAs + sector 200 scsi-dir-read cdb scsi-param-size 10 retry-scsi-command + \ Success ? + 0= IF sector true ELSE drop false THEN +; + +\ This routine creates a disk alias for the first found disk/cdrom +: make-disk-alias ( $name srplun -- ) + >r 2dup r> -rot ( $name srplun $name) + find-alias 0<> IF 4drop exit THEN + get-node node>path + 20 allot + " /disk@" string-cat ( $name srplun npath npathl ) + rot base @ >r hex (u.) r> base ! string-cat ( $name $diskpath ) + set-alias +; |