diff options
author | Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> | 2013-06-05 16:07:49 +1000 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-06-05 16:12:39 +1000 |
commit | 45b6e9201cf28dcc0167727398c7da79faa9fb60 (patch) | |
tree | fc135318ae707c873ed245784bdb7801e98a804e /board-qemu/slof | |
parent | 1da4a14a371c29e3f322e78ca01a351be877fc5f (diff) | |
download | SLOF-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')
-rw-r--r-- | board-qemu/slof/pci-device_1af4_1004.fs | 2 | ||||
-rw-r--r-- | board-qemu/slof/virtio-scsi.fs | 293 |
2 files changed, 162 insertions, 133 deletions
diff --git a/board-qemu/slof/pci-device_1af4_1004.fs b/board-qemu/slof/pci-device_1af4_1004.fs index 66f7bb3..9c1089a 100644 --- a/board-qemu/slof/pci-device_1af4_1004.fs +++ b/board-qemu/slof/pci-device_1af4_1004.fs @@ -19,4 +19,6 @@ pci-master-enable pci-mem-enable pci-io-enable +s" virtio-scsi.fs" included + pci-device-disable 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 |