aboutsummaryrefslogtreecommitdiff
path: root/board-qemu/slof/virtio-scsi.fs
diff options
context:
space:
mode:
authorNikunj A. Dadhania <nikunj@linux.vnet.ibm.com>2013-06-05 16:07:49 +1000
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-06-05 16:12:39 +1000
commit45b6e9201cf28dcc0167727398c7da79faa9fb60 (patch)
treefc135318ae707c873ed245784bdb7801e98a804e /board-qemu/slof/virtio-scsi.fs
parent1da4a14a371c29e3f322e78ca01a351be877fc5f (diff)
downloadSLOF-45b6e9201cf28dcc0167727398c7da79faa9fb60.zip
SLOF-45b6e9201cf28dcc0167727398c7da79faa9fb60.tar.gz
SLOF-45b6e9201cf28dcc0167727398c7da79faa9fb60.tar.bz2
SLOF: virtio-scsi block driver code
Forth implementation for virtio-scsi as a block driver. Uses scsi-support.fs for the scsi command protocol Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'board-qemu/slof/virtio-scsi.fs')
-rw-r--r--board-qemu/slof/virtio-scsi.fs293
1 files changed, 160 insertions, 133 deletions
diff --git a/board-qemu/slof/virtio-scsi.fs b/board-qemu/slof/virtio-scsi.fs
index ae74f4d..bedfe76 100644
--- a/board-qemu/slof/virtio-scsi.fs
+++ b/board-qemu/slof/virtio-scsi.fs
@@ -12,178 +12,200 @@
." Populating " pwd cr
-0 CONSTANT virtio-scsi-debug
-1 CONSTANT virtio-scsi \ scsi-type for device address handling
+FALSE CONSTANT virtio-scsi-debug
-1 encode-int s" #address-cells" property
-1 encode-int s" #size-cells" property
+2 encode-int s" #address-cells" property
+0 encode-int s" #size-cells" property
-: decode-unit 1 hex-decode-unit ;
-: encode-unit 1 hex-encode-unit ;
-
-\ s" block" device-type
+: decode-unit 2 hex64-decode-unit ;
+: encode-unit 2 hex64-encode-unit ;
FALSE VALUE initialized?
/vd-len BUFFER: virtiodev
virtiodev virtio-setup-vd
-STRUCT
- 100 FIELD >cdb-req
-constant /cdb-buf
+STRUCT \ virtio-scsi-config
+ /l FIELD vs-cfg>num-queues
+ /l FIELD vs-cfg>seg-max
+ /l FIELD vs-cfg>max-sectors
+ /l FIELD vs-cfg>cmd-per-lun
+ /l FIELD vs-cfg>event-info-size
+ /l FIELD vs-cfg>sense_size
+ /l FIELD vs-cfg>cdb-size
+ /w FIELD vs-cfg>max-channel
+ /w FIELD vs-cfg>max-target
+ /l FIELD vs-cfg>max-lun
+CONSTANT vs-cfg-length
+
+STRUCT \ virtio-scsi-req
+ 8 FIELD vs-req>lun
+ 8 FIELD vs-req>tag
+ /c FIELD vs-req>task-attr
+ /c FIELD vs-req>prio
+ /c FIELD vs-req>crn
+ 20 FIELD vs-req>cdb
+CONSTANT vs-req-length
+
+STRUCT \ virtio-scsi-resp
+ /l FIELD vs-rsp>sense-len
+ /l FIELD vs-rsp>residual
+ /w FIELD vs-rsp>status-qualifier
+ /c FIELD vs-rsp>status
+ /c FIELD vs-rsp>response
+ 60 FIELD vs-rsp>sense
+CONSTANT vs-rsp-length
+
+CREATE vs-req vs-req-length allot
+CREATE vs-rsp vs-rsp-length allot
scsi-open
-CREATE sector d# 512 allot
-CREATE sectorlun d# 512 allot
-0 INSTANCE VALUE current-target
-CREATE cdb 100 allot
-
-: inquiry ( -- )
- ff cdb >cdb-req scsi-build-inquiry
- virtiodev current-target cdb sector ff virtio-scsi-send
- 0<> IF ." Inquiry failed " cr FALSE EXIT THEN
- TRUE
-;
+\ -----------------------------------------------------------
+\ Perform SCSI commands
+\ -----------------------------------------------------------
-: request-sense ( -- )
- ff cdb >cdb-req scsi-build-request-sense
- virtiodev current-target cdb sector ff virtio-scsi-send
- 0<> IF ." Error " cr FALSE EXIT THEN
- sector scsi-get-sense-data
-;
+0 INSTANCE VALUE current-target
-: report-luns ( -- )
- 200 cdb >cdb-req scsi-build-report-luns
- virtiodev current-target cdb sectorlun 200 virtio-scsi-send
- 0<> IF ." Report-luns failed " cr request-sense FALSE EXIT THEN
- virtio-scsi-debug IF
- sectorlun 20 dump cr
+\ SCSI command. We do *NOT* implement the "standard" execute-command
+\ because that doesn't have a way to return the sense buffer back, and
+\ we do have auto-sense with some hosts. Instead we implement a made-up
+\ do-scsi-command.
+\
+\ Note: stat is -1 for "hw error" (ie, error queuing the command or
+\ getting the response).
+\
+\ A sense buffer is returned whenever the status is non-0 however
+\ if sense-len is 0 then no sense data is actually present
+\
+
+: execute-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len -- ... )
+ ( ... [ sense-buf sense-len ] stat )
+ \ Cleanup virtio request and response
+ vs-req vs-req-length erase
+ vs-rsp vs-rsp-length erase
+
+ \ Populate the request
+ current-target vs-req vs-req>lun x!
+ vs-req vs-req>cdb swap move
+
+ \ Send it
+ vs-req vs-rsp virtiodev
+ virtio-scsi-send
+
+ 0 <> IF
+ ." VIRTIO-SCSI: Queuing failure !" cr
+ 0 0 -1 EXIT
THEN
- TRUE
-;
-: test-unit-ready ( -- true | [ ascq asc sense-key false ] )
- cdb >cdb-req scsi-build-test-unit-ready
- virtiodev current-target cdb sector ff virtio-scsi-send
- 0<> IF
- request-sense FALSE
- EXIT THEN
- TRUE
+ \ Check virtio response
+ vs-rsp vs-rsp>response c@ CASE
+ 0 OF ENDOF \ Good
+ 5 OF drop 0 0 8 EXIT ENDOF \ Busy
+ dup OF 0 0 -1 EXIT ENDOF \ Anything else -> HW error
+ ENDCASE
+
+ \ Other error status
+ vs-rsp vs-rsp>status c@ dup 0<> IF
+ vs-rsp vs-rsp>sense-len l@ dup 0= IF
+ \ This relies on auto-sense from qemu... if that isn't always the
+ \ case we should request sense here
+ ." VIRTIO-SCSI: No sense data" cr
+ 0 EXIT
+ THEN
+ vs-rsp vs-rsp>sense swap
+ virtio-scsi-debug IF
+ over scsi-get-sense-data
+ ." VIRTIO-SCSI: Sense key [ " dup . ." ] " .sense-text
+ ." ASC,ASCQ: " . . cr
+ THEN
+ rot
+ THEN
;
-: read-capacity ( -- TRUE | FALSE )
- cdb >cdb-req scsi-build-read-cap-10
- virtiodev current-target cdb sector ff virtio-scsi-send
- 0<> IF ." Error reading capacity virtio-scsi block " cr FALSE EXIT THEN
- TRUE
-;
+\ --------------------------------
+\ Include the generic host helpers
+\ --------------------------------
-: get-media-event ( -- true | false )
- cdb >cdb-req scsi-build-get-media-event
- virtiodev current-target cdb sector ff virtio-scsi-send
- 0<> IF ." Error get-media-event " cr FALSE EXIT THEN
- TRUE
-;
+" scsi-host-helpers.fs" included
-: start-stop-unit ( state# -- true | false )
- cdb >cdb-req scsi-build-start-stop-unit
- virtiodev current-target cdb sector ff virtio-scsi-send
- 0<> IF ." Error start-stop-unit " cr FALSE EXIT THEN
- TRUE
+\ FIXME: Check max transfer coming from virtio config
+: max-transfer ( -- n )
+ 10000 \ Larger value seem to have problems with some CDROMs
;
-: read-blocks ( address block# #blocks block-size -- [#read-blocks true] | false )
- over * ( address block# #block len )
- -rot tuck ( address len #block block# #block )
- cdb >cdb-req scsi-build-read-10 ( address len #blocks )
- -rot >r >r ( #block ) ( R: len address )
- virtiodev current-target cdb r> r> virtio-scsi-send
- 0<> IF drop false ." Error reading virtio-scsi block " cr ABORT THEN
- true
-;
+\ -----------------------------------------------------------
+\ SCSI scan at boot and child device support
+\ -----------------------------------------------------------
-: set-target ( srplun -- )
- virtio-scsi-debug IF
- dup ." Setting target " . cr
- THEN
+\ We use SRP luns of the form 01000000 | (target << 8) | lun
+\ in the top 32 bits of the 64-bit LUN
+: (set-target)
to current-target
;
-
-: wrapped-inquiry ( -- true | false )
- inquiry not IF false EXIT THEN
- \ Skip devices with PQ != 0
- sector inquiry-data>peripheral c@ e0 and 0 =
+\ We obtain here a unit address on the stack, since our #address-cells
+\ is 2, the 64-bit srplun is split in two cells that we need to join
+\
+\ Note: This diverges a bit from the original OF scsi spec as the two
+\ cells are the 2 words of a 64-bit SRP LUN
+: set-address ( srplun.lo srplun.hi -- )
+ lxjoin (set-target)
;
-: initial-test-unit-ready ( -- true | [ ascq asc sense-key false ] )
- 0 0 0 false
- 3 0 DO
- 2drop 2drop
- test-unit-ready dup IF UNLOOP EXIT THEN
- LOOP
-;
+\ FIXME: Make these two common somewhat, possibly passing the
+\ unit "name" as an argument
-: compare-sense ( ascq asc key ascq2 asc2 key2 -- true | false )
- 3 pick = ( ascq asc key ascq2 asc2 keycmp )
- swap 4 pick = ( ascq asc key ascq2 keycmp asccmp )
- rot 5 pick = ( ascq asc key keycmp asccmp ascqcmp )
- and and nip nip nip
+: make-disk-alias ( srplun -- )
+ " disk" find-alias 0<> IF drop THEN
+ get-node node>path
+ 20 allot
+ " /disk@" string-cat \ srplun npath npathl
+ rot base @ >r hex (u.) r> base ! string-cat
+ " disk" 2swap set-alias
;
-#include "generic-cdrom.fs"
-
-: dev-prep-disk ( -- )
- initial-test-unit-ready 0= IF
- ." Disk not ready!" cr
- 3drop
- THEN
-;
-
-: dev-max-transfer ( -- n )
- 10000 \ Larger value seem to have problems with some CDROMs
-;
-
-: dev-get-capacity ( -- blocksize #blocks )
- \ Make sure that there are zeros in the buffer in case something
- \ goes wrong:
- sector 10 erase
- \ Now issue the read-capacity command
- read-capacity not IF
- 0 0 EXIT
- THEN
- sector scsi-get-capacity-10
+: make-cdrom-alias ( srplun -- )
+ " cdrom" find-alias 0<> IF drop THEN
+ get-node node>path
+ 20 allot
+ " /disk@" string-cat \ srplun npath npathl
+ rot base @ >r hex (u.) r> base ! string-cat
+ " cdrom" 2swap set-alias
;
-: dev-read-blocks ( addr block# #blocks block-size -- [#blocks-read true] | false)
- read-blocks
-;
-
-: virtio-scsi-create-disk ( srplun -- )
- " disk" 0 virtio-scsi " generic-scsi-device.fs" included
+\ FIXME Remove use of "sector"
+: wrapped-inquiry ( -- true | false )
+ inquiry dup 0= IF drop false EXIT THEN
+ \ Skip devices with PQ != 0
+ inquiry-data>peripheral c@ e0 and 0 =
;
-: virtio-scsi-create-cdrom ( srplun -- )
- " cdrom" 1 virtio-scsi " generic-scsi-device.fs" included
-;
+\ Get rid of that when report-lun returns an allocated buffer
+CREATE sectorlun d# 512 allot
: virtio-scsi-find-disks ( -- )
." VIRTIO-SCSI: Looking for devices" cr
- 0 set-target
+ 0100000000000000 (set-target)
+ \ XXX FIXME: Iterate targets, not only luns, base code on vscsi
+ \ or better, make it generic (using an encode-target method that
+ \ takes ID,lun as argument maybe
report-luns IF
- sectorlun 8 + ( lunarray )
+ sectorlun 200 move \ copy report-luns result to sectorlun
+ \ will go away when report-lun returns
+ \ an allocated block
+ sectorlun 8 + ( lunarray )
dup sectorlun l@ 3 >> 0 DO ( lunarray lunarraycur )
- \ fixme: Read word, as virtio-scsi writes u16 luns
- dup w@ set-target wrapped-inquiry IF
+ dup w@ 32 << 0100000000000000 or
+ (set-target) wrapped-inquiry IF
." " current-target (u.) type ." "
\ XXX FIXME: Check top bits to ignore unsupported units
\ and maybe provide better printout & more cases
\ XXX FIXME: Actually check for LUNs
sector inquiry-data>peripheral c@ CASE
- 0 OF ." DISK : " current-target virtio-scsi-create-disk ENDOF
- 5 OF ." CD-ROM : " current-target virtio-scsi-create-cdrom ENDOF
- 7 OF ." OPTICAL : " current-target virtio-scsi-create-cdrom ENDOF
- e OF ." RED-BLOCK: " current-target virtio-scsi-create-disk ENDOF
+ 0 OF ." DISK : " current-target make-disk-alias ENDOF
+ 5 OF ." CD-ROM : " current-target make-cdrom-alias ENDOF
+ 7 OF ." OPTICAL : " current-target make-cdrom-alias ENDOF
+ e OF ." RED-BLOCK: " current-target make-disk-alias ENDOF
dup dup OF ." ? (" . 8 emit 29 emit 5 spaces ENDOF
ENDCASE
sector .inquiry-text cr
@@ -216,10 +238,10 @@ scsi-close \ no further scsi words required
virtiodev 2 queue-cmd-addr virtio-set-qaddr
;
-\ Set disk alias if none is set yet
+\ Set scsi alias if none is set yet
: setup-alias
- s" disk" find-alias 0= IF
- s" disk" get-node node>path set-alias
+ s" scsi" find-alias 0= IF
+ s" scsi" get-node node>path set-alias
ELSE
drop
THEN
@@ -237,7 +259,7 @@ scsi-close \ no further scsi words required
dup to my-self
\ Scan the VSCSI bus:
virtiodev virtio-scsi-init
- dup 0= IF
+ 0= IF
setup-virt-queues
virtio-scsi-find-disks
setup-alias
@@ -249,4 +271,9 @@ scsi-close \ no further scsi words required
r> to my-self
;
+: virtio-scsi-add-disk
+ " scsi-disk.fs" included
+;
+
+virtio-scsi-add-disk
virtio-scsi-init-and-scan