aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board-qemu/slof/Makefile3
-rw-r--r--board-qemu/slof/pci-device_1af4_1004.fs1
-rw-r--r--board-qemu/slof/virtio-scsi.fs252
-rw-r--r--lib/libvirtio/Makefile2
-rw-r--r--lib/libvirtio/virtio-scsi.c143
-rw-r--r--lib/libvirtio/virtio-scsi.h69
-rw-r--r--lib/libvirtio/virtio.code27
-rw-r--r--lib/libvirtio/virtio.in4
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)