Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / board-qemu / slof / vio-vscsi.fs
diff --git a/qemu/roms/SLOF/board-qemu/slof/vio-vscsi.fs b/qemu/roms/SLOF/board-qemu/slof/vio-vscsi.fs
new file mode 100644 (file)
index 0000000..f2d4c6f
--- /dev/null
@@ -0,0 +1,546 @@
+\ *****************************************************************************
+\ * Copyright (c) 2011 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+." Populating " pwd
+
+false VALUE vscsi-debug?
+0 VALUE vscsi-unit
+
+\ -----------------------------------------------------------
+\ Direct DMA conversion hack
+\ -----------------------------------------------------------
+: l2dma ( laddr - dma_addr)      
+;
+
+\ -----------------------------------------------------------
+\ CRQ related functions
+\ -----------------------------------------------------------
+
+0    VALUE     crq-real-base
+0    VALUE     crq-base
+0    VALUE     crq-dma
+0    VALUE     crq-offset
+1000 CONSTANT  CRQ-SIZE
+
+CREATE crq 10 allot
+
+: crq-alloc ( -- )
+    \ Allocate enough to align to a page
+    CRQ-SIZE fff + alloc-mem to crq-real-base
+    \ align the result
+    crq-real-base fff + fffff000 AND to crq-base 0 to crq-offset
+    crq-base l2dma to crq-dma
+;
+
+: crq-free ( -- )
+    vscsi-unit hv-free-crq
+    crq-real-base CRQ-SIZE fff + free-mem 0 to crq-base 0 to crq-real-base
+;
+
+: crq-init ( -- res )
+    \ Allocate CRQ. XXX deal with fail
+    crq-alloc
+
+    vscsi-debug? IF
+        ." VSCSI: allocated crq at " crq-base . cr
+    THEN
+
+    \ Clear buffer
+    crq-base CRQ-SIZE erase
+
+    \ Register with HV
+    vscsi-unit crq-dma CRQ-SIZE hv-reg-crq
+
+    \ Fail case
+    dup 0 <> IF
+        ." VSCSI: Error " . ."  registering CRQ !" cr
+       crq-free
+    THEN
+;
+
+: crq-cleanup ( -- )
+    crq-base 0 = IF EXIT THEN
+
+    vscsi-debug? IF
+        ." VSCSI: freeing crq at " crq-base . cr
+    THEN
+    crq-free
+;
+
+: crq-send ( msgaddr -- true | false )
+    vscsi-unit swap hv-send-crq 0 =
+;
+
+: crq-poll ( -- true | false)
+    crq-offset crq-base + dup
+    vscsi-debug? IF
+        ." VSCSI: crq poll " dup .
+    THEN
+    c@
+    vscsi-debug? IF
+        ."  value=" dup . cr
+    THEN
+    80 and 0 <> IF
+        dup crq 10 move
+       0 swap c!
+       crq-offset 10 + dup CRQ-SIZE >= IF drop 0 THEN to crq-offset
+       true
+    ELSE drop false THEN
+;
+
+: crq-wait ( -- true | false)
+    \ FIXME: Add timeout
+    0 BEGIN drop crq-poll dup not WHILE d# 1 ms REPEAT
+    dup not IF
+        ." VSCSI: Timeout waiting response !" cr EXIT
+    ELSE
+        vscsi-debug? IF
+            ." VSCSI: got crq: " crq dup l@ . ."  " 4 + dup l@ . ."  "
+           4 + dup l@ . ."  " 4 + l@ . cr
+        THEN
+    THEN
+;
+
+\ -----------------------------------------------------------
+\ CRQ encapsulated SRP definitions
+\ -----------------------------------------------------------
+
+01 CONSTANT VIOSRP_SRP_FORMAT
+02 CONSTANT VIOSRP_MAD_FORMAT
+03 CONSTANT VIOSRP_OS400_FORMAT
+04 CONSTANT VIOSRP_AIX_FORMAT
+06 CONSTANT VIOSRP_LINUX_FORMAT
+07 CONSTANT VIOSRP_INLINE_FORMAT
+
+struct
+   1 field >crq-valid
+   1 field >crq-format
+   1 field >crq-reserved
+   1 field >crq-status
+   2 field >crq-timeout
+   2 field >crq-iu-len
+   8 field >crq-iu-data-ptr
+constant /crq
+
+: srp-send-crq ( addr len -- )
+    80                crq >crq-valid c!
+    VIOSRP_SRP_FORMAT crq >crq-format c!
+    0                 crq >crq-reserved c!
+    0                 crq >crq-status c!
+    0                 crq >crq-timeout w!
+    ( len )           crq >crq-iu-len w!
+    ( addr ) l2dma    crq >crq-iu-data-ptr x!
+    crq crq-send
+    not IF
+        ." VSCSI: Error sending CRQ !" cr
+    THEN
+;
+
+: srp-wait-crq ( -- [tag true] | false )
+    crq-wait not IF false EXIT THEN
+
+    crq >crq-format c@ VIOSRP_SRP_FORMAT <> IF
+       ." VSCSI: Unsupported SRP response: "
+       crq >crq-format c@ . cr
+       false EXIT
+    THEN
+
+    crq >crq-iu-data-ptr x@ true
+;
+
+\ Add scsi functions to dictionary
+scsi-open
+
+
+\ -----------------------------------------------------------
+\ SRP definitions
+\ -----------------------------------------------------------
+
+0 VALUE >srp_opcode
+
+00 CONSTANT SRP_LOGIN_REQ
+01 CONSTANT SRP_TSK_MGMT
+02 CONSTANT SRP_CMD
+03 CONSTANT SRP_I_LOGOUT
+c0 CONSTANT SRP_LOGIN_RSP
+c1 CONSTANT SRP_RSP
+c2 CONSTANT SRP_LOGIN_REJ
+80 CONSTANT SRP_T_LOGOUT
+81 CONSTANT SRP_CRED_REQ
+82 CONSTANT SRP_AER_REQ
+41 CONSTANT SRP_CRED_RSP
+42 CONSTANT SRP_AER_RSP
+
+02 CONSTANT SRP_BUF_FORMAT_DIRECT
+04 CONSTANT SRP_BUF_FORMAT_INDIRECT
+
+struct
+   1 field >srp-login-opcode
+   3 +
+   8 field >srp-login-tag
+   4 field >srp-login-req-it-iu-len
+   4 +
+   2 field >srp-login-req-buf-fmt
+   1 field >srp-login-req-flags
+   5 +
+  10 field >srp-login-init-port-ids
+  10 field >srp-login-trgt-port-ids
+constant /srp-login
+
+struct
+   1 field >srp-lresp-opcode
+   3 +
+   4 field >srp-lresp-req-lim-delta
+   8 field >srp-lresp-tag
+   4 field >srp-lresp-max-it-iu-len
+   4 field >srp-lresp-max-ti-iu-len
+   2 field >srp-lresp-buf-fmt
+   1 field >srp-lresp-flags
+constant /srp-login-resp
+
+struct
+   1 field >srp-lrej-opcode
+   3 +
+   4 field >srp-lrej-reason
+   8 field >srp-lrej-tag
+   8 +
+   2 field >srp-lrej-buf-fmt
+constant /srp-login-rej
+
+00 CONSTANT SRP_NO_DATA_DESC
+01 CONSTANT SRP_DATA_DESC_DIRECT
+02 CONSTANT SRP_DATA_DESC_INDIRECT
+
+struct
+    1 field >srp-cmd-opcode
+    1 field >srp-cmd-sol-not
+    3 +
+    1 field >srp-cmd-buf-fmt
+    1 field >srp-cmd-dout-desc-cnt
+    1 field >srp-cmd-din-desc-cnt
+    8 field >srp-cmd-tag
+    4 +
+    8 field >srp-cmd-lun
+    1 +
+    1 field >srp-cmd-task-attr
+    1 +
+    1 field >srp-cmd-add-cdb-len
+   10 field >srp-cmd-cdb
+    0 field >srp-cmd-cdb-add
+constant /srp-cmd
+
+struct
+    1 field >srp-rsp-opcode
+    1 field >srp-rsp-sol-not
+    2 +
+    4 field >srp-rsp-req-lim-delta
+    8 field >srp-rsp-tag
+    2 +
+    1 field >srp-rsp-flags
+    1 field >srp-rsp-status
+    4 field >srp-rsp-dout-res-cnt
+    4 field >srp-rsp-din-res-cnt
+    4 field >srp-rsp-sense-len
+    4 field >srp-rsp-resp-len
+    0 field >srp-rsp-data
+constant /srp-rsp
+
+\ Constants for srp-rsp-flags
+01 CONSTANT SRP_RSP_FLAG_RSPVALID
+02 CONSTANT SRP_RSP_FLAG_SNSVALID
+04 CONSTANT SRP_RSP_FLAG_DOOVER
+05 CONSTANT SRP_RSP_FLAG_DOUNDER
+06 CONSTANT SRP_RSP_FLAG_DIOVER
+07 CONSTANT SRP_RSP_FLAG_DIUNDER
+
+\ Storage for up to 256 bytes SRP request */
+CREATE srp 100 allot
+0 VALUE srp-len
+
+: srp-prep-cmd-nodata ( srplun -- )
+    srp /srp-cmd erase
+    SRP_CMD srp >srp-cmd-opcode c!
+    1 srp >srp-cmd-tag x!
+    srp >srp-cmd-lun x!         \ 8 bytes lun
+    /srp-cmd to srp-len   
+;
+
+: srp-prep-cmd-io ( addr len srplun -- )
+    srp-prep-cmd-nodata                ( addr len )
+    swap l2dma                 ( len dmaaddr )
+    srp srp-len +              ( len dmaaddr descaddr )
+    dup >r x! r> 8 +           ( len descaddr+8 )
+    dup 0 swap l! 4 +          ( len descaddr+c )
+    l!    
+    srp-len 10 + to srp-len
+;
+
+: srp-prep-cmd-read ( addr len srplun -- )
+    srp-prep-cmd-io
+    01 srp >srp-cmd-buf-fmt c! \ in direct buffer
+    1 srp >srp-cmd-din-desc-cnt c!
+;
+
+: srp-prep-cmd-write ( addr len srplun -- )
+    srp-prep-cmd-io
+    10 srp >srp-cmd-buf-fmt c! \ out direct buffer
+    1 srp >srp-cmd-dout-desc-cnt c!
+;
+
+: srp-send-cmd ( -- )
+    vscsi-debug? IF
+        ." VSCSI: Sending SCSI cmd " srp >srp-cmd-cdb c@ . cr
+    THEN
+    srp srp-len srp-send-crq
+;
+
+: srp-rsp-find-sense ( -- addr len true | false )
+    srp >srp-rsp-flags c@ SRP_RSP_FLAG_SNSVALID and 0= IF
+        false EXIT
+    THEN
+    \ XXX FIXME: We assume the sense data is right at response
+    \            data. A different server might actually have both
+    \            some response data we need to skip *and* some sense
+    \            data.
+    srp >srp-rsp-data srp >srp-rsp-sense-len l@ true
+;
+
+\ Wait for a response to the last sent SRP command
+\ returns a SCSI status code or -1 (HW error).
+\
+: srp-wait-rsp ( -- stat )
+    srp-wait-crq not IF false EXIT THEN
+    dup 1 <> IF
+        ." VSCSI: Invalid CRQ response tag, want 1 got " . cr
+       -1 EXIT
+    THEN drop
+    
+    srp >srp-rsp-tag x@ dup 1 <> IF
+        ." VSCSI: Invalid SRP response tag, want 1 got " . cr
+       -1 EXIT
+    THEN drop
+    
+    srp >srp-rsp-status c@
+    vscsi-debug? IF
+        ." VSCSI: Got response status: "
+       dup .status-text cr
+    THEN
+;
+
+\ -----------------------------------------------------------
+\ Perform SCSI commands
+\ -----------------------------------------------------------
+
+8000000000000000 INSTANCE VALUE current-target
+
+\ 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 )
+    \ Stash command addr & len
+    >r >r                              ( buf-addr buf-len dir )
+    \ Command has no data ?
+    over 0= IF
+        3drop current-target srp-prep-cmd-nodata
+    ELSE
+        \ Command is a read ?
+        current-target swap IF srp-prep-cmd-read ELSE srp-prep-cmd-write THEN
+    THEN
+    \ Recover command and copy it to our srp buffer
+    r> r>
+    srp >srp-cmd-cdb swap move
+    srp-send-cmd
+    srp-wait-rsp
+
+    \ Check for HW error
+    dup -1 = IF
+        0 0 rot EXIT
+    THEN
+
+    \ Other error status
+    dup 0<> IF
+       srp-rsp-find-sense IF
+           vscsi-debug? IF
+               over scsi-get-sense-data
+               ." VSCSI: Sense key [ " dup . ." ] " .sense-text
+              ."  ASC,ASCQ: " . . cr
+           THEN
+       ELSE 0 0
+           \ This relies on auto-sense from qemu... if that isn't always the
+           \ case we should request sense here
+           ." VSCSI: No sense data" cr
+       THEN
+       rot
+    THEN
+;
+
+\ --------------------------------
+\ Include the generic host helpers
+\ --------------------------------
+
+" scsi-host-helpers.fs" included
+
+TRUE VALUE first-time-init?
+0 VALUE open-count
+
+\ Cleanup behind us
+: vscsi-cleanup
+    vscsi-debug? IF ." VSCSI: Cleaning up" cr THEN
+    crq-cleanup
+
+    \ Disable TCE bypass:
+    vscsi-unit 0 rtas-set-tce-bypass
+;
+
+\ Initialize our vscsi instance
+: vscsi-init ( -- true | false )
+    vscsi-debug? IF ." VSCSI: Initializing" cr THEN
+
+    my-unit to vscsi-unit
+
+    \ Enable TCE bypass special qemu feature
+    vscsi-unit 1 rtas-set-tce-bypass
+
+    \ Initialize CRQ
+    crq-init 0 <> IF false EXIT THEN
+
+    \ Send init command
+    " "(C0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00)" drop
+    crq-send not IF
+        ." VSCSI: Error sending init command"
+        crq-cleanup false EXIT
+    THEN
+    \ Wait reply
+    crq-wait not IF
+        crq-cleanup false EXIT
+    THEN
+
+    \ Check init reply
+    crq c@ c0 <> crq 1 + c@ 02 <> or IF
+        ." VSCSI: Initial handshake failed"
+       crq-cleanup false EXIT
+    THEN
+
+    \ We should now login etc.. but we really don't need to
+    \ with our qemu model
+
+    \ Ensure we cleanup after booting
+    first-time-init? IF
+        ['] vscsi-cleanup add-quiesce-xt
+       false to first-time-init?
+    THEN
+
+    true
+;
+
+: open
+    vscsi-debug? IF ." VSCSI: Opening (count is " open-count . ." )" cr THEN
+
+    open-count 0= IF
+        vscsi-init IF
+           1 to open-count true
+       ELSE ." VSCSI initialization failed !" cr false THEN
+    ELSE
+        open-count 1 + to open-count
+        true
+    THEN
+;
+
+: close
+    vscsi-debug? IF ." VSCSI: Closing (count is " open-count . ." )" cr THEN
+
+    open-count 0> IF
+        open-count 1 - dup to open-count
+       0= IF
+           vscsi-cleanup
+       THEN
+    THEN
+;
+
+\ -----------------------------------------------------------
+\ SCSI scan at boot and child device support
+\ -----------------------------------------------------------
+
+\ We use SRP luns of the form 8000 | (bus << 8) | (id << 5) | lun
+\ in the top 16 bits of the 64-bit LUN
+: (set-target)
+    to current-target
+;
+
+: dev-generate-srplun ( target lun -- )
+    swap 8 << 8000 or or 30 <<
+;
+
+\ 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)
+;
+
+\ We set max-transfer to a fixed value for now to avoid problems
+\ with some CD-ROM drives.
+\ FIXME: Check max transfer coming from VSCSI
+: max-transfer ( -- n )
+    10000 \ Larger value seem to have problems with some CDROMs
+;
+
+8 CONSTANT #dev
+: dev-max-target ( -- #max-target )
+    #dev
+;
+
+" scsi-probe-helpers.fs" included
+
+\ Remove scsi functions from word list
+scsi-close
+
+: setup-alias
+    " scsi" find-alias 0= IF
+        " scsi" get-node node>path set-alias
+    ELSE
+        drop
+    THEN 
+;
+
+: vscsi-init-and-scan  ( -- )
+    \ Create instance for scanning:
+    0 0 get-node open-node ?dup 0= IF EXIT THEN
+    my-self >r
+    dup to my-self
+    \ Scan the VSCSI bus:
+    scsi-find-disks
+    setup-alias
+    \ Close the temporary instance:
+    close-node
+    r> to my-self
+;
+
+: vscsi-add-disk
+    " scsi-disk.fs" included
+;
+
+vscsi-add-disk
+vscsi-init-and-scan