[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