127 lines
3.7 KiB
Forth
127 lines
3.7 KiB
Forth
\ 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
|
|
;
|