[kernel] r19794 - in dists/sid/linux/debian: . config patches patches/features/all/virtio_scsi
Ben Hutchings
benh at alioth.debian.org
Thu Feb 7 04:42:41 UTC 2013
Author: benh
Date: Thu Feb 7 04:42:39 2013
New Revision: 19794
Log:
SCSI: Add virtio_scsi driver (Closes: #686636)
Added:
dists/sid/linux/debian/patches/features/all/virtio_scsi/
dists/sid/linux/debian/patches/features/all/virtio_scsi/0001-SCSI-virtio-scsi-SCSI-driver-for-QEMU-based-virtual-.patch
dists/sid/linux/debian/patches/features/all/virtio_scsi/0002-SCSI-virtio_scsi-fix-TMF-use-after-free.patch
dists/sid/linux/debian/patches/features/all/virtio_scsi/0003-SCSI-virtio-scsi-unlock-during-kick.patch
dists/sid/linux/debian/patches/features/all/virtio_scsi/0004-SCSI-virtio-scsi-split-locking-per-vq.patch
dists/sid/linux/debian/patches/features/all/virtio_scsi/0005-SCSI-virtio-scsi-release-sg_lock-after-add_buf.patch
dists/sid/linux/debian/patches/features/all/virtio_scsi/0006-SCSI-virtio-scsi-split-scatterlist-per-target.patch
dists/sid/linux/debian/patches/features/all/virtio_scsi/0007-SCSI-virtio-scsi-hotplug-support-for-virtio-scsi.patch
dists/sid/linux/debian/patches/features/all/virtio_scsi/0008-SCSI-virtio-scsi-Add-vdrv-scan-for-post-VIRTIO_CONFI.patch
dists/sid/linux/debian/patches/features/all/virtio_scsi/0009-SCSI-scsi-virtio-scsi-Fix-address-translation-failur.patch
dists/sid/linux/debian/patches/features/all/virtio_scsi/0010-SCSI-virtio-scsi-initialize-scatterlist-structure.patch
dists/sid/linux/debian/patches/features/all/virtio_scsi/0011-SCSI-virtio-scsi-fix-LUNs-greater-than-255.patch
dists/sid/linux/debian/patches/features/all/virtio_scsi/0012-SCSI-virtio-scsi-support-online-resizing-of-disks.patch
dists/sid/linux/debian/patches/features/all/virtio_scsi/virtio-support-unlocked-queue-kick.patch
Modified:
dists/sid/linux/debian/changelog
dists/sid/linux/debian/config/config
dists/sid/linux/debian/config/defines
dists/sid/linux/debian/patches/series
Modified: dists/sid/linux/debian/changelog
==============================================================================
--- dists/sid/linux/debian/changelog Thu Feb 7 04:09:44 2013 (r19793)
+++ dists/sid/linux/debian/changelog Thu Feb 7 04:42:39 2013 (r19794)
@@ -127,6 +127,7 @@
- Also allow this behaviour to be enabled via module parameter
invert_brightness=1
* [amd64] edac: Enable EDAC_SBRIDGE as module (Closes: #699283)
+ * SCSI: Add virtio_scsi driver (Closes: #686636)
[ Aurelien Jarno ]
* [armhf/vexpress] Add kernel udebs.
Modified: dists/sid/linux/debian/config/config
==============================================================================
--- dists/sid/linux/debian/config/config Thu Feb 7 04:09:44 2013 (r19793)
+++ dists/sid/linux/debian/config/config Thu Feb 7 04:42:39 2013 (r19794)
@@ -2626,6 +2626,7 @@
CONFIG_SCSI_PM8001=m
CONFIG_SCSI_SRP=m
CONFIG_SCSI_BFA_FC=m
+CONFIG_SCSI_VIRTIO=m
##
## file: drivers/scsi/aic7xxx/Kconfig.aic79xx
Modified: dists/sid/linux/debian/config/defines
==============================================================================
--- dists/sid/linux/debian/config/defines Thu Feb 7 04:09:44 2013 (r19793)
+++ dists/sid/linux/debian/config/defines Thu Feb 7 04:42:39 2013 (r19794)
@@ -30,6 +30,8 @@
# wanrouter was totally broken
module:drivers/net/wan/cycx_drv
module:net/wanrouter/wanrouter
+# No-one tries to use virtio from OOT
+ module:drivers/virtio/*
[base]
arches:
Added: dists/sid/linux/debian/patches/features/all/virtio_scsi/0001-SCSI-virtio-scsi-SCSI-driver-for-QEMU-based-virtual-.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/virtio_scsi/0001-SCSI-virtio-scsi-SCSI-driver-for-QEMU-based-virtual-.patch Thu Feb 7 04:42:39 2013 (r19794)
@@ -0,0 +1,782 @@
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Sun, 5 Feb 2012 12:16:00 +0100
+Subject: [01/12] [SCSI] virtio-scsi: SCSI driver for QEMU based virtual
+ machines
+
+commit 4fe74b1cb051dc9d47a80e263c388cf1651783d4 upstream.
+
+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).
+
+Acked-by: Rusty Russell <rusty at rustcorp.com.au>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: James Bottomley <JBottomley at Parallels.com>
+[bwh: Backported to 3.2:
+ - s/virtqueue_add_buf/&_gfp/
+ - Remove virtio driver PM operations]
+---
+ 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(+)
+ create mode 100644 drivers/scsi/virtio_scsi.c
+ create mode 100644 include/linux/virtio_scsi.h
+
+--- a/drivers/scsi/Kconfig
++++ b/drivers/scsi/Kconfig
+@@ -1910,6 +1910,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"
+--- a/drivers/scsi/Makefile
++++ b/drivers/scsi/Makefile
+@@ -141,6 +141,7 @@ obj-$(CONFIG_SCSI_CXGB4_ISCSI) += libisc
+ 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
+
+--- /dev/null
++++ b/drivers/scsi/virtio_scsi.c
+@@ -0,0 +1,594 @@
++/*
++ * Virtio SCSI HBA driver
++ *
++ * Copyright IBM Corp. 2010
++ * Copyright Red Hat, Inc. 2011
++ *
++ * Authors:
++ * Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
++ * Paolo Bonzini <pbonzini at 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;
++ struct completion *comp;
++ 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);
++};
++
++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);
++}
++
++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_gfp(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 int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
++{
++ DECLARE_COMPLETION_ONSTACK(comp);
++ int ret;
++
++ cmd->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,
++ .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 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 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);
++}
++
++#if 0
++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 },
++};
++
++static struct virtio_driver virtio_scsi_driver = {
++ .driver.name = KBUILD_MODNAME,
++ .driver.owner = THIS_MODULE,
++ .id_table = id_table,
++ .probe = virtscsi_probe,
++#if 0
++ .freeze = virtscsi_freeze,
++ .restore = virtscsi_restore,
++#endif
++ .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");
+--- 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 */
+--- /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 */
Added: dists/sid/linux/debian/patches/features/all/virtio_scsi/0002-SCSI-virtio_scsi-fix-TMF-use-after-free.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/virtio_scsi/0002-SCSI-virtio_scsi-fix-TMF-use-after-free.patch Thu Feb 7 04:42:39 2013 (r19794)
@@ -0,0 +1,68 @@
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 4 May 2012 12:32:04 +0200
+Subject: [02/12] [SCSI] virtio_scsi: fix TMF use-after-free
+
+commit e4594bb50518eb89c447be97dabd5bd99f405d71 upstream.
+
+Fix a use-after-free in the TMF path, where cmd may have been already
+freed by virtscsi_complete_free when wait_for_completion restarts
+executing virtscsi_tmf. Technically a race, but in practice the command
+will always be freed long before the completion waiter is awoken.
+
+The fix is to make callers specifying a completion responsible for
+freeing the command in all cases.
+
+Signed-off-by: Hu Tao <hutao at cn.fujitsu.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: James Bottomley <JBottomley at Parallels.com>
+---
+ drivers/scsi/virtio_scsi.c | 24 +++++++++++++-----------
+ 1 file changed, 13 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
+index efccd72..1b38431 100644
+--- a/drivers/scsi/virtio_scsi.c
++++ b/drivers/scsi/virtio_scsi.c
+@@ -175,7 +175,8 @@ static void virtscsi_complete_free(void *buf)
+
+ if (cmd->comp)
+ complete_all(cmd->comp);
+- mempool_free(cmd, virtscsi_cmd_pool);
++ else
++ mempool_free(cmd, virtscsi_cmd_pool);
+ }
+
+ static void virtscsi_ctrl_done(struct virtqueue *vq)
+@@ -311,21 +312,22 @@ out:
+ static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
+ {
+ DECLARE_COMPLETION_ONSTACK(comp);
+- int ret;
++ int ret = FAILED;
+
+ cmd->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;
++ if (virtscsi_kick_cmd(vscsi, vscsi->ctrl_vq, cmd,
++ sizeof cmd->req.tmf, sizeof cmd->resp.tmf,
++ GFP_NOIO) < 0)
++ goto out;
+
+ wait_for_completion(&comp);
+- if (cmd->resp.tmf.response != VIRTIO_SCSI_S_OK &&
+- cmd->resp.tmf.response != VIRTIO_SCSI_S_FUNCTION_SUCCEEDED)
+- return FAILED;
++ if (cmd->resp.tmf.response == VIRTIO_SCSI_S_OK ||
++ cmd->resp.tmf.response == VIRTIO_SCSI_S_FUNCTION_SUCCEEDED)
++ ret = SUCCESS;
+
+- return SUCCESS;
++out:
++ mempool_free(cmd, virtscsi_cmd_pool);
++ return ret;
+ }
+
+ static int virtscsi_device_reset(struct scsi_cmnd *sc)
Added: dists/sid/linux/debian/patches/features/all/virtio_scsi/0003-SCSI-virtio-scsi-unlock-during-kick.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/virtio_scsi/0003-SCSI-virtio-scsi-unlock-during-kick.patch Thu Feb 7 04:42:39 2013 (r19794)
@@ -0,0 +1,30 @@
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Wed, 13 Jun 2012 16:56:31 +0200
+Subject: [03/12] [SCSI] virtio-scsi: unlock during kick
+
+commit b5ee8f2802c559fccb177c0a117f5cd56c1049cc upstream.
+
+Separate virtqueue_kick_prepare from virtqueue_notify, so that the
+expensive vmexit is done without holding the lock.
+
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: James Bottomley <JBottomley at Parallels.com>
+---
+ drivers/scsi/virtio_scsi.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/scsi/virtio_scsi.c
++++ b/drivers/scsi/virtio_scsi.c
+@@ -264,9 +264,11 @@ static int virtscsi_kick_cmd(struct virt
+
+ ret = virtqueue_add_buf_gfp(vq, vscsi->sg, out_num, in_num, cmd, gfp);
+ if (ret >= 0)
+- virtqueue_kick(vq);
++ ret = virtqueue_kick_prepare(vq);
+
+ spin_unlock_irqrestore(&vscsi->vq_lock, flags);
++ if (ret > 0)
++ virtqueue_notify(vq);
+ return ret;
+ }
+
Added: dists/sid/linux/debian/patches/features/all/virtio_scsi/0004-SCSI-virtio-scsi-split-locking-per-vq.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/virtio_scsi/0004-SCSI-virtio-scsi-split-locking-per-vq.patch Thu Feb 7 04:42:39 2013 (r19794)
@@ -0,0 +1,195 @@
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Wed, 13 Jun 2012 16:56:32 +0200
+Subject: [04/12] [SCSI] virtio-scsi: split locking per vq
+
+commit 139fe45abc2234b20fd5ecbcb7ea6d3688fed5e5 upstream.
+
+Keep a separate lock for each virtqueue. While not particularly
+important now, it prepares the code for when we will add support
+for multiple request queues. It is also more tidy as soon as
+we introduce a separate lock for the sglist.
+
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: James Bottomley <JBottomley at Parallels.com>
+[bwh: Backported to 3.2: s/virtqueue_add_buf/&_gfp/]
+---
+ drivers/scsi/virtio_scsi.c | 77 ++++++++++++++++++++++++++++++--------------
+ 1 file changed, 52 insertions(+), 25 deletions(-)
+
+--- a/drivers/scsi/virtio_scsi.c
++++ b/drivers/scsi/virtio_scsi.c
+@@ -43,15 +43,22 @@ struct virtio_scsi_cmd {
+ } resp;
+ } ____cacheline_aligned_in_smp;
+
++struct virtio_scsi_vq {
++ /* Protects vq */
++ spinlock_t vq_lock;
++
++ struct virtqueue *vq;
++};
++
+ /* Driver instance state */
+ struct virtio_scsi {
+- /* Protects ctrl_vq, req_vq and sg[] */
+- spinlock_t vq_lock;
++ /* Protects sg[]. The lock hierarchy is sg_lock -> vq_lock. */
++ spinlock_t sg_lock;
+
+ struct virtio_device *vdev;
+- struct virtqueue *ctrl_vq;
+- struct virtqueue *event_vq;
+- struct virtqueue *req_vq;
++ struct virtio_scsi_vq ctrl_vq;
++ struct virtio_scsi_vq event_vq;
++ struct virtio_scsi_vq req_vq;
+
+ /* For sglist construction when adding commands to the virtqueue. */
+ struct scatterlist sg[];
+@@ -147,26 +154,25 @@ static void virtscsi_complete_cmd(void *
+
+ 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)
+ {
++ struct Scsi_Host *sh = virtio_scsi_host(vq->vdev);
++ struct virtio_scsi *vscsi = shost_priv(sh);
++ unsigned long flags;
++
++ spin_lock_irqsave(&vscsi->req_vq.vq_lock, flags);
+ virtscsi_vq_done(vq, virtscsi_complete_cmd);
++ spin_unlock_irqrestore(&vscsi->req_vq.vq_lock, flags);
+ };
+
+ static void virtscsi_complete_free(void *buf)
+@@ -181,12 +187,24 @@ static void virtscsi_complete_free(void
+
+ static void virtscsi_ctrl_done(struct virtqueue *vq)
+ {
++ struct Scsi_Host *sh = virtio_scsi_host(vq->vdev);
++ struct virtio_scsi *vscsi = shost_priv(sh);
++ unsigned long flags;
++
++ spin_lock_irqsave(&vscsi->ctrl_vq.vq_lock, flags);
+ virtscsi_vq_done(vq, virtscsi_complete_free);
++ spin_unlock_irqrestore(&vscsi->ctrl_vq.vq_lock, flags);
+ };
+
+ static void virtscsi_event_done(struct virtqueue *vq)
+ {
++ struct Scsi_Host *sh = virtio_scsi_host(vq->vdev);
++ struct virtio_scsi *vscsi = shost_priv(sh);
++ unsigned long flags;
++
++ spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags);
+ virtscsi_vq_done(vq, virtscsi_complete_free);
++ spin_unlock_irqrestore(&vscsi->event_vq.vq_lock, flags);
+ };
+
+ static void virtscsi_map_sgl(struct scatterlist *sg, unsigned int *p_idx,
+@@ -250,7 +268,7 @@ static void virtscsi_map_cmd(struct virt
+ *in_num = idx - *out_num;
+ }
+
+-static int virtscsi_kick_cmd(struct virtio_scsi *vscsi, struct virtqueue *vq,
++static int virtscsi_kick_cmd(struct virtio_scsi *vscsi, struct virtio_scsi_vq *vq,
+ struct virtio_scsi_cmd *cmd,
+ size_t req_size, size_t resp_size, gfp_t gfp)
+ {
+@@ -258,17 +276,19 @@ static int virtscsi_kick_cmd(struct virt
+ unsigned long flags;
+ int ret;
+
+- spin_lock_irqsave(&vscsi->vq_lock, flags);
+-
++ spin_lock_irqsave(&vscsi->sg_lock, flags);
+ virtscsi_map_cmd(vscsi, cmd, &out_num, &in_num, req_size, resp_size);
+
+- ret = virtqueue_add_buf_gfp(vq, vscsi->sg, out_num, in_num, cmd, gfp);
++ spin_lock(&vq->vq_lock);
++ ret = virtqueue_add_buf_gfp(vq->vq, vscsi->sg, out_num, in_num, cmd, gfp);
+ if (ret >= 0)
+- ret = virtqueue_kick_prepare(vq);
++ ret = virtqueue_kick_prepare(vq->vq);
++
++ spin_unlock(&vq->vq_lock);
++ spin_unlock_irqrestore(&vscsi->sg_lock, flags);
+
+- spin_unlock_irqrestore(&vscsi->vq_lock, flags);
+ if (ret > 0)
+- virtqueue_notify(vq);
++ virtqueue_notify(vq->vq);
+ return ret;
+ }
+
+@@ -302,7 +322,7 @@ static int virtscsi_queuecommand(struct
+ 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,
++ if (virtscsi_kick_cmd(vscsi, &vscsi->req_vq, cmd,
+ sizeof cmd->req.cmd, sizeof cmd->resp.cmd,
+ GFP_ATOMIC) >= 0)
+ ret = 0;
+@@ -317,7 +337,7 @@ static int virtscsi_tmf(struct virtio_sc
+ int ret = FAILED;
+
+ cmd->comp = ∁
+- if (virtscsi_kick_cmd(vscsi, vscsi->ctrl_vq, cmd,
++ if (virtscsi_kick_cmd(vscsi, &vscsi->ctrl_vq, cmd,
+ sizeof cmd->req.tmf, sizeof cmd->resp.tmf,
+ GFP_NOIO) < 0)
+ goto out;
+@@ -410,6 +430,13 @@ static struct scsi_host_template virtscs
+ &__val, sizeof(__val)); \
+ })
+
++static void virtscsi_init_vq(struct virtio_scsi_vq *virtscsi_vq,
++ struct virtqueue *vq)
++{
++ spin_lock_init(&virtscsi_vq->vq_lock);
++ virtscsi_vq->vq = vq;
++}
++
+ static int virtscsi_init(struct virtio_device *vdev,
+ struct virtio_scsi *vscsi)
+ {
+@@ -431,9 +458,9 @@ static int virtscsi_init(struct virtio_d
+ if (err)
+ return err;
+
+- vscsi->ctrl_vq = vqs[0];
+- vscsi->event_vq = vqs[1];
+- vscsi->req_vq = vqs[2];
++ virtscsi_init_vq(&vscsi->ctrl_vq, vqs[0]);
++ virtscsi_init_vq(&vscsi->event_vq, vqs[1]);
++ virtscsi_init_vq(&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);
+@@ -466,7 +493,7 @@ static int __devinit virtscsi_probe(stru
+ vdev->priv = shost;
+
+ /* Random initializations. */
+- spin_lock_init(&vscsi->vq_lock);
++ spin_lock_init(&vscsi->sg_lock);
+ sg_init_table(vscsi->sg, sg_elems + 2);
+
+ err = virtscsi_init(vdev, vscsi);
Added: dists/sid/linux/debian/patches/features/all/virtio_scsi/0005-SCSI-virtio-scsi-release-sg_lock-after-add_buf.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/virtio_scsi/0005-SCSI-virtio-scsi-release-sg_lock-after-add_buf.patch Thu Feb 7 04:42:39 2013 (r19794)
@@ -0,0 +1,49 @@
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Wed, 13 Jun 2012 16:56:33 +0200
+Subject: [05/12] [SCSI] virtio-scsi: release sg_lock after add_buf
+
+commit bce750b1633927be3eecf821f4d17975c3ba5b6a upstream.
+
+We do not need the sglist after calling virtqueue_add_buf. Hence we
+can "pipeline" the locked operations and start preparing the sglist
+for the next request while we kick the virtqueue.
+
+Together with the previous two patches, this improves performance as
+follows. For a simple "if=/dev/sda of=/dev/null bs=128M iflag=direct"
+(the source being a 10G disk, residing entirely in the host buffer cache),
+the additional locking does not cause any penalty with only one dd
+process, but 2 simultaneous I/O operations improve their times by 3%:
+
+ number of simultaneous dd
+ 1 2
+ ----------------------------------------
+ current 5.9958s 10.2640s
+ patched 5.9531s 9.8663s
+
+(Times are best of 10).
+
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: James Bottomley <JBottomley at Parallels.com>
+[bwh: Backported to 3.2: adjust context]
+---
+ drivers/scsi/virtio_scsi.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
+index 0ecf95e..facfc90 100644
+--- a/drivers/scsi/virtio_scsi.c
++++ b/drivers/scsi/virtio_scsi.c
+@@ -281,11 +281,11 @@ static int virtscsi_kick_cmd(struct virtio_scsi *vscsi, struct virtio_scsi_vq *v
+
+ spin_lock(&vq->vq_lock);
+ ret = virtqueue_add_buf_gfp(vq->vq, vscsi->sg, out_num, in_num, cmd, gfp);
++ spin_unlock(&vscsi->sg_lock);
+ if (ret >= 0)
+ ret = virtqueue_kick_prepare(vq->vq);
+
+- spin_unlock(&vq->vq_lock);
+- spin_unlock_irqrestore(&vscsi->sg_lock, flags);
++ spin_unlock_irqrestore(&vq->vq_lock, flags);
+
+ if (ret > 0)
+ virtqueue_notify(vq->vq);
Added: dists/sid/linux/debian/patches/features/all/virtio_scsi/0006-SCSI-virtio-scsi-split-scatterlist-per-target.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/virtio_scsi/0006-SCSI-virtio-scsi-split-scatterlist-per-target.patch Thu Feb 7 04:42:39 2013 (r19794)
@@ -0,0 +1,290 @@
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Wed, 13 Jun 2012 16:56:34 +0200
+Subject: [06/12] [SCSI] virtio-scsi: split scatterlist per target
+
+commit 2bd37f0fde99cbf8b78fb55f1128e8c3a63cf1da upstream.
+
+To improve performance for I/O to different targets, add a separate
+scatterlist for each of them.
+
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: James Bottomley <JBottomley at Parallels.com>
+[bwh: Backported to 3.2: s/virtqueue_add_buf/&_gfp/]
+---
+ drivers/scsi/virtio_scsi.c | 141 +++++++++++++++++++++++++++++---------------
+ 1 file changed, 94 insertions(+), 47 deletions(-)
+
+--- a/drivers/scsi/virtio_scsi.c
++++ b/drivers/scsi/virtio_scsi.c
+@@ -50,18 +50,24 @@ struct virtio_scsi_vq {
+ struct virtqueue *vq;
+ };
+
++/* Per-target queue state */
++struct virtio_scsi_target_state {
++ /* Protects sg. Lock hierarchy is tgt_lock -> vq_lock. */
++ spinlock_t tgt_lock;
++
++ /* For sglist construction when adding commands to the virtqueue. */
++ struct scatterlist sg[];
++};
++
+ /* Driver instance state */
+ struct virtio_scsi {
+- /* Protects sg[]. The lock hierarchy is sg_lock -> vq_lock. */
+- spinlock_t sg_lock;
+-
+ struct virtio_device *vdev;
++
+ struct virtio_scsi_vq ctrl_vq;
+ struct virtio_scsi_vq event_vq;
+ struct virtio_scsi_vq req_vq;
+
+- /* For sglist construction when adding commands to the virtqueue. */
+- struct scatterlist sg[];
++ struct virtio_scsi_target_state *tgt[];
+ };
+
+ static struct kmem_cache *virtscsi_cmd_cache;
+@@ -230,25 +236,17 @@ static void virtscsi_map_sgl(struct scat
+ * @req_size : size of the request buffer
+ * @resp_size : size of the response buffer
+ *
+- * Called with vq_lock held.
++ * Called with tgt_lock held.
+ */
+-static void virtscsi_map_cmd(struct virtio_scsi *vscsi,
++static void virtscsi_map_cmd(struct virtio_scsi_target_state *tgt,
+ 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;
++ struct scatterlist *sg = tgt->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);
+
+@@ -268,7 +266,8 @@ static void virtscsi_map_cmd(struct virt
+ *in_num = idx - *out_num;
+ }
+
+-static int virtscsi_kick_cmd(struct virtio_scsi *vscsi, struct virtio_scsi_vq *vq,
++static int virtscsi_kick_cmd(struct virtio_scsi_target_state *tgt,
++ struct virtio_scsi_vq *vq,
+ struct virtio_scsi_cmd *cmd,
+ size_t req_size, size_t resp_size, gfp_t gfp)
+ {
+@@ -276,12 +275,12 @@ static int virtscsi_kick_cmd(struct virt
+ unsigned long flags;
+ int ret;
+
+- spin_lock_irqsave(&vscsi->sg_lock, flags);
+- virtscsi_map_cmd(vscsi, cmd, &out_num, &in_num, req_size, resp_size);
++ spin_lock_irqsave(&tgt->tgt_lock, flags);
++ virtscsi_map_cmd(tgt, cmd, &out_num, &in_num, req_size, resp_size);
+
+ spin_lock(&vq->vq_lock);
+- ret = virtqueue_add_buf_gfp(vq->vq, vscsi->sg, out_num, in_num, cmd, gfp);
+- spin_unlock(&vscsi->sg_lock);
++ ret = virtqueue_add_buf_gfp(vq->vq, tgt->sg, out_num, in_num, cmd, gfp);
++ spin_unlock(&tgt->tgt_lock);
+ if (ret >= 0)
+ ret = virtqueue_kick_prepare(vq->vq);
+
+@@ -295,9 +294,16 @@ static int virtscsi_kick_cmd(struct virt
+ static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
+ {
+ struct virtio_scsi *vscsi = shost_priv(sh);
++ struct virtio_scsi_target_state *tgt = vscsi->tgt[sc->device->id];
+ struct virtio_scsi_cmd *cmd;
+ int ret;
+
++ 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);
++
+ dev_dbg(&sc->device->sdev_gendev,
+ "cmd %p CDB: %#02x\n", sc, sc->cmnd[0]);
+
+@@ -322,7 +328,7 @@ static int virtscsi_queuecommand(struct
+ 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,
++ if (virtscsi_kick_cmd(tgt, &vscsi->req_vq, cmd,
+ sizeof cmd->req.cmd, sizeof cmd->resp.cmd,
+ GFP_ATOMIC) >= 0)
+ ret = 0;
+@@ -334,10 +340,11 @@ out:
+ static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
+ {
+ DECLARE_COMPLETION_ONSTACK(comp);
++ struct virtio_scsi_target_state *tgt = vscsi->tgt[cmd->sc->device->id];
+ int ret = FAILED;
+
+ cmd->comp = ∁
+- if (virtscsi_kick_cmd(vscsi, &vscsi->ctrl_vq, cmd,
++ if (virtscsi_kick_cmd(tgt, &vscsi->ctrl_vq, cmd,
+ sizeof cmd->req.tmf, sizeof cmd->resp.tmf,
+ GFP_NOIO) < 0)
+ goto out;
+@@ -437,11 +444,49 @@ static void virtscsi_init_vq(struct virt
+ virtscsi_vq->vq = vq;
+ }
+
++static struct virtio_scsi_target_state *virtscsi_alloc_tgt(
++ struct virtio_device *vdev, int sg_elems)
++{
++ struct virtio_scsi_target_state *tgt;
++ gfp_t gfp_mask = GFP_KERNEL;
++
++ /* We need extra sg elements at head and tail. */
++ tgt = kmalloc(sizeof(*tgt) + sizeof(tgt->sg[0]) * (sg_elems + 2),
++ gfp_mask);
++
++ if (!tgt)
++ return NULL;
++
++ spin_lock_init(&tgt->tgt_lock);
++ sg_init_table(tgt->sg, sg_elems + 2);
++ return tgt;
++}
++
++static void virtscsi_remove_vqs(struct virtio_device *vdev)
++{
++ struct Scsi_Host *sh = virtio_scsi_host(vdev);
++ struct virtio_scsi *vscsi = shost_priv(sh);
++ u32 i, num_targets;
++
++ /* Stop all the virtqueues. */
++ vdev->config->reset(vdev);
++
++ num_targets = sh->max_id;
++ for (i = 0; i < num_targets; i++) {
++ kfree(vscsi->tgt[i]);
++ vscsi->tgt[i] = NULL;
++ }
++
++ vdev->config->del_vqs(vdev);
++}
++
+ static int virtscsi_init(struct virtio_device *vdev,
+- struct virtio_scsi *vscsi)
++ struct virtio_scsi *vscsi, int num_targets)
+ {
+ int err;
+ struct virtqueue *vqs[3];
++ u32 i, sg_elems;
++
+ vq_callback_t *callbacks[] = {
+ virtscsi_ctrl_done,
+ virtscsi_event_done,
+@@ -464,7 +509,23 @@ static int virtscsi_init(struct virtio_d
+
+ virtscsi_config_set(vdev, cdb_size, VIRTIO_SCSI_CDB_SIZE);
+ virtscsi_config_set(vdev, sense_size, VIRTIO_SCSI_SENSE_SIZE);
+- return 0;
++
++ /* We need to know how many segments before we allocate. */
++ sg_elems = virtscsi_config_get(vdev, seg_max) ?: 1;
++
++ for (i = 0; i < num_targets; i++) {
++ vscsi->tgt[i] = virtscsi_alloc_tgt(vdev, sg_elems);
++ if (!vscsi->tgt[i]) {
++ err = -ENOMEM;
++ goto out;
++ }
++ }
++ err = 0;
++
++out:
++ if (err)
++ virtscsi_remove_vqs(vdev);
++ return err;
+ }
+
+ static int __devinit virtscsi_probe(struct virtio_device *vdev)
+@@ -472,31 +533,25 @@ static int __devinit virtscsi_probe(stru
+ struct Scsi_Host *shost;
+ struct virtio_scsi *vscsi;
+ int err;
+- u32 sg_elems;
++ u32 sg_elems, num_targets;
+ 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. */
++ num_targets = virtscsi_config_get(vdev, max_target) + 1;
+ shost = scsi_host_alloc(&virtscsi_host_template,
+- sizeof(*vscsi) + sizeof(vscsi->sg[0]) * (sg_elems + 2));
++ sizeof(*vscsi)
++ + num_targets * sizeof(struct virtio_scsi_target_state));
+
+ if (!shost)
+ return -ENOMEM;
+
++ sg_elems = virtscsi_config_get(vdev, seg_max) ?: 1;
+ shost->sg_tablesize = sg_elems;
+ vscsi = shost_priv(shost);
+ vscsi->vdev = vdev;
+ vdev->priv = shost;
+
+- /* Random initializations. */
+- spin_lock_init(&vscsi->sg_lock);
+- sg_init_table(vscsi->sg, sg_elems + 2);
+-
+- err = virtscsi_init(vdev, vscsi);
++ err = virtscsi_init(vdev, vscsi, num_targets);
+ if (err)
+ goto virtscsi_init_failed;
+
+@@ -504,7 +559,7 @@ static int __devinit virtscsi_probe(stru
+ 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_id = num_targets;
+ shost->max_channel = 0;
+ shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE;
+ err = scsi_add_host(shost, &vdev->dev);
+@@ -522,14 +577,6 @@ virtscsi_init_failed:
+ return err;
+ }
+
+-static void 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);
+@@ -552,7 +599,7 @@ static int virtscsi_restore(struct virti
+ struct Scsi_Host *sh = virtio_scsi_host(vdev);
+ struct virtio_scsi *vscsi = shost_priv(sh);
+
+- return virtscsi_init(vdev, vscsi);
++ return virtscsi_init(vdev, vscsi, sh->max_id);
+ }
+ #endif
+
Added: dists/sid/linux/debian/patches/features/all/virtio_scsi/0007-SCSI-virtio-scsi-hotplug-support-for-virtio-scsi.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/virtio_scsi/0007-SCSI-virtio-scsi-hotplug-support-for-virtio-scsi.patch Thu Feb 7 04:42:39 2013 (r19794)
@@ -0,0 +1,229 @@
+From: Cong Meng <mc at linux.vnet.ibm.com>
+Date: Thu, 5 Jul 2012 17:06:43 +0800
+Subject: [07/12] [SCSI] virtio-scsi: hotplug support for virtio-scsi
+
+commit 365a7150094114a0f8ef0b6164e6b04b519039e8 upstream.
+
+This patch implements the hotplug support for virtio-scsi.
+When there is a device attached/detached, the virtio-scsi driver will be
+signaled via event virtual queue and it will add/remove the scsi device
+in question automatically.
+
+Signed-off-by: Sen Wang <senwang at linux.vnet.ibm.com>
+Signed-off-by: Cong Meng <mc at linux.vnet.ibm.com>
+Acked-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: James Bottomley <JBottomley at Parallels.com>
+[bwh: Backported to 3.2: s/virtqueue_add_buf/&_gfp/]
+---
+ drivers/scsi/virtio_scsi.c | 124 ++++++++++++++++++++++++++++++++++++++++++-
+ include/linux/virtio_scsi.h | 9 ++++
+ 2 files changed, 132 insertions(+), 1 deletion(-)
+
+--- a/drivers/scsi/virtio_scsi.c
++++ b/drivers/scsi/virtio_scsi.c
+@@ -25,6 +25,7 @@
+ #include <scsi/scsi_cmnd.h>
+
+ #define VIRTIO_SCSI_MEMPOOL_SZ 64
++#define VIRTIO_SCSI_EVENT_LEN 8
+
+ /* Command queue element */
+ struct virtio_scsi_cmd {
+@@ -43,6 +44,12 @@ struct virtio_scsi_cmd {
+ } resp;
+ } ____cacheline_aligned_in_smp;
+
++struct virtio_scsi_event_node {
++ struct virtio_scsi *vscsi;
++ struct virtio_scsi_event event;
++ struct work_struct work;
++};
++
+ struct virtio_scsi_vq {
+ /* Protects vq */
+ spinlock_t vq_lock;
+@@ -67,6 +74,9 @@ struct virtio_scsi {
+ struct virtio_scsi_vq event_vq;
+ struct virtio_scsi_vq req_vq;
+
++ /* Get some buffers ready for event vq */
++ struct virtio_scsi_event_node event_list[VIRTIO_SCSI_EVENT_LEN];
++
+ struct virtio_scsi_target_state *tgt[];
+ };
+
+@@ -202,6 +212,105 @@ static void virtscsi_ctrl_done(struct vi
+ spin_unlock_irqrestore(&vscsi->ctrl_vq.vq_lock, flags);
+ };
+
++static int virtscsi_kick_event(struct virtio_scsi *vscsi,
++ struct virtio_scsi_event_node *event_node)
++{
++ int ret;
++ struct scatterlist sg;
++ unsigned long flags;
++
++ sg_set_buf(&sg, &event_node->event, sizeof(struct virtio_scsi_event));
++
++ spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags);
++
++ ret = virtqueue_add_buf_gfp(vscsi->event_vq.vq, &sg, 0, 1, event_node, GFP_ATOMIC);
++ if (ret >= 0)
++ virtqueue_kick(vscsi->event_vq.vq);
++
++ spin_unlock_irqrestore(&vscsi->event_vq.vq_lock, flags);
++
++ return ret;
++}
++
++static int virtscsi_kick_event_all(struct virtio_scsi *vscsi)
++{
++ int i;
++
++ for (i = 0; i < VIRTIO_SCSI_EVENT_LEN; i++) {
++ vscsi->event_list[i].vscsi = vscsi;
++ virtscsi_kick_event(vscsi, &vscsi->event_list[i]);
++ }
++
++ return 0;
++}
++
++static void virtscsi_cancel_event_work(struct virtio_scsi *vscsi)
++{
++ int i;
++
++ for (i = 0; i < VIRTIO_SCSI_EVENT_LEN; i++)
++ cancel_work_sync(&vscsi->event_list[i].work);
++}
++
++static void virtscsi_handle_transport_reset(struct virtio_scsi *vscsi,
++ struct virtio_scsi_event *event)
++{
++ struct scsi_device *sdev;
++ struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
++ unsigned int target = event->lun[1];
++ unsigned int lun = (event->lun[2] << 8) | event->lun[3];
++
++ switch (event->reason) {
++ case VIRTIO_SCSI_EVT_RESET_RESCAN:
++ scsi_add_device(shost, 0, target, lun);
++ break;
++ case VIRTIO_SCSI_EVT_RESET_REMOVED:
++ sdev = scsi_device_lookup(shost, 0, target, lun);
++ if (sdev) {
++ scsi_remove_device(sdev);
++ scsi_device_put(sdev);
++ } else {
++ pr_err("SCSI device %d 0 %d %d not found\n",
++ shost->host_no, target, lun);
++ }
++ break;
++ default:
++ pr_info("Unsupport virtio scsi event reason %x\n", event->reason);
++ }
++}
++
++static void virtscsi_handle_event(struct work_struct *work)
++{
++ struct virtio_scsi_event_node *event_node =
++ container_of(work, struct virtio_scsi_event_node, work);
++ struct virtio_scsi *vscsi = event_node->vscsi;
++ struct virtio_scsi_event *event = &event_node->event;
++
++ if (event->event & VIRTIO_SCSI_T_EVENTS_MISSED) {
++ event->event &= ~VIRTIO_SCSI_T_EVENTS_MISSED;
++ scsi_scan_host(virtio_scsi_host(vscsi->vdev));
++ }
++
++ switch (event->event) {
++ case VIRTIO_SCSI_T_NO_EVENT:
++ break;
++ case VIRTIO_SCSI_T_TRANSPORT_RESET:
++ virtscsi_handle_transport_reset(vscsi, event);
++ break;
++ default:
++ pr_err("Unsupport virtio scsi event %x\n", event->event);
++ }
++ virtscsi_kick_event(vscsi, event_node);
++}
++
++static void virtscsi_complete_event(void *buf)
++{
++ struct virtio_scsi_event_node *event_node = buf;
++
++ INIT_WORK(&event_node->work, virtscsi_handle_event);
++ schedule_work(&event_node->work);
++}
++
+ static void virtscsi_event_done(struct virtqueue *vq)
+ {
+ struct Scsi_Host *sh = virtio_scsi_host(vq->vdev);
+@@ -209,7 +318,7 @@ static void virtscsi_event_done(struct v
+ unsigned long flags;
+
+ spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags);
+- virtscsi_vq_done(vq, virtscsi_complete_free);
++ virtscsi_vq_done(vq, virtscsi_complete_event);
+ spin_unlock_irqrestore(&vscsi->event_vq.vq_lock, flags);
+ };
+
+@@ -510,6 +619,9 @@ static int virtscsi_init(struct virtio_d
+ virtscsi_config_set(vdev, cdb_size, VIRTIO_SCSI_CDB_SIZE);
+ virtscsi_config_set(vdev, sense_size, VIRTIO_SCSI_SENSE_SIZE);
+
++ if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG))
++ virtscsi_kick_event_all(vscsi);
++
+ /* We need to know how many segments before we allocate. */
+ sg_elems = virtscsi_config_get(vdev, seg_max) ?: 1;
+
+@@ -580,6 +692,10 @@ virtscsi_init_failed:
+ static void __devexit virtscsi_remove(struct virtio_device *vdev)
+ {
+ struct Scsi_Host *shost = virtio_scsi_host(vdev);
++ struct virtio_scsi *vscsi = shost_priv(shost);
++
++ if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG))
++ virtscsi_cancel_event_work(vscsi);
+
+ scsi_remove_host(shost);
+
+@@ -608,7 +724,13 @@ static struct virtio_device_id id_table[
+ { 0 },
+ };
+
++static unsigned int features[] = {
++ VIRTIO_SCSI_F_HOTPLUG
++};
++
+ static struct virtio_driver virtio_scsi_driver = {
++ .feature_table = features,
++ .feature_table_size = ARRAY_SIZE(features),
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+--- a/include/linux/virtio_scsi.h
++++ b/include/linux/virtio_scsi.h
+@@ -69,6 +69,10 @@ struct virtio_scsi_config {
+ u32 max_lun;
+ } __packed;
+
++/* Feature Bits */
++#define VIRTIO_SCSI_F_INOUT 0
++#define VIRTIO_SCSI_F_HOTPLUG 1
++
+ /* Response codes */
+ #define VIRTIO_SCSI_S_OK 0
+ #define VIRTIO_SCSI_S_OVERRUN 1
+@@ -105,6 +109,11 @@ struct virtio_scsi_config {
+ #define VIRTIO_SCSI_T_TRANSPORT_RESET 1
+ #define VIRTIO_SCSI_T_ASYNC_NOTIFY 2
+
++/* Reasons of transport reset event */
++#define VIRTIO_SCSI_EVT_RESET_HARD 0
++#define VIRTIO_SCSI_EVT_RESET_RESCAN 1
++#define VIRTIO_SCSI_EVT_RESET_REMOVED 2
++
+ #define VIRTIO_SCSI_S_SIMPLE 0
+ #define VIRTIO_SCSI_S_ORDERED 1
+ #define VIRTIO_SCSI_S_HEAD 2
Added: dists/sid/linux/debian/patches/features/all/virtio_scsi/0008-SCSI-virtio-scsi-Add-vdrv-scan-for-post-VIRTIO_CONFI.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/virtio_scsi/0008-SCSI-virtio-scsi-Add-vdrv-scan-for-post-VIRTIO_CONFI.patch Thu Feb 7 04:42:39 2013 (r19794)
@@ -0,0 +1,92 @@
+From: Nicholas Bellinger <nab at linux-iscsi.org>
+Date: Wed, 11 Jul 2012 21:22:16 +0000
+Subject: [08/12] [SCSI] virtio-scsi: Add vdrv->scan for post
+ VIRTIO_CONFIG_S_DRIVER_OK LUN scanning
+
+commit 59057fbc37178f10a196ab7ec170b80273f75a47 upstream.
+
+This patch changes virtio-scsi to use a new virtio_driver->scan() callback
+so that scsi_scan_host() can be properly invoked once virtio_dev_probe() has
+set add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK) to signal active virtio-ring
+operation, instead of from within virtscsi_probe().
+
+This fixes a bug where SCSI LUN scanning for both virtio-scsi-raw and
+virtio-scsi/tcm_vhost setups was happening before VIRTIO_CONFIG_S_DRIVER_OK
+had been set, causing VIRTIO_SCSI_S_BAD_TARGET to occur. This fixes a bug
+with virtio-scsi/tcm_vhost where LUN scan was not detecting LUNs.
+
+Tested with virtio-scsi-raw + virtio-scsi/tcm_vhost w/ IBLOCK on 3.5-rc2 code.
+
+Signed-off-by: Nicholas Bellinger <nab at linux-iscsi.org>
+Acked-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: James Bottomley <JBottomley at Parallels.com>
+[bwh: Backported to 3.2: adjust context]
+---
+ drivers/scsi/virtio_scsi.c | 15 ++++++++++++---
+ drivers/virtio/virtio.c | 5 ++++-
+ include/linux/virtio.h | 1 +
+ 3 files changed, 17 insertions(+), 4 deletions(-)
+
+--- a/drivers/scsi/virtio_scsi.c
++++ b/drivers/scsi/virtio_scsi.c
+@@ -571,6 +571,13 @@ static struct virtio_scsi_target_state *
+ return tgt;
+ }
+
++static void virtscsi_scan(struct virtio_device *vdev)
++{
++ struct Scsi_Host *shost = (struct Scsi_Host *)vdev->priv;
++
++ scsi_scan_host(shost);
++}
++
+ static void virtscsi_remove_vqs(struct virtio_device *vdev)
+ {
+ struct Scsi_Host *sh = virtio_scsi_host(vdev);
+@@ -677,9 +684,10 @@ static int __devinit virtscsi_probe(stru
+ err = scsi_add_host(shost, &vdev->dev);
+ if (err)
+ goto scsi_add_host_failed;
+-
+- scsi_scan_host(shost);
+-
++ /*
++ * scsi_scan_host() happens in virtscsi_scan() via virtio_driver->scan()
++ * after VIRTIO_CONFIG_S_DRIVER_OK has been set..
++ */
+ return 0;
+
+ scsi_add_host_failed:
+@@ -735,6 +743,7 @@ static struct virtio_driver virtio_scsi_
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+ .probe = virtscsi_probe,
++ .scan = virtscsi_scan,
+ #if 0
+ .freeze = virtscsi_freeze,
+ .restore = virtscsi_restore,
+--- a/drivers/virtio/virtio.c
++++ b/drivers/virtio/virtio.c
+@@ -140,8 +140,11 @@ static int virtio_dev_probe(struct devic
+ err = drv->probe(dev);
+ if (err)
+ add_status(dev, VIRTIO_CONFIG_S_FAILED);
+- else
++ else {
+ add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
++ if (drv->scan)
++ drv->scan(dev);
++ }
+
+ return err;
+ }
+--- a/include/linux/virtio.h
++++ b/include/linux/virtio.h
+@@ -148,6 +148,7 @@ struct virtio_driver {
+ const unsigned int *feature_table;
+ unsigned int feature_table_size;
+ int (*probe)(struct virtio_device *dev);
++ void (*scan)(struct virtio_device *dev);
+ void (*remove)(struct virtio_device *dev);
+ void (*config_changed)(struct virtio_device *dev);
+ };
Added: dists/sid/linux/debian/patches/features/all/virtio_scsi/0009-SCSI-scsi-virtio-scsi-Fix-address-translation-failur.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/virtio_scsi/0009-SCSI-scsi-virtio-scsi-Fix-address-translation-failur.patch Thu Feb 7 04:42:39 2013 (r19794)
@@ -0,0 +1,54 @@
+From: Wang Sen <senwang at linux.vnet.ibm.com>
+Date: Mon, 30 Jul 2012 14:25:06 +0800
+Subject: [09/12] [SCSI] scsi: virtio-scsi: Fix address translation failure of
+ HighMem pages used by sg list
+
+commit 27e99ade81368e6fdda3212bff9345177cf9e57a upstream.
+
+When using the commands below to write some data to a virtio-scsi LUN of the
+QEMU guest(32-bit) with 1G physical memory(qemu -m 1024), the qemu will crash.
+
+ # sudo mkfs.ext4 /dev/sdb (/dev/sdb is the virtio-scsi LUN.)
+ # sudo mount /dev/sdb /mnt
+ # dd if=/dev/zero of=/mnt/file bs=1M count=1024
+
+In current implementation, sg_set_buf is called to add buffers to sg list which
+is put into the virtqueue eventually. But if there are some HighMem pages in
+table->sgl you can not get virtual address by sg_virt. So, sg_virt(sg_elem) may
+return NULL value. This will cause QEMU exit when virtqueue_map_sg is called
+in QEMU because an invalid GPA is passed by virtqueue.
+
+Two solutions are discussed here:
+http://lkml.indiana.edu/hypermail/linux/kernel/1207.3/00675.html
+
+Finally, value assignment approach was adopted because:
+
+Value assignment creates a well-formed scatterlist, because the termination
+marker in source sg_list has been set in blk_rq_map_sg(). The last entry of the
+source sg_list is just copied to the the last entry in destination list. Note
+that, for now, virtio_ring does not care about the form of the scatterlist and
+simply processes the first out_num + in_num consecutive elements of the sg[]
+array.
+
+I have tested the patch on my workstation. QEMU would not crash any more.
+
+Signed-off-by: Wang Sen <senwang at linux.vnet.ibm.com>
+Acked-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: James Bottomley <JBottomley at Parallels.com>
+---
+ drivers/scsi/virtio_scsi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
+index c7030fb..3e79a2f 100644
+--- a/drivers/scsi/virtio_scsi.c
++++ b/drivers/scsi/virtio_scsi.c
+@@ -331,7 +331,7 @@ static void virtscsi_map_sgl(struct scatterlist *sg, unsigned int *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);
++ sg[idx++] = *sg_elem;
+
+ *p_idx = idx;
+ }
Added: dists/sid/linux/debian/patches/features/all/virtio_scsi/0010-SCSI-virtio-scsi-initialize-scatterlist-structure.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/virtio_scsi/0010-SCSI-virtio-scsi-initialize-scatterlist-structure.patch Thu Feb 7 04:42:39 2013 (r19794)
@@ -0,0 +1,29 @@
+From: "Richard W.M. Jones" <rjones at redhat.com>
+Date: Tue, 2 Oct 2012 17:25:46 +0200
+Subject: [10/12] [SCSI] virtio-scsi: initialize scatterlist structure
+
+commit 2e9c9dfde00a6466441e93033cf2c37f720bdacf upstream.
+
+The sg struct is used without being initialized, which breaks
+when CONFIG_DEBUG_SG is enabled.
+
+Signed-off-by: Richard W.M. Jones <rjones at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: James Bottomley <JBottomley at Parallels.com>
+---
+ drivers/scsi/virtio_scsi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
+index 3e79a2f..7554d78 100644
+--- a/drivers/scsi/virtio_scsi.c
++++ b/drivers/scsi/virtio_scsi.c
+@@ -219,7 +219,7 @@ static int virtscsi_kick_event(struct virtio_scsi *vscsi,
+ struct scatterlist sg;
+ unsigned long flags;
+
+- sg_set_buf(&sg, &event_node->event, sizeof(struct virtio_scsi_event));
++ sg_init_one(&sg, &event_node->event, sizeof(struct virtio_scsi_event));
+
+ spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags);
+
Added: dists/sid/linux/debian/patches/features/all/virtio_scsi/0011-SCSI-virtio-scsi-fix-LUNs-greater-than-255.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/virtio_scsi/0011-SCSI-virtio-scsi-fix-LUNs-greater-than-255.patch Thu Feb 7 04:42:39 2013 (r19794)
@@ -0,0 +1,35 @@
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Tue, 2 Oct 2012 17:25:47 +0200
+Subject: [11/12] [SCSI] virtio-scsi: fix LUNs greater than 255
+
+commit 9da5f5ac6affad8dd8cd80f5cca26e4335e1728b upstream.
+
+virtio-scsi needs to report LUNs greater than 256 using the "flat"
+format. Because the Linux SCSI layer just maps the SCSI LUN to
+an u32, without any parsing, these end up in the range from 16640
+to 32767. Fix max_lun to account for the possibility that logical
+unit numbers are encoded with the "flat" format.
+
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: James Bottomley <JBottomley at Parallels.com>
+---
+ drivers/scsi/virtio_scsi.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
+index 7554d78..a7cf726 100644
+--- a/drivers/scsi/virtio_scsi.c
++++ b/drivers/scsi/virtio_scsi.c
+@@ -677,7 +677,11 @@ static int __devinit virtscsi_probe(struct virtio_device *vdev)
+ 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;
++
++ /* LUNs > 256 are reported with format 1, so they go in the range
++ * 16640-32767.
++ */
++ shost->max_lun = virtscsi_config_get(vdev, max_lun) + 1 + 0x4000;
+ shost->max_id = num_targets;
+ shost->max_channel = 0;
+ shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE;
Added: dists/sid/linux/debian/patches/features/all/virtio_scsi/0012-SCSI-virtio-scsi-support-online-resizing-of-disks.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/virtio_scsi/0012-SCSI-virtio-scsi-support-online-resizing-of-disks.patch Thu Feb 7 04:42:39 2013 (r19794)
@@ -0,0 +1,96 @@
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Tue, 2 Oct 2012 17:25:48 +0200
+Subject: [12/12] [SCSI] virtio-scsi: support online resizing of disks
+
+commit 865b58c05b841964f48f574c2027311bd04db8a1 upstream.
+
+Support the LUN parameter change event. Currently, the host fires this event
+when the capacity of a disk is changed from the virtual machine monitor.
+The resize then appears in the kernel log like this:
+
+ sd 0:0:0:0: [sda] 46137344 512-byte logical blocks: (23.6 GB/22.0 GIb)
+ sda: detected capacity change from 22548578304 to 23622320128
+
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: James Bottomley <JBottomley at Parallels.com>
+---
+ drivers/scsi/virtio_scsi.c | 31 ++++++++++++++++++++++++++++++-
+ include/linux/virtio_scsi.h | 2 ++
+ 2 files changed, 32 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
+index a7cf726..595af1a 100644
+--- a/drivers/scsi/virtio_scsi.c
++++ b/drivers/scsi/virtio_scsi.c
+@@ -279,6 +279,31 @@ static void virtscsi_handle_transport_reset(struct virtio_scsi *vscsi,
+ }
+ }
+
++static void virtscsi_handle_param_change(struct virtio_scsi *vscsi,
++ struct virtio_scsi_event *event)
++{
++ struct scsi_device *sdev;
++ struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
++ unsigned int target = event->lun[1];
++ unsigned int lun = (event->lun[2] << 8) | event->lun[3];
++ u8 asc = event->reason & 255;
++ u8 ascq = event->reason >> 8;
++
++ sdev = scsi_device_lookup(shost, 0, target, lun);
++ if (!sdev) {
++ pr_err("SCSI device %d 0 %d %d not found\n",
++ shost->host_no, target, lun);
++ return;
++ }
++
++ /* Handle "Parameters changed", "Mode parameters changed", and
++ "Capacity data has changed". */
++ if (asc == 0x2a && (ascq == 0x00 || ascq == 0x01 || ascq == 0x09))
++ scsi_rescan_device(&sdev->sdev_gendev);
++
++ scsi_device_put(sdev);
++}
++
+ static void virtscsi_handle_event(struct work_struct *work)
+ {
+ struct virtio_scsi_event_node *event_node =
+@@ -297,6 +322,9 @@ static void virtscsi_handle_event(struct work_struct *work)
+ case VIRTIO_SCSI_T_TRANSPORT_RESET:
+ virtscsi_handle_transport_reset(vscsi, event);
+ break;
++ case VIRTIO_SCSI_T_PARAM_CHANGE:
++ virtscsi_handle_param_change(vscsi, event);
++ break;
+ default:
+ pr_err("Unsupport virtio scsi event %x\n", event->event);
+ }
+@@ -737,7 +765,8 @@ static struct virtio_device_id id_table[] = {
+ };
+
+ static unsigned int features[] = {
+- VIRTIO_SCSI_F_HOTPLUG
++ VIRTIO_SCSI_F_HOTPLUG,
++ VIRTIO_SCSI_F_CHANGE,
+ };
+
+ static struct virtio_driver virtio_scsi_driver = {
+diff --git a/include/linux/virtio_scsi.h b/include/linux/virtio_scsi.h
+index dc8d305..d6b4440 100644
+--- a/include/linux/virtio_scsi.h
++++ b/include/linux/virtio_scsi.h
+@@ -72,6 +72,7 @@ struct virtio_scsi_config {
+ /* Feature Bits */
+ #define VIRTIO_SCSI_F_INOUT 0
+ #define VIRTIO_SCSI_F_HOTPLUG 1
++#define VIRTIO_SCSI_F_CHANGE 2
+
+ /* Response codes */
+ #define VIRTIO_SCSI_S_OK 0
+@@ -108,6 +109,7 @@ struct virtio_scsi_config {
+ #define VIRTIO_SCSI_T_NO_EVENT 0
+ #define VIRTIO_SCSI_T_TRANSPORT_RESET 1
+ #define VIRTIO_SCSI_T_ASYNC_NOTIFY 2
++#define VIRTIO_SCSI_T_PARAM_CHANGE 3
+
+ /* Reasons of transport reset event */
+ #define VIRTIO_SCSI_EVT_RESET_HARD 0
Added: dists/sid/linux/debian/patches/features/all/virtio_scsi/virtio-support-unlocked-queue-kick.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/virtio_scsi/virtio-support-unlocked-queue-kick.patch Thu Feb 7 04:42:39 2013 (r19794)
@@ -0,0 +1,122 @@
+From: Rusty Russell <rusty at rustcorp.com.au>
+Date: Thu, 12 Jan 2012 15:44:43 +1030
+Subject: virtio: support unlocked queue kick
+
+commit 41f0377f73039ca6fe97a469d1941a89cd9757f1 upstream.
+
+Based on patch by Christoph for virtio_blk speedup:
+
+ Split virtqueue_kick to be able to do the actual notification
+ outside the lock protecting the virtqueue. This patch was
+ originally done by Stefan Hajnoczi, but I can't find the
+ original one anymore and had to recreated it from memory.
+ Pointers to the original or corrections for the commit message
+ are welcome.
+
+Stefan's patch was here:
+
+ https://github.com/stefanha/linux/commit/a6d06644e3a58e57a774e77d7dc34c4a5a2e7496
+ http://www.spinics.net/lists/linux-virtualization/msg14616.html
+
+Third time's the charm!
+
+Signed-off-by: Rusty Russell <rusty at rustcorp.com.au>
+[bwh: Backported to 3.2: adjust context]
+---
+ drivers/virtio/virtio_ring.c | 60 +++++++++++++++++++++++++++++++++---------
+ include/linux/virtio.h | 4 +++
+ 2 files changed, 52 insertions(+), 12 deletions(-)
+
+--- a/drivers/virtio/virtio_ring.c
++++ b/drivers/virtio/virtio_ring.c
+@@ -245,10 +245,23 @@ add_head:
+ }
+ EXPORT_SYMBOL_GPL(virtqueue_add_buf_gfp);
+
+-void virtqueue_kick(struct virtqueue *_vq)
++/**
++ * virtqueue_kick_prepare - first half of split virtqueue_kick call.
++ * @vq: the struct virtqueue
++ *
++ * Instead of virtqueue_kick(), you can do:
++ * if (virtqueue_kick_prepare(vq))
++ * virtqueue_notify(vq);
++ *
++ * This is sometimes useful because the virtqueue_kick_prepare() needs
++ * to be serialized, but the actual virtqueue_notify() call does not.
++ */
++bool virtqueue_kick_prepare(struct virtqueue *_vq)
+ {
+ struct vring_virtqueue *vq = to_vvq(_vq);
+ u16 new, old;
++ bool needs_kick;
++
+ START_USE(vq);
+ /* Descriptors and available array need to be set before we expose the
+ * new available array entries. */
+@@ -261,13 +274,46 @@ void virtqueue_kick(struct virtqueue *_v
+ /* Need to update avail index before checking if we should notify */
+ virtio_mb();
+
+- if (vq->event ?
+- vring_need_event(vring_avail_event(&vq->vring), new, old) :
+- !(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
+- /* Prod other side to tell it about changes. */
+- vq->notify(&vq->vq);
+-
++ if (vq->event) {
++ needs_kick = vring_need_event(vring_avail_event(&vq->vring),
++ new, old);
++ } else {
++ needs_kick = !(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY);
++ }
+ END_USE(vq);
++ return needs_kick;
++}
++EXPORT_SYMBOL_GPL(virtqueue_kick_prepare);
++
++/**
++ * virtqueue_notify - second half of split virtqueue_kick call.
++ * @vq: the struct virtqueue
++ *
++ * This does not need to be serialized.
++ */
++void virtqueue_notify(struct virtqueue *_vq)
++{
++ struct vring_virtqueue *vq = to_vvq(_vq);
++
++ /* Prod other side to tell it about changes. */
++ vq->notify(_vq);
++}
++EXPORT_SYMBOL_GPL(virtqueue_notify);
++
++/**
++ * virtqueue_kick - update after add_buf
++ * @vq: the struct virtqueue
++ *
++ * After one or more virtqueue_add_buf calls, invoke this to kick
++ * the other side.
++ *
++ * Caller must ensure we don't call this with other virtqueue
++ * operations at the same time (except where noted).
++ */
++void virtqueue_kick(struct virtqueue *vq)
++{
++ if (virtqueue_kick_prepare(vq))
++ virtqueue_notify(vq);
+ }
+ EXPORT_SYMBOL_GPL(virtqueue_kick);
+
+--- a/include/linux/virtio.h
++++ b/include/linux/virtio.h
+@@ -90,6 +90,10 @@ static inline int virtqueue_add_buf(stru
+
+ void virtqueue_kick(struct virtqueue *vq);
+
++bool virtqueue_kick_prepare(struct virtqueue *vq);
++
++void virtqueue_notify(struct virtqueue *vq);
++
+ void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
+
+ void virtqueue_disable_cb(struct virtqueue *vq);
Modified: dists/sid/linux/debian/patches/series
==============================================================================
--- dists/sid/linux/debian/patches/series Thu Feb 7 04:09:44 2013 (r19793)
+++ dists/sid/linux/debian/patches/series Thu Feb 7 04:42:39 2013 (r19794)
@@ -502,3 +502,18 @@
bugfix/x86/drm-i915-GFX_MODE-Flush-TLB-Invalidate-Mode-must-be-.patch
bugfix/x86/drm-i915-dump-UTS_RELEASE-into-the-error_state.patch
features/all/drm/efi-Make-efi_enabled-a-function-to-query-EFI-facilit.patch
+
+# virtio-scsi from 3.7
+features/all/virtio_scsi/0001-SCSI-virtio-scsi-SCSI-driver-for-QEMU-based-virtual-.patch
+features/all/virtio_scsi/0002-SCSI-virtio_scsi-fix-TMF-use-after-free.patch
+features/all/virtio_scsi/virtio-support-unlocked-queue-kick.patch
+features/all/virtio_scsi/0003-SCSI-virtio-scsi-unlock-during-kick.patch
+features/all/virtio_scsi/0004-SCSI-virtio-scsi-split-locking-per-vq.patch
+features/all/virtio_scsi/0005-SCSI-virtio-scsi-release-sg_lock-after-add_buf.patch
+features/all/virtio_scsi/0006-SCSI-virtio-scsi-split-scatterlist-per-target.patch
+features/all/virtio_scsi/0007-SCSI-virtio-scsi-hotplug-support-for-virtio-scsi.patch
+features/all/virtio_scsi/0008-SCSI-virtio-scsi-Add-vdrv-scan-for-post-VIRTIO_CONFI.patch
+features/all/virtio_scsi/0009-SCSI-scsi-virtio-scsi-Fix-address-translation-failur.patch
+features/all/virtio_scsi/0010-SCSI-virtio-scsi-initialize-scatterlist-structure.patch
+features/all/virtio_scsi/0011-SCSI-virtio-scsi-fix-LUNs-greater-than-255.patch
+features/all/virtio_scsi/0012-SCSI-virtio-scsi-support-online-resizing-of-disks.patch
More information about the Kernel-svn-changes
mailing list