| \ 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 |
| ; |