diff options
Diffstat (limited to 'qemu/roms/SLOF/board-qemu/slof/vio-vscsi.fs')
-rw-r--r-- | qemu/roms/SLOF/board-qemu/slof/vio-vscsi.fs | 546 |
1 files changed, 546 insertions, 0 deletions
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 index 000000000..f2d4c6fcc --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/vio-vscsi.fs @@ -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 |