blob: 579ce37f9fa1b9d30bd2d7cddcc575a4e28c9eb4 [file] [log] [blame]
\ 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
;