diff options
-rw-r--r-- | board-qemu/slof/Makefile | 3 | ||||
-rw-r--r-- | board-qemu/slof/pci-device_1af4_1004.fs | 1 | ||||
-rw-r--r-- | board-qemu/slof/virtio-scsi.fs | 252 | ||||
-rw-r--r-- | lib/libvirtio/Makefile | 2 | ||||
-rw-r--r-- | lib/libvirtio/virtio-scsi.c | 143 | ||||
-rw-r--r-- | lib/libvirtio/virtio-scsi.h | 69 | ||||
-rw-r--r-- | lib/libvirtio/virtio.code | 27 | ||||
-rw-r--r-- | lib/libvirtio/virtio.in | 4 |
8 files changed, 499 insertions, 2 deletions
diff --git a/board-qemu/slof/Makefile b/board-qemu/slof/Makefile index efa2567..e41b03d 100644 --- a/board-qemu/slof/Makefile +++ b/board-qemu/slof/Makefile @@ -67,7 +67,8 @@ VIO_FFS_FILES = \ $(SLOFBRDDIR)/rtas-nvram.fs \ $(SLOFBRDDIR)/virtio-net.fs \ $(SLOFBRDDIR)/virtio-block.fs \ - $(SLOFBRDDIR)/virtio-fs.fs + $(SLOFBRDDIR)/virtio-fs.fs \ + $(SLOFBRDDIR)/virtio-scsi.fs # Files that should go into the ROM fs (and so have to be listed in OF.ffs): OF_FFS_FILES = \ diff --git a/board-qemu/slof/pci-device_1af4_1004.fs b/board-qemu/slof/pci-device_1af4_1004.fs index 9637a7d..66f7bb3 100644 --- a/board-qemu/slof/pci-device_1af4_1004.fs +++ b/board-qemu/slof/pci-device_1af4_1004.fs @@ -18,4 +18,5 @@ my-space pci-device-generic-setup pci-master-enable pci-mem-enable pci-io-enable + pci-device-disable diff --git a/board-qemu/slof/virtio-scsi.fs b/board-qemu/slof/virtio-scsi.fs new file mode 100644 index 0000000..ae74f4d --- /dev/null +++ b/board-qemu/slof/virtio-scsi.fs @@ -0,0 +1,252 @@ +\ ***************************************************************************** +\ * Copyright (c) 2012 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 cr + +0 CONSTANT virtio-scsi-debug +1 CONSTANT virtio-scsi \ scsi-type for device address handling + +1 encode-int s" #address-cells" property +1 encode-int s" #size-cells" property + +: decode-unit 1 hex-decode-unit ; +: encode-unit 1 hex-encode-unit ; + +\ s" block" device-type + +FALSE VALUE initialized? + +/vd-len BUFFER: virtiodev +virtiodev virtio-setup-vd + +STRUCT + 100 FIELD >cdb-req +constant /cdb-buf + +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 +; + +: 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 +; + +: 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 + 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 +; + +: 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 +; + +: 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 +; + +: 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 +; + +: 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 +; + +: set-target ( srplun -- ) + virtio-scsi-debug IF + dup ." Setting target " . cr + THEN + 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 = +; + +: 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 +; + +: 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 +; + +#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 +; + +: 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 +; + +: virtio-scsi-create-cdrom ( srplun -- ) + " cdrom" 1 virtio-scsi " generic-scsi-device.fs" included +; + +: virtio-scsi-find-disks ( -- ) + ." VIRTIO-SCSI: Looking for devices" cr + 0 set-target + report-luns IF + 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 + ." " 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 + dup dup OF ." ? (" . 8 emit 29 emit 5 spaces ENDOF + ENDCASE + sector .inquiry-text cr + THEN + 8 + + LOOP drop + THEN + drop +; + +scsi-close \ no further scsi words required + +0 VALUE queue-control-addr +0 VALUE queue-event-addr +0 VALUE queue-cmd-addr + +: setup-virt-queues + \ add 3 queues 0-controlq, 1-eventq, 2-cmdq + \ fixme: do we need to find more than the above 3 queues if exists + virtiodev 0 virtio-get-qsize virtio-vring-size + alloc-mem to queue-control-addr + virtiodev 0 queue-control-addr virtio-set-qaddr + + virtiodev 1 virtio-get-qsize virtio-vring-size + alloc-mem to queue-event-addr + virtiodev 1 queue-event-addr virtio-set-qaddr + + virtiodev 2 virtio-get-qsize virtio-vring-size + alloc-mem to queue-cmd-addr + virtiodev 2 queue-cmd-addr virtio-set-qaddr +; + +\ Set disk alias if none is set yet +: setup-alias + s" disk" find-alias 0= IF + s" disk" get-node node>path set-alias + ELSE + drop + THEN +; + +: virito-scsi-shutdown ( -- ) + virtiodev virtio-scsi-shutdown + FALSE to initialized? +; + +: virtio-scsi-init-and-scan ( -- ) + \ Create instance for scanning: + 0 0 get-node open-node ?dup 0= IF ." exiting " cr EXIT THEN + my-self >r + dup to my-self + \ Scan the VSCSI bus: + virtiodev virtio-scsi-init + dup 0= IF + setup-virt-queues + virtio-scsi-find-disks + setup-alias + TRUE to initialized? + ['] virtio-scsi-shutdown add-quiesce-xt + THEN + \ Close the temporary instance: + close-node + r> to my-self +; + +virtio-scsi-init-and-scan diff --git a/lib/libvirtio/Makefile b/lib/libvirtio/Makefile index 994a885..e61457f 100644 --- a/lib/libvirtio/Makefile +++ b/lib/libvirtio/Makefile @@ -22,7 +22,7 @@ TARGET = ../libvirtio.a all: $(TARGET) -SRCS = virtio.c virtio-blk.c p9.c virtio-9p.c +SRCS = virtio.c virtio-blk.c p9.c virtio-9p.c virtio-scsi.c OBJS = $(SRCS:%.c=%.o) diff --git a/lib/libvirtio/virtio-scsi.c b/lib/libvirtio/virtio-scsi.c new file mode 100644 index 0000000..dba0cff --- /dev/null +++ b/lib/libvirtio/virtio-scsi.c @@ -0,0 +1,143 @@ +/****************************************************************************** + * Copyright (c) 2012 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 + *****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include "virtio.h" +#include "virtio-scsi.h" + +#define sync() asm volatile (" sync \n" ::: "memory") + +int virtioscsi_send(struct virtio_device *dev, + struct virtio_scsi_req_cmd *req, + struct virtio_scsi_resp_cmd *resp, + int is_read, void *buf, uint64_t buf_len) +{ + struct vring_desc *desc; + struct vring_desc *vq_desc; /* Descriptor vring */ + struct vring_avail *vq_avail; /* "Available" vring */ + struct vring_used *vq_used; /* "Used" vring */ + + volatile uint16_t *current_used_idx; + uint16_t last_used_idx; + int id, i; + uint32_t vq_size; + + int vq = VIRTIO_SCSI_REQUEST_VQ; + + vq_size = virtio_get_qsize(dev, vq); + vq_desc = virtio_get_vring_desc(dev, vq); + vq_avail = virtio_get_vring_avail(dev, vq); + vq_used = virtio_get_vring_used(dev, vq); + + last_used_idx = vq_used->idx; + current_used_idx = &vq_used->idx; + + /* Determine descriptor index */ + id = (vq_avail->idx * 3) % vq_size; + + desc = &vq_desc[id]; + desc->addr = (uint64_t)req; + desc->len = sizeof(*req); + desc->flags = VRING_DESC_F_NEXT; + desc->next = (id + 1) % vq_size; + + /* Set up virtqueue descriptor for data */ + desc = &vq_desc[(id + 1) % vq_size]; + desc->addr = (uint64_t)resp; + desc->len = sizeof(*resp); + desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE; + desc->next = (id + 2) % vq_size; + + if (buf && buf_len) { + /* Set up virtqueue descriptor for status */ + desc = &vq_desc[(id + 2) % vq_size]; + desc->addr = (uint64_t)buf; + desc->len = buf_len; + desc->flags = is_read ? VRING_DESC_F_WRITE : 0; + desc->next = 0; + } else + desc->flags &= ~VRING_DESC_F_NEXT; + + vq_avail->ring[vq_avail->idx % vq_size] = id; + sync(); + vq_avail->idx += 1; + + /* Tell HV that the vq is ready */ + virtio_queue_notify(dev, vq); + + /* Wait for host to consume the descriptor */ + i = 10000000; + while (*current_used_idx == last_used_idx && i-- > 0) { + // do something better + sync(); + } + + return 0; +} + +/** + * Initialize virtio-block device. + * @param dev pointer to virtio device information + */ +int virtioscsi_init(struct virtio_device *dev) +{ + struct vring_avail *vq_avail; + unsigned int idx = 0; + int qsize = 0; + + /* Reset device */ + // XXX That will clear the virtq base. We need to move + // initializing it to here anyway + // + // virtio_reset_device(dev); + + /* Acknowledge device. */ + virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE); + + /* Tell HV that we know how to drive the device. */ + virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER); + + /* Device specific setup - we do not support special features right now */ + virtio_set_guest_features(dev, 0); + + while(1) { + qsize = virtio_get_qsize(dev, idx); + if (!qsize) + break; + virtio_vring_size(qsize); + + vq_avail = virtio_get_vring_avail(dev, 0); + vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT; + vq_avail->idx = 0; + idx++; + } + + /* Tell HV that setup succeeded */ + virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER + |VIRTIO_STAT_DRIVER_OK); + + return 0; +} + +/** + * Shutdown the virtio-block device. + * @param dev pointer to virtio device information + */ +void virtioscsi_shutdown(struct virtio_device *dev) +{ + /* Quiesce device */ + virtio_set_status(dev, VIRTIO_STAT_FAILED); + + /* Reset device */ + virtio_reset_device(dev); +} diff --git a/lib/libvirtio/virtio-scsi.h b/lib/libvirtio/virtio-scsi.h new file mode 100644 index 0000000..451ba4d --- /dev/null +++ b/lib/libvirtio/virtio-scsi.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * Copyright (c) 2012 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 + *****************************************************************************/ + +/* + * Virtio SCSI Host device definitions. + * See Virtio Spec, Appendix I, for details + */ + +#ifndef _VIRTIO_SCSI_H +#define _VIRTIO_SCSI_H + +#define VIRTIO_SCSI_CDB_SIZE 32 +#define VIRTIO_SCSI_SENSE_SIZE 96 + +#define VIRTIO_SCSI_CONTROL_VQ 0 +#define VIRTIO_SCSI_EVENT_VQ 1 +#define VIRTIO_SCSI_REQUEST_VQ 2 + +struct virtio_scsi_config +{ + uint32_t num_queues; + uint32_t seg_max; + uint32_t max_sectors; + uint32_t cmd_per_lun; + uint32_t event_info_size; + uint32_t sense_size; + uint32_t cdb_size; + uint16_t max_channel; + uint16_t max_target; + uint32_t max_lun; +} __attribute__((packed)); + +/* This is the first element of the "out" scatter-gather list. */ +struct virtio_scsi_req_cmd { + uint8_t lun[8]; + uint64_t tag; + uint8_t task_attr; + uint8_t prio; + uint8_t crn; + char cdb[VIRTIO_SCSI_CDB_SIZE]; +}; + +/* This is the first element of the "in" scatter-gather list. */ +struct virtio_scsi_resp_cmd { + uint32_t sense_len; + uint32_t residual; + uint16_t status_qualifier; + uint8_t status; + uint8_t response; + uint8_t sense[VIRTIO_SCSI_SENSE_SIZE]; +}; + +extern int virtioscsi_init(struct virtio_device *dev); +extern void virtioscsi_shutdown(struct virtio_device *dev); +extern int virtioscsi_send(struct virtio_device *dev, + struct virtio_scsi_req_cmd *req, + struct virtio_scsi_resp_cmd *resp, + int is_read, void *buf, uint64_t buf_len); + +#endif /* _VIRTIO_SCSI_H */ diff --git a/lib/libvirtio/virtio.code b/lib/libvirtio/virtio.code index 100cc96..9c50c92 100644 --- a/lib/libvirtio/virtio.code +++ b/lib/libvirtio/virtio.code @@ -13,6 +13,7 @@ #include <virtio.h> #include <virtio-blk.h> #include <virtio-9p.h> +#include <virtio-scsi.h> /******** core virtio ********/ @@ -92,3 +93,29 @@ PRIM(virtio_X2d_fs_X2d_load) TOS.n = virtio_9p_load(dev, str, buf); MIRP + +/******** virtio-scsi ********/ + +// : virtio-scsi-init ( dev -- success ) +PRIM(virtio_X2d_scsi_X2d_init) + void *dev = TOS.a; + TOS.u = virtioscsi_init(dev); +MIRP + +// : virtio-scsi-shutdown ( dev -- ) +PRIM(virtio_X2d_scsi_X2d_shutdown) + void *dev = TOS.a; POP; + virtioscsi_shutdown(dev); +MIRP + +// : virtio-scsi-send ( buf_addr buf_len is_read req_ptr rsp_ptr dev -- success) +PRIM(virtio_X2d_scsi_X2d_send) + void *dev = TOS.a; POP; + void *resp = TOS.a; POP; + void *req = TOS.a; POP; + int is_read = !!TOS.n; POP; + uint64_t blen = TOS.n; POP; + void *buf = TOS.a; + TOS.n = virtioscsi_send(dev, req, resp, is_read, buf, blen); +MIRP + diff --git a/lib/libvirtio/virtio.in b/lib/libvirtio/virtio.in index a702779..e62341d 100644 --- a/lib/libvirtio/virtio.in +++ b/lib/libvirtio/virtio.in @@ -19,6 +19,10 @@ cod(virtio-blk-init) cod(virtio-blk-shutdown) cod(virtio-blk-read) +cod(virtio-scsi-init) +cod(virtio-scsi-shutdown) +cod(virtio-scsi-send) + cod(virtio-fs-init) cod(virtio-fs-shutdown) cod(virtio-fs-load) |