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