1 \ This file is meant to be included by SCSI hosts to provide
2 \ helpers such as retry-scsi-command
4 \ Returns 1 for retry, 0 for return with no error and
5 \ -1 for return with an error
7 : check-retry-sense? ( sense-buf sense-len -- retry? )
8 \ Check if the sense-len is at least 8 bytes
11 \ Fixed sense record, look for filemark etc...
12 dup sense-data>response-code c@ 7e and 70 = IF
13 dup sense-data>sense-key c@ e0 and IF drop -1 EXIT THEN
17 scsi-get-sense-data? IF ( ascq asc sense-key )
18 \ No sense or recoverable, return success
19 dup 2 < IF 3drop 0 EXIT THEN
20 \ not ready and unit attention, retry
21 dup 2 = swap 6 = or nip nip IF 1 EXIT THEN
27 \ This is almost as the standard retry-command but returns
28 \ additionally the length of the returned sense information
30 \ The hw-err? field is gone, stat is -1 for a HW error, and
31 \ the sense data is provided iff stat is CHECK_CONDITION (02)
33 \ Additionally we wait 10ms between retries
35 0 INSTANCE VALUE rcmd-buf-addr
36 0 INSTANCE VALUE rcmd-buf-len
37 0 INSTANCE VALUE rcmd-dir
38 0 INSTANCE VALUE rcmd-cmd-addr
39 0 INSTANCE VALUE rcmd-cmd-len
41 : retry-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len #retries -- ... )
42 ( ... 0 | [ sense-buf sense-len ] stat )
44 to rcmd-cmd-len to rcmd-cmd-addr to rcmd-dir to rcmd-buf-len to rcmd-buf-addr
45 0 \ dummy status & sense
46 r> \ retreive #retries ( stat #retries )
48 \ drop previous status & sense
59 execute-scsi-command ( [ sense-buf sense-len ] stat )
65 dup -1 = IF LEAVE THEN
68 dup 2 = IF ( sense-buf sense-len stat )
69 >r \ stash stat ( sense-buf sense len )
71 check-retry-sense? ( sense-buf sense-len retry? )
72 r> swap \ unstash stat ( sense-buf sense-len stat retry? )
75 0 OF 3drop 0 LEAVE ENDOF \ Swallow error, return 0
76 -1 OF LEAVE ENDOF \ No retry
78 ELSE \ Anything other than busy -> exit
79 dup 8 <> IF LEAVE THEN
85 \ -----------------------------------------------------------
86 \ Some command helpers
87 \ -----------------------------------------------------------
89 \ TODO: Get rid of global "sector" and instead return an
90 \ allocated block for the caller to free
92 CREATE sector d# 512 allot
95 : (inquiry) ( size -- buffer | NULL )
96 dup cdb scsi-build-inquiry
97 \ 16 retries for inquiry to flush out any UAs
98 sector swap scsi-dir-read cdb scsi-param-size 10 retry-scsi-command
100 0= IF sector ELSE 2drop 0 THEN
103 \ Read the initial 36bytes and then decide how much more is to be read
104 : inquiry ( -- buffer | NULL )
105 d# 36 (inquiry) 0= IF 0 EXIT THEN
106 sector inquiry-data>add-length c@ 5 +
110 : report-luns ( -- [ sector ] true | false )
111 200 cdb scsi-build-report-luns
112 \ 16 retries to flush out any UAs
113 sector 200 scsi-dir-read cdb scsi-param-size 10 retry-scsi-command
115 0= IF sector true ELSE drop false THEN
118 \ This routine creates a disk alias for the first found disk/cdrom
119 : make-disk-alias ( $name srplun -- )
120 >r 2dup r> -rot ( $name srplun $name)
121 find-alias 0<> IF 4drop exit THEN
124 " /disk@" string-cat ( $name srplun npath npathl )
125 rot base @ >r hex (u.) r> base ! string-cat ( $name $diskpath )