aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNikunj A. Dadhania <nikunj@linux.vnet.ibm.com>2013-06-05 16:05:09 +1000
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-06-05 16:12:31 +1000
commitb5595b4565b65e02c6cdc083951bc439b9a353af (patch)
tree6fee9f9d4776ebbd88e97f03a56e66038296b85d /lib
parent41deea102e8233b7278155a0c41bf850bc5a6d07 (diff)
downloadSLOF-b5595b4565b65e02c6cdc083951bc439b9a353af.zip
SLOF-b5595b4565b65e02c6cdc083951bc439b9a353af.tar.gz
SLOF-b5595b4565b65e02c6cdc083951bc439b9a353af.tar.bz2
SLOF: virtio-scsi helper routines
* initialize/shutdown virtio-scsi device * routine for sending scsi commands to virtio-scsi device [ Modified to pass the whole virtio req/resp from forth to allow better handling of status and sense buffer -- BenH ] Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'lib')
-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
5 files changed, 244 insertions, 1 deletions
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)