summaryrefslogtreecommitdiff
path: root/roms/SLOF/slof/fs/scsi-host-helpers.fs
diff options
context:
space:
mode:
Diffstat (limited to 'roms/SLOF/slof/fs/scsi-host-helpers.fs')
-rw-r--r--roms/SLOF/slof/fs/scsi-host-helpers.fs127
1 files changed, 127 insertions, 0 deletions
diff --git a/roms/SLOF/slof/fs/scsi-host-helpers.fs b/roms/SLOF/slof/fs/scsi-host-helpers.fs
new file mode 100644
index 000000000..579ce37f9
--- /dev/null
+++ b/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
+;