summaryrefslogtreecommitdiffstats
path: root/linux-3.3-virtio-scsi.patch
diff options
context:
space:
mode:
authorJustin M. Forbes <jforbes@redhat.com>2012-03-26 20:22:58 -0500
committerJustin M. Forbes <jforbes@redhat.com>2012-03-26 20:22:58 -0500
commit62c169cbc376249a4e1994067edc62c7b64d4c47 (patch)
tree095edccb253747c2d04518f25e48282d34cfd4d8 /linux-3.3-virtio-scsi.patch
parentd5a077e50087def572b513c01402be19eeac933e (diff)
downloadkernel-62c169cbc376249a4e1994067edc62c7b64d4c47.tar.gz
kernel-62c169cbc376249a4e1994067edc62c7b64d4c47.tar.xz
kernel-62c169cbc376249a4e1994067edc62c7b64d4c47.zip
Linux v3.3-6972-ge22057c
Diffstat (limited to 'linux-3.3-virtio-scsi.patch')
-rw-r--r--linux-3.3-virtio-scsi.patch993
1 files changed, 0 insertions, 993 deletions
diff --git a/linux-3.3-virtio-scsi.patch b/linux-3.3-virtio-scsi.patch
deleted file mode 100644
index 9d944f5d2..000000000
--- a/linux-3.3-virtio-scsi.patch
+++ /dev/null
@@ -1,993 +0,0 @@
-From 43cf1b6a4ee31e69581042a0c85d1398f83dcedc Mon Sep 17 00:00:00 2001
-From: Paolo Bonzini <pbonzini@redhat.com>
-Date: Fri, 20 Jan 2012 17:27:20 +0100
-Cc: <linux-scsi@vger.kernel.org>
-Cc: Rusty Russell <rusty@rustcorp.com.au>
-Cc: kvm@vger.kernel.org
-Cc: Pekka Enberg <penberg@kernel.org>
-Cc: Michael S. Tsirkin <mst@redhat.com>
-Cc: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>, Mike Christie <michaelc@cs.wisc.edu>
-Subject: [PATCH v5 0/3] virtio-scsi driver
-
-This is the first implementation of the virtio-scsi driver, a virtual
-HBA that will be supported by KVM. It implements a subset of the spec,
-in particular it does not implement asynchronous notifications for either
-LUN reset/removal/addition or CD-ROM media events, but it is already
-functional and usable.
-
-Other matching bits:
-
-- spec at http://people.redhat.com/pbonzini/virtio-spec.pdf
-
-- QEMU implementation at git://github.com/bonzini/qemu.git,
- branch virtio-scsi
-
-Please review. Getting this in 3.3 is starting to look like wishful thinking,
-but the possibility of regressions is obviously zero so I'm still dreaming.
-Otherwise, that would be 3.4.
-
-Paolo Bonzini (3):
- virtio-scsi: first version
- virtio-scsi: add error handling
- virtio-scsi: add power management support
-
-v4->v5: change virtio id from 7 to 8
-
-v3->v4: renamed VIRTIO_SCSI_S_UNDERRUN to VIRTIO_SCSI_S_OVERRUN;
- fixed 32-bit compilation; added power management support;
- adjusted calls to virtqueue_add_buf
-
- drivers/scsi/Kconfig | 8 +
- drivers/scsi/Makefile | 1 +
- drivers/scsi/virtio_scsi.c | 594 +++++++++++++++++++++++++++++++++++++++++++
- include/linux/virtio_ids.h | 1 +
- include/linux/virtio_scsi.h | 114 +++++++++
- 5 files changed, 718 insertions(+), 0 deletions(-)
- create mode 100644 drivers/scsi/virtio_scsi.c
- create mode 100644 include/linux/virtio_scsi.h
-
-From 84ad93b7215e18ab1755a625ede0fb00175e79bb Mon Sep 17 00:00:00 2001
-From: Paolo Bonzini <pbonzini@redhat.com>
-Date: Tue, 29 Nov 2011 16:31:09 +0100
-Cc: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>, Mike Christie <michaelc@cs.wisc.edu>, Pekka Enberg <penberg@kernel.org>
-Subject: [PATCH v5 1/3] virtio-scsi: first version
-
-The virtio-scsi HBA is the basis of an alternative storage stack
-for QEMU-based virtual machines (including KVM). Compared to
-virtio-blk it is more scalable, because it supports many LUNs
-on a single PCI slot), more powerful (it more easily supports
-passthrough of host devices to the guest) and more easily
-extensible (new SCSI features implemented by QEMU should not
-require updating the driver in the guest).
-
-Cc: linux-scsi <linux-scsi@vger.kernel.org>
-Cc: Rusty Russell <rusty@rustcorp.com.au>
-Cc: Michael S. Tsirkin <mst@redhat.com>
-Cc: kvm@vger.kernel.org
-Acked-by: Pekka Enberg <penberg@kernel.org>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- v4->v5: change virtio id from 7 to 8
-
- v3->v4: renamed VIRTIO_SCSI_S_UNDERRUN to VIRTIO_SCSI_S_OVERRUN;
- fixed 32-bit compilation; adjust call to virtqueue_add_buf
-
- v2->v3: added mempool, formatting fixes
-
- v1->v2: use dbg_dev, sdev_printk, scmd_printk
- - renamed lock to vq_lock
- - renamed cmd_vq to req_vq (and other similar changes)
- - fixed missing break in VIRTIO_SCSI_S_OVERRUN
- - added VIRTIO_SCSI_S_BUSY
- - removed unused argument from virtscsi_map_cmd
- - fixed two tabs that had slipped in
- - moved max_sectors and cmd_per_lun from template to config space
- - __attribute__((packed)) -> __packed
-
- drivers/scsi/Kconfig | 8 +
- drivers/scsi/Makefile | 1 +
- drivers/scsi/virtio_scsi.c | 503 +++++++++++++++++++++++++++++++++++++++++++
- include/linux/virtio_ids.h | 1 +
- include/linux/virtio_scsi.h | 114 ++++++++++
- 5 files changed, 627 insertions(+), 0 deletions(-)
- create mode 100644 drivers/scsi/virtio_scsi.c
- create mode 100644 include/linux/virtio_scsi.h
-
-diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
-index 16570aa..827ebaf 100644
---- a/drivers/scsi/Kconfig
-+++ b/drivers/scsi/Kconfig
-@@ -1897,6 +1897,14 @@ config SCSI_BFA_FC
- To compile this driver as a module, choose M here. The module will
- be called bfa.
-
-+config SCSI_VIRTIO
-+ tristate "virtio-scsi support (EXPERIMENTAL)"
-+ depends on EXPERIMENTAL && VIRTIO
-+ help
-+ This is the virtual HBA driver for virtio. If the kernel will
-+ be used in a virtual machine, say Y or M.
-+
-+
- endif # SCSI_LOWLEVEL
-
- source "drivers/scsi/pcmcia/Kconfig"
-diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
-index e4c1a69..ad24e06 100644
---- a/drivers/scsi/Makefile
-+++ b/drivers/scsi/Makefile
-@@ -141,6 +141,7 @@ obj-$(CONFIG_SCSI_CXGB4_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/
- obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/
- obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/
- obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o
-+obj-$(CONFIG_SCSI_VIRTIO) += virtio_scsi.o
- obj-$(CONFIG_VMWARE_PVSCSI) += vmw_pvscsi.o
- obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o
-
-diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
-new file mode 100644
-index 0000000..3f87ae0
---- /dev/null
-+++ b/drivers/scsi/virtio_scsi.c
-@@ -0,0 +1,503 @@
-+/*
-+ * Virtio SCSI HBA driver
-+ *
-+ * Copyright IBM Corp. 2010
-+ * Copyright Red Hat, Inc. 2011
-+ *
-+ * Authors:
-+ * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
-+ * Paolo Bonzini <pbonzini@redhat.com>
-+ *
-+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
-+ * See the COPYING file in the top-level directory.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/mempool.h>
-+#include <linux/virtio.h>
-+#include <linux/virtio_ids.h>
-+#include <linux/virtio_config.h>
-+#include <linux/virtio_scsi.h>
-+#include <scsi/scsi_host.h>
-+#include <scsi/scsi_device.h>
-+#include <scsi/scsi_cmnd.h>
-+
-+#define VIRTIO_SCSI_MEMPOOL_SZ 64
-+
-+/* Command queue element */
-+struct virtio_scsi_cmd {
-+ struct scsi_cmnd *sc;
-+ union {
-+ struct virtio_scsi_cmd_req cmd;
-+ struct virtio_scsi_ctrl_tmf_req tmf;
-+ struct virtio_scsi_ctrl_an_req an;
-+ } req;
-+ union {
-+ struct virtio_scsi_cmd_resp cmd;
-+ struct virtio_scsi_ctrl_tmf_resp tmf;
-+ struct virtio_scsi_ctrl_an_resp an;
-+ struct virtio_scsi_event evt;
-+ } resp;
-+} ____cacheline_aligned_in_smp;
-+
-+/* Driver instance state */
-+struct virtio_scsi {
-+ /* Protects ctrl_vq, req_vq and sg[] */
-+ spinlock_t vq_lock;
-+
-+ struct virtio_device *vdev;
-+ struct virtqueue *ctrl_vq;
-+ struct virtqueue *event_vq;
-+ struct virtqueue *req_vq;
-+
-+ /* For sglist construction when adding commands to the virtqueue. */
-+ struct scatterlist sg[];
-+};
-+
-+static struct kmem_cache *virtscsi_cmd_cache;
-+static mempool_t *virtscsi_cmd_pool;
-+
-+static inline struct Scsi_Host *virtio_scsi_host(struct virtio_device *vdev)
-+{
-+ return vdev->priv;
-+}
-+
-+static void virtscsi_compute_resid(struct scsi_cmnd *sc, u32 resid)
-+{
-+ if (!resid)
-+ return;
-+
-+ if (!scsi_bidi_cmnd(sc)) {
-+ scsi_set_resid(sc, resid);
-+ return;
-+ }
-+
-+ scsi_in(sc)->resid = min(resid, scsi_in(sc)->length);
-+ scsi_out(sc)->resid = resid - scsi_in(sc)->resid;
-+}
-+
-+/**
-+ * virtscsi_complete_cmd - finish a scsi_cmd and invoke scsi_done
-+ *
-+ * Called with vq_lock held.
-+ */
-+static void virtscsi_complete_cmd(void *buf)
-+{
-+ struct virtio_scsi_cmd *cmd = buf;
-+ struct scsi_cmnd *sc = cmd->sc;
-+ struct virtio_scsi_cmd_resp *resp = &cmd->resp.cmd;
-+
-+ dev_dbg(&sc->device->sdev_gendev,
-+ "cmd %p response %u status %#02x sense_len %u\n",
-+ sc, resp->response, resp->status, resp->sense_len);
-+
-+ sc->result = resp->status;
-+ virtscsi_compute_resid(sc, resp->resid);
-+ switch (resp->response) {
-+ case VIRTIO_SCSI_S_OK:
-+ set_host_byte(sc, DID_OK);
-+ break;
-+ case VIRTIO_SCSI_S_OVERRUN:
-+ set_host_byte(sc, DID_ERROR);
-+ break;
-+ case VIRTIO_SCSI_S_ABORTED:
-+ set_host_byte(sc, DID_ABORT);
-+ break;
-+ case VIRTIO_SCSI_S_BAD_TARGET:
-+ set_host_byte(sc, DID_BAD_TARGET);
-+ break;
-+ case VIRTIO_SCSI_S_RESET:
-+ set_host_byte(sc, DID_RESET);
-+ break;
-+ case VIRTIO_SCSI_S_BUSY:
-+ set_host_byte(sc, DID_BUS_BUSY);
-+ break;
-+ case VIRTIO_SCSI_S_TRANSPORT_FAILURE:
-+ set_host_byte(sc, DID_TRANSPORT_DISRUPTED);
-+ break;
-+ case VIRTIO_SCSI_S_TARGET_FAILURE:
-+ set_host_byte(sc, DID_TARGET_FAILURE);
-+ break;
-+ case VIRTIO_SCSI_S_NEXUS_FAILURE:
-+ set_host_byte(sc, DID_NEXUS_FAILURE);
-+ break;
-+ default:
-+ scmd_printk(KERN_WARNING, sc, "Unknown response %d",
-+ resp->response);
-+ /* fall through */
-+ case VIRTIO_SCSI_S_FAILURE:
-+ set_host_byte(sc, DID_ERROR);
-+ break;
-+ }
-+
-+ WARN_ON(resp->sense_len > VIRTIO_SCSI_SENSE_SIZE);
-+ if (sc->sense_buffer) {
-+ memcpy(sc->sense_buffer, resp->sense,
-+ min_t(u32, resp->sense_len, VIRTIO_SCSI_SENSE_SIZE));
-+ if (resp->sense_len)
-+ set_driver_byte(sc, DRIVER_SENSE);
-+ }
-+
-+ mempool_free(cmd, virtscsi_cmd_pool);
-+ sc->scsi_done(sc);
-+}
-+
-+static void virtscsi_vq_done(struct virtqueue *vq, void (*fn)(void *buf))
-+{
-+ struct Scsi_Host *sh = virtio_scsi_host(vq->vdev);
-+ struct virtio_scsi *vscsi = shost_priv(sh);
-+ void *buf;
-+ unsigned long flags;
-+ unsigned int len;
-+
-+ spin_lock_irqsave(&vscsi->vq_lock, flags);
-+
-+ do {
-+ virtqueue_disable_cb(vq);
-+ while ((buf = virtqueue_get_buf(vq, &len)) != NULL)
-+ fn(buf);
-+ } while (!virtqueue_enable_cb(vq));
-+
-+ spin_unlock_irqrestore(&vscsi->vq_lock, flags);
-+}
-+
-+static void virtscsi_req_done(struct virtqueue *vq)
-+{
-+ virtscsi_vq_done(vq, virtscsi_complete_cmd);
-+};
-+
-+/* These are still stubs. */
-+static void virtscsi_complete_free(void *buf)
-+{
-+ struct virtio_scsi_cmd *cmd = buf;
-+
-+ mempool_free(cmd, virtscsi_cmd_pool);
-+}
-+
-+static void virtscsi_ctrl_done(struct virtqueue *vq)
-+{
-+ virtscsi_vq_done(vq, virtscsi_complete_free);
-+};
-+
-+static void virtscsi_event_done(struct virtqueue *vq)
-+{
-+ virtscsi_vq_done(vq, virtscsi_complete_free);
-+};
-+
-+static void virtscsi_map_sgl(struct scatterlist *sg, unsigned int *p_idx,
-+ struct scsi_data_buffer *sdb)
-+{
-+ struct sg_table *table = &sdb->table;
-+ struct scatterlist *sg_elem;
-+ unsigned int idx = *p_idx;
-+ int i;
-+
-+ for_each_sg(table->sgl, sg_elem, table->nents, i)
-+ sg_set_buf(&sg[idx++], sg_virt(sg_elem), sg_elem->length);
-+
-+ *p_idx = idx;
-+}
-+
-+/**
-+ * virtscsi_map_cmd - map a scsi_cmd to a virtqueue scatterlist
-+ * @vscsi : virtio_scsi state
-+ * @cmd : command structure
-+ * @out_num : number of read-only elements
-+ * @in_num : number of write-only elements
-+ * @req_size : size of the request buffer
-+ * @resp_size : size of the response buffer
-+ *
-+ * Called with vq_lock held.
-+ */
-+static void virtscsi_map_cmd(struct virtio_scsi *vscsi,
-+ struct virtio_scsi_cmd *cmd,
-+ unsigned *out_num, unsigned *in_num,
-+ size_t req_size, size_t resp_size)
-+{
-+ struct scsi_cmnd *sc = cmd->sc;
-+ struct scatterlist *sg = vscsi->sg;
-+ unsigned int idx = 0;
-+
-+ if (sc) {
-+ struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
-+ BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize);
-+
-+ /* TODO: check feature bit and fail if unsupported? */
-+ BUG_ON(sc->sc_data_direction == DMA_BIDIRECTIONAL);
-+ }
-+
-+ /* Request header. */
-+ sg_set_buf(&sg[idx++], &cmd->req, req_size);
-+
-+ /* Data-out buffer. */
-+ if (sc && sc->sc_data_direction != DMA_FROM_DEVICE)
-+ virtscsi_map_sgl(sg, &idx, scsi_out(sc));
-+
-+ *out_num = idx;
-+
-+ /* Response header. */
-+ sg_set_buf(&sg[idx++], &cmd->resp, resp_size);
-+
-+ /* Data-in buffer */
-+ if (sc && sc->sc_data_direction != DMA_TO_DEVICE)
-+ virtscsi_map_sgl(sg, &idx, scsi_in(sc));
-+
-+ *in_num = idx - *out_num;
-+}
-+
-+static int virtscsi_kick_cmd(struct virtio_scsi *vscsi, struct virtqueue *vq,
-+ struct virtio_scsi_cmd *cmd,
-+ size_t req_size, size_t resp_size, gfp_t gfp)
-+{
-+ unsigned int out_num, in_num;
-+ unsigned long flags;
-+ int ret;
-+
-+ spin_lock_irqsave(&vscsi->vq_lock, flags);
-+
-+ virtscsi_map_cmd(vscsi, cmd, &out_num, &in_num, req_size, resp_size);
-+
-+ ret = virtqueue_add_buf(vq, vscsi->sg, out_num, in_num, cmd, gfp);
-+ if (ret >= 0)
-+ virtqueue_kick(vq);
-+
-+ spin_unlock_irqrestore(&vscsi->vq_lock, flags);
-+ return ret;
-+}
-+
-+static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
-+{
-+ struct virtio_scsi *vscsi = shost_priv(sh);
-+ struct virtio_scsi_cmd *cmd;
-+ int ret;
-+
-+ dev_dbg(&sc->device->sdev_gendev,
-+ "cmd %p CDB: %#02x\n", sc, sc->cmnd[0]);
-+
-+ ret = SCSI_MLQUEUE_HOST_BUSY;
-+ cmd = mempool_alloc(virtscsi_cmd_pool, GFP_ATOMIC);
-+ if (!cmd)
-+ goto out;
-+
-+ memset(cmd, 0, sizeof(*cmd));
-+ cmd->sc = sc;
-+ cmd->req.cmd = (struct virtio_scsi_cmd_req){
-+ .lun[0] = 1,
-+ .lun[1] = sc->device->id,
-+ .lun[2] = (sc->device->lun >> 8) | 0x40,
-+ .lun[3] = sc->device->lun & 0xff,
-+ .tag = (unsigned long)sc,
-+ .task_attr = VIRTIO_SCSI_S_SIMPLE,
-+ .prio = 0,
-+ .crn = 0,
-+ };
-+
-+ BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE);
-+ memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len);
-+
-+ if (virtscsi_kick_cmd(vscsi, vscsi->req_vq, cmd,
-+ sizeof cmd->req.cmd, sizeof cmd->resp.cmd,
-+ GFP_ATOMIC) >= 0)
-+ ret = 0;
-+
-+out:
-+ return ret;
-+}
-+
-+static struct scsi_host_template virtscsi_host_template = {
-+ .module = THIS_MODULE,
-+ .name = "Virtio SCSI HBA",
-+ .proc_name = "virtio_scsi",
-+ .queuecommand = virtscsi_queuecommand,
-+ .this_id = -1,
-+
-+ .can_queue = 1024,
-+ .dma_boundary = UINT_MAX,
-+ .use_clustering = ENABLE_CLUSTERING,
-+};
-+
-+#define virtscsi_config_get(vdev, fld) \
-+ ({ \
-+ typeof(((struct virtio_scsi_config *)0)->fld) __val; \
-+ vdev->config->get(vdev, \
-+ offsetof(struct virtio_scsi_config, fld), \
-+ &__val, sizeof(__val)); \
-+ __val; \
-+ })
-+
-+#define virtscsi_config_set(vdev, fld, val) \
-+ (void)({ \
-+ typeof(((struct virtio_scsi_config *)0)->fld) __val = (val); \
-+ vdev->config->set(vdev, \
-+ offsetof(struct virtio_scsi_config, fld), \
-+ &__val, sizeof(__val)); \
-+ })
-+
-+static int __devinit virtscsi_init(struct virtio_device *vdev,
-+ struct virtio_scsi *vscsi)
-+{
-+ int err;
-+ struct virtqueue *vqs[3];
-+ vq_callback_t *callbacks[] = {
-+ virtscsi_ctrl_done,
-+ virtscsi_event_done,
-+ virtscsi_req_done
-+ };
-+ const char *names[] = {
-+ "control",
-+ "event",
-+ "request"
-+ };
-+
-+ /* Discover virtqueues and write information to configuration. */
-+ err = vdev->config->find_vqs(vdev, 3, vqs, callbacks, names);
-+ if (err)
-+ return err;
-+
-+ vscsi->ctrl_vq = vqs[0];
-+ vscsi->event_vq = vqs[1];
-+ vscsi->req_vq = vqs[2];
-+
-+ virtscsi_config_set(vdev, cdb_size, VIRTIO_SCSI_CDB_SIZE);
-+ virtscsi_config_set(vdev, sense_size, VIRTIO_SCSI_SENSE_SIZE);
-+ return 0;
-+}
-+
-+static int __devinit virtscsi_probe(struct virtio_device *vdev)
-+{
-+ struct Scsi_Host *shost;
-+ struct virtio_scsi *vscsi;
-+ int err;
-+ u32 sg_elems;
-+ u32 cmd_per_lun;
-+
-+ /* We need to know how many segments before we allocate.
-+ * We need an extra sg elements at head and tail.
-+ */
-+ sg_elems = virtscsi_config_get(vdev, seg_max) ?: 1;
-+
-+ /* Allocate memory and link the structs together. */
-+ shost = scsi_host_alloc(&virtscsi_host_template,
-+ sizeof(*vscsi) + sizeof(vscsi->sg[0]) * (sg_elems + 2));
-+
-+ if (!shost)
-+ return -ENOMEM;
-+
-+ shost->sg_tablesize = sg_elems;
-+ vscsi = shost_priv(shost);
-+ vscsi->vdev = vdev;
-+ vdev->priv = shost;
-+
-+ /* Random initializations. */
-+ spin_lock_init(&vscsi->vq_lock);
-+ sg_init_table(vscsi->sg, sg_elems + 2);
-+
-+ err = virtscsi_init(vdev, vscsi);
-+ if (err)
-+ goto virtscsi_init_failed;
-+
-+ cmd_per_lun = virtscsi_config_get(vdev, cmd_per_lun) ?: 1;
-+ shost->cmd_per_lun = min_t(u32, cmd_per_lun, shost->can_queue);
-+ shost->max_sectors = virtscsi_config_get(vdev, max_sectors) ?: 0xFFFF;
-+ shost->max_lun = virtscsi_config_get(vdev, max_lun) + 1;
-+ shost->max_id = virtscsi_config_get(vdev, max_target) + 1;
-+ shost->max_channel = 0;
-+ shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE;
-+ err = scsi_add_host(shost, &vdev->dev);
-+ if (err)
-+ goto scsi_add_host_failed;
-+
-+ scsi_scan_host(shost);
-+
-+ return 0;
-+
-+scsi_add_host_failed:
-+ vdev->config->del_vqs(vdev);
-+virtscsi_init_failed:
-+ scsi_host_put(shost);
-+ return err;
-+}
-+
-+static void __devexit virtscsi_remove_vqs(struct virtio_device *vdev)
-+{
-+ /* Stop all the virtqueues. */
-+ vdev->config->reset(vdev);
-+
-+ vdev->config->del_vqs(vdev);
-+}
-+
-+static void __devexit virtscsi_remove(struct virtio_device *vdev)
-+{
-+ struct Scsi_Host *shost = virtio_scsi_host(vdev);
-+
-+ scsi_remove_host(shost);
-+
-+ virtscsi_remove_vqs(vdev);
-+ scsi_host_put(shost);
-+}
-+
-+static struct virtio_device_id id_table[] = {
-+ { VIRTIO_ID_SCSI, VIRTIO_DEV_ANY_ID },
-+ { 0 },
-+};
-+
-+static struct virtio_driver virtio_scsi_driver = {
-+ .driver.name = KBUILD_MODNAME,
-+ .driver.owner = THIS_MODULE,
-+ .id_table = id_table,
-+ .probe = virtscsi_probe,
-+ .remove = __devexit_p(virtscsi_remove),
-+};
-+
-+static int __init init(void)
-+{
-+ int ret = -ENOMEM;
-+
-+ virtscsi_cmd_cache = KMEM_CACHE(virtio_scsi_cmd, 0);
-+ if (!virtscsi_cmd_cache) {
-+ printk(KERN_ERR "kmem_cache_create() for "
-+ "virtscsi_cmd_cache failed\n");
-+ goto error;
-+ }
-+
-+
-+ virtscsi_cmd_pool =
-+ mempool_create_slab_pool(VIRTIO_SCSI_MEMPOOL_SZ,
-+ virtscsi_cmd_cache);
-+ if (!virtscsi_cmd_pool) {
-+ printk(KERN_ERR "mempool_create() for"
-+ "virtscsi_cmd_pool failed\n");
-+ goto error;
-+ }
-+ ret = register_virtio_driver(&virtio_scsi_driver);
-+ if (ret < 0)
-+ goto error;
-+
-+ return 0;
-+
-+error:
-+ if (virtscsi_cmd_pool) {
-+ mempool_destroy(virtscsi_cmd_pool);
-+ virtscsi_cmd_pool = NULL;
-+ }
-+ if (virtscsi_cmd_cache) {
-+ kmem_cache_destroy(virtscsi_cmd_cache);
-+ virtscsi_cmd_cache = NULL;
-+ }
-+ return ret;
-+}
-+
-+static void __exit fini(void)
-+{
-+ unregister_virtio_driver(&virtio_scsi_driver);
-+ mempool_destroy(virtscsi_cmd_pool);
-+ kmem_cache_destroy(virtscsi_cmd_cache);
-+}
-+module_init(init);
-+module_exit(fini);
-+
-+MODULE_DEVICE_TABLE(virtio, id_table);
-+MODULE_DESCRIPTION("Virtio SCSI HBA driver");
-+MODULE_LICENSE("GPL");
-diff --git a/include/linux/virtio_ids.h b/include/linux/virtio_ids.h
-index 85bb0bb..d83ae52 100644
---- a/include/linux/virtio_ids.h
-+++ b/include/linux/virtio_ids.h
-@@ -34,6 +34,7 @@
- #define VIRTIO_ID_CONSOLE 3 /* virtio console */
- #define VIRTIO_ID_RNG 4 /* virtio ring */
- #define VIRTIO_ID_BALLOON 5 /* virtio balloon */
-+#define VIRTIO_ID_SCSI 8 /* virtio scsi */
- #define VIRTIO_ID_9P 9 /* 9p virtio console */
-
- #endif /* _LINUX_VIRTIO_IDS_H */
-diff --git a/include/linux/virtio_scsi.h b/include/linux/virtio_scsi.h
-new file mode 100644
-index 0000000..8ddeafd
---- /dev/null
-+++ b/include/linux/virtio_scsi.h
-@@ -0,0 +1,114 @@
-+#ifndef _LINUX_VIRTIO_SCSI_H
-+#define _LINUX_VIRTIO_SCSI_H
-+/* This header is BSD licensed so anyone can use the definitions to implement
-+ * compatible drivers/servers. */
-+
-+#define VIRTIO_SCSI_CDB_SIZE 32
-+#define VIRTIO_SCSI_SENSE_SIZE 96
-+
-+/* SCSI command request, followed by data-out */
-+struct virtio_scsi_cmd_req {
-+ u8 lun[8]; /* Logical Unit Number */
-+ u64 tag; /* Command identifier */
-+ u8 task_attr; /* Task attribute */
-+ u8 prio;
-+ u8 crn;
-+ u8 cdb[VIRTIO_SCSI_CDB_SIZE];
-+} __packed;
-+
-+/* Response, followed by sense data and data-in */
-+struct virtio_scsi_cmd_resp {
-+ u32 sense_len; /* Sense data length */
-+ u32 resid; /* Residual bytes in data buffer */
-+ u16 status_qualifier; /* Status qualifier */
-+ u8 status; /* Command completion status */
-+ u8 response; /* Response values */
-+ u8 sense[VIRTIO_SCSI_SENSE_SIZE];
-+} __packed;
-+
-+/* Task Management Request */
-+struct virtio_scsi_ctrl_tmf_req {
-+ u32 type;
-+ u32 subtype;
-+ u8 lun[8];
-+ u64 tag;
-+} __packed;
-+
-+struct virtio_scsi_ctrl_tmf_resp {
-+ u8 response;
-+} __packed;
-+
-+/* Asynchronous notification query/subscription */
-+struct virtio_scsi_ctrl_an_req {
-+ u32 type;
-+ u8 lun[8];
-+ u32 event_requested;
-+} __packed;
-+
-+struct virtio_scsi_ctrl_an_resp {
-+ u32 event_actual;
-+ u8 response;
-+} __packed;
-+
-+struct virtio_scsi_event {
-+ u32 event;
-+ u8 lun[8];
-+ u32 reason;
-+} __packed;
-+
-+struct virtio_scsi_config {
-+ u32 num_queues;
-+ u32 seg_max;
-+ u32 max_sectors;
-+ u32 cmd_per_lun;
-+ u32 event_info_size;
-+ u32 sense_size;
-+ u32 cdb_size;
-+ u16 max_channel;
-+ u16 max_target;
-+ u32 max_lun;
-+} __packed;
-+
-+/* Response codes */
-+#define VIRTIO_SCSI_S_OK 0
-+#define VIRTIO_SCSI_S_OVERRUN 1
-+#define VIRTIO_SCSI_S_ABORTED 2
-+#define VIRTIO_SCSI_S_BAD_TARGET 3
-+#define VIRTIO_SCSI_S_RESET 4
-+#define VIRTIO_SCSI_S_BUSY 5
-+#define VIRTIO_SCSI_S_TRANSPORT_FAILURE 6
-+#define VIRTIO_SCSI_S_TARGET_FAILURE 7
-+#define VIRTIO_SCSI_S_NEXUS_FAILURE 8
-+#define VIRTIO_SCSI_S_FAILURE 9
-+#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED 10
-+#define VIRTIO_SCSI_S_FUNCTION_REJECTED 11
-+#define VIRTIO_SCSI_S_INCORRECT_LUN 12
-+
-+/* Controlq type codes. */
-+#define VIRTIO_SCSI_T_TMF 0
-+#define VIRTIO_SCSI_T_AN_QUERY 1
-+#define VIRTIO_SCSI_T_AN_SUBSCRIBE 2
-+
-+/* Valid TMF subtypes. */
-+#define VIRTIO_SCSI_T_TMF_ABORT_TASK 0
-+#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET 1
-+#define VIRTIO_SCSI_T_TMF_CLEAR_ACA 2
-+#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET 3
-+#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET 4
-+#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET 5
-+#define VIRTIO_SCSI_T_TMF_QUERY_TASK 6
-+#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET 7
-+
-+/* Events. */
-+#define VIRTIO_SCSI_T_EVENTS_MISSED 0x80000000
-+#define VIRTIO_SCSI_T_NO_EVENT 0
-+#define VIRTIO_SCSI_T_TRANSPORT_RESET 1
-+#define VIRTIO_SCSI_T_ASYNC_NOTIFY 2
-+
-+#define VIRTIO_SCSI_S_SIMPLE 0
-+#define VIRTIO_SCSI_S_ORDERED 1
-+#define VIRTIO_SCSI_S_HEAD 2
-+#define VIRTIO_SCSI_S_ACA 3
-+
-+
-+#endif /* _LINUX_VIRTIO_SCSI_H */
---
-1.7.1
-
-
-From 3c0e8846ac0fc2175dd0e06f495b16a30b549762 Mon Sep 17 00:00:00 2001
-From: Paolo Bonzini <pbonzini@redhat.com>
-Date: Tue, 29 Nov 2011 16:33:28 +0100
-Cc: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>, Mike Christie <michaelc@cs.wisc.edu>, Pekka Enberg <penberg@kernel.org>
-Subject: [PATCH v5 2/3] virtio-scsi: add error handling
-
-This commit adds basic error handling to the virtio-scsi
-HBA device. Task management functions are sent synchronously
-via the control virtqueue.
-
-Cc: linux-scsi <linux-scsi@vger.kernel.org>
-Cc: Rusty Russell <rusty@rustcorp.com.au>
-Cc: Michael S. Tsirkin <mst@redhat.com>
-Cc: kvm@vger.kernel.org
-Acked-by: Pekka Enberg <penberg@kernel.org>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- v3->v4: fixed 32-bit compilation; adjusted call to virtscsi_kick_cmd
-
- v2->v3: added mempool, used GFP_NOIO instead of GFP_ATOMIC,
- formatting fixes
-
- v1->v2: use scmd_printk
-
- drivers/scsi/virtio_scsi.c | 73 +++++++++++++++++++++++++++++++++++++++++++-
- 1 files changed, 72 insertions(+), 1 deletions(-)
-
-diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
-index 3f87ae0..68104cd 100644
---- a/drivers/scsi/virtio_scsi.c
-+++ b/drivers/scsi/virtio_scsi.c
-@@ -29,6 +29,7 @@
- /* Command queue element */
- struct virtio_scsi_cmd {
- struct scsi_cmnd *sc;
-+ struct completion *comp;
- union {
- struct virtio_scsi_cmd_req cmd;
- struct virtio_scsi_ctrl_tmf_req tmf;
-@@ -168,11 +169,12 @@ static void virtscsi_req_done(struct virtqueue *vq)
- virtscsi_vq_done(vq, virtscsi_complete_cmd);
- };
-
--/* These are still stubs. */
- static void virtscsi_complete_free(void *buf)
- {
- struct virtio_scsi_cmd *cmd = buf;
-
-+ if (cmd->comp)
-+ complete_all(cmd->comp);
- mempool_free(cmd, virtscsi_cmd_pool);
- }
-
-@@ -306,12 +308,81 @@ out:
- return ret;
- }
-
-+static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
-+{
-+ DECLARE_COMPLETION_ONSTACK(comp);
-+ int ret;
-+
-+ cmd->comp = &comp;
-+ ret = virtscsi_kick_cmd(vscsi, vscsi->ctrl_vq, cmd,
-+ sizeof cmd->req.tmf, sizeof cmd->resp.tmf,
-+ GFP_NOIO);
-+ if (ret < 0)
-+ return FAILED;
-+
-+ wait_for_completion(&comp);
-+ if (cmd->resp.tmf.response != VIRTIO_SCSI_S_OK &&
-+ cmd->resp.tmf.response != VIRTIO_SCSI_S_FUNCTION_SUCCEEDED)
-+ return FAILED;
-+
-+ return SUCCESS;
-+}
-+
-+static int virtscsi_device_reset(struct scsi_cmnd *sc)
-+{
-+ struct virtio_scsi *vscsi = shost_priv(sc->device->host);
-+ struct virtio_scsi_cmd *cmd;
-+
-+ sdev_printk(KERN_INFO, sc->device, "device reset\n");
-+ cmd = mempool_alloc(virtscsi_cmd_pool, GFP_NOIO);
-+ if (!cmd)
-+ return FAILED;
-+
-+ memset(cmd, 0, sizeof(*cmd));
-+ cmd->sc = sc;
-+ cmd->req.tmf = (struct virtio_scsi_ctrl_tmf_req){
-+ .type = VIRTIO_SCSI_T_TMF,
-+ .subtype = VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET,
-+ .lun[0] = 1,
-+ .lun[1] = sc->device->id,
-+ .lun[2] = (sc->device->lun >> 8) | 0x40,
-+ .lun[3] = sc->device->lun & 0xff,
-+ };
-+ return virtscsi_tmf(vscsi, cmd);
-+}
-+
-+static int virtscsi_abort(struct scsi_cmnd *sc)
-+{
-+ struct virtio_scsi *vscsi = shost_priv(sc->device->host);
-+ struct virtio_scsi_cmd *cmd;
-+
-+ scmd_printk(KERN_INFO, sc, "abort\n");
-+ cmd = mempool_alloc(virtscsi_cmd_pool, GFP_NOIO);
-+ if (!cmd)
-+ return FAILED;
-+
-+ memset(cmd, 0, sizeof(*cmd));
-+ cmd->sc = sc;
-+ cmd->req.tmf = (struct virtio_scsi_ctrl_tmf_req){
-+ .type = VIRTIO_SCSI_T_TMF,
-+ .subtype = VIRTIO_SCSI_T_TMF_ABORT_TASK,
-+ .lun[0] = 1,
-+ .lun[1] = sc->device->id,
-+ .lun[2] = (sc->device->lun >> 8) | 0x40,
-+ .lun[3] = sc->device->lun & 0xff,
-+ .tag = (unsigned long)sc,
-+ };
-+ return virtscsi_tmf(vscsi, cmd);
-+}
-+
- static struct scsi_host_template virtscsi_host_template = {
- .module = THIS_MODULE,
- .name = "Virtio SCSI HBA",
- .proc_name = "virtio_scsi",
- .queuecommand = virtscsi_queuecommand,
- .this_id = -1,
-+ .eh_abort_handler = virtscsi_abort,
-+ .eh_device_reset_handler = virtscsi_device_reset,
-
- .can_queue = 1024,
- .dma_boundary = UINT_MAX,
---
-1.7.1
-
-
-From 43cf1b6a4ee31e69581042a0c85d1398f83dcedc Mon Sep 17 00:00:00 2001
-From: Paolo Bonzini <pbonzini@redhat.com>
-Date: Fri, 13 Jan 2012 15:30:08 +0100
-Cc: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>, Mike Christie <michaelc@cs.wisc.edu>, Pekka Enberg <penberg@kernel.org>
-Subject: [PATCH v5 3/3] virtio-scsi: add power management support
-
-This patch adds freeze/restore handlers for the HBA. Block queues
-are managed independently by the disk devices.
-
-Cc: linux-scsi <linux-scsi@vger.kernel.org>
-Cc: Rusty Russell <rusty@rustcorp.com.au>
-Cc: Michael S. Tsirkin <mst@redhat.com>
-Cc: kvm@vger.kernel.org
-Acked-by: Pekka Enberg <penberg@kernel.org>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- The feature has been merged in the virtio core for 3.3, so the patch
- is new in v4.
-
- drivers/scsi/virtio_scsi.c | 26 +++++++++++++++++++++++---
- 1 files changed, 23 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
-index 68104cd..efccd72 100644
---- a/drivers/scsi/virtio_scsi.c
-+++ b/drivers/scsi/virtio_scsi.c
-@@ -406,8 +406,8 @@ static struct scsi_host_template virtscsi_host_template = {
- &__val, sizeof(__val)); \
- })
-
--static int __devinit virtscsi_init(struct virtio_device *vdev,
-- struct virtio_scsi *vscsi)
-+static int virtscsi_init(struct virtio_device *vdev,
-+ struct virtio_scsi *vscsi)
- {
- int err;
- struct virtqueue *vqs[3];
-@@ -491,7 +491,7 @@ virtscsi_init_failed:
- return err;
- }
-
--static void __devexit virtscsi_remove_vqs(struct virtio_device *vdev)
-+static void virtscsi_remove_vqs(struct virtio_device *vdev)
- {
- /* Stop all the virtqueues. */
- vdev->config->reset(vdev);
-@@ -509,6 +509,22 @@ static void __devexit virtscsi_remove(struct virtio_device *vdev)
- scsi_host_put(shost);
- }
-
-+#ifdef CONFIG_PM
-+static int virtscsi_freeze(struct virtio_device *vdev)
-+{
-+ virtscsi_remove_vqs(vdev);
-+ return 0;
-+}
-+
-+static int virtscsi_restore(struct virtio_device *vdev)
-+{
-+ struct Scsi_Host *sh = virtio_scsi_host(vdev);
-+ struct virtio_scsi *vscsi = shost_priv(sh);
-+
-+ return virtscsi_init(vdev, vscsi);
-+}
-+#endif
-+
- static struct virtio_device_id id_table[] = {
- { VIRTIO_ID_SCSI, VIRTIO_DEV_ANY_ID },
- { 0 },
-@@ -519,6 +535,10 @@ static struct virtio_driver virtio_scsi_driver = {
- .driver.owner = THIS_MODULE,
- .id_table = id_table,
- .probe = virtscsi_probe,
-+#ifdef CONFIG_PM
-+ .freeze = virtscsi_freeze,
-+ .restore = virtscsi_restore,
-+#endif
- .remove = __devexit_p(virtscsi_remove),
- };
-
---
-1.7.1
-