# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1212397136 -3600
# Node ID 3b3701ad4eece5b99e88394d15846c2fc54a4506
# Parent 66faefe721ebb4c9490f3b06b653386d9d2ad4af
pvSCSI frontend driver
Signed-off-by: Tomonari Horikoshi <t.horikoshi@xxxxxxxxxxxxxx>
Signed-off-by: Jun Kamada <kama@xxxxxxxxxxxxxx>
---
buildconfigs/linux-defconfig_xen0_ia64 | 1
buildconfigs/linux-defconfig_xen0_x86_32 | 1
buildconfigs/linux-defconfig_xen0_x86_64 | 1
buildconfigs/linux-defconfig_xenU_ia64 | 1
buildconfigs/linux-defconfig_xenU_x86_32 | 1
buildconfigs/linux-defconfig_xenU_x86_64 | 1
buildconfigs/linux-defconfig_xen_ia64 | 1
buildconfigs/linux-defconfig_xen_x86_32 | 1
buildconfigs/linux-defconfig_xen_x86_64 | 1
drivers/xen/Kconfig | 8
drivers/xen/Makefile | 1
drivers/xen/scsifront/Makefile | 3
drivers/xen/scsifront/common.h | 132 +++++++
drivers/xen/scsifront/scsifront.c | 519 +++++++++++++++++++++++++++++++
drivers/xen/scsifront/xenbus.c | 446 ++++++++++++++++++++++++++
15 files changed, 1118 insertions(+)
diff -r 66faefe721eb -r 3b3701ad4eec buildconfigs/linux-defconfig_xen0_ia64
--- a/buildconfigs/linux-defconfig_xen0_ia64 Mon Jun 02 09:58:27 2008 +0100
+++ b/buildconfigs/linux-defconfig_xen0_ia64 Mon Jun 02 09:58:56 2008 +0100
@@ -1684,6 +1684,7 @@ CONFIG_XEN_SCSI_BACKEND=m
CONFIG_XEN_SCSI_BACKEND=m
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
+CONFIG_XEN_SCSI_FRONTEND=m
CONFIG_XEN_GRANT_DEV=y
# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
CONFIG_XEN_FRAMEBUFFER=y
diff -r 66faefe721eb -r 3b3701ad4eec buildconfigs/linux-defconfig_xen0_x86_32
--- a/buildconfigs/linux-defconfig_xen0_x86_32 Mon Jun 02 09:58:27 2008 +0100
+++ b/buildconfigs/linux-defconfig_xen0_x86_32 Mon Jun 02 09:58:56 2008 +0100
@@ -1421,6 +1421,7 @@ CONFIG_XEN_SCSI_BACKEND=m
CONFIG_XEN_SCSI_BACKEND=m
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
+CONFIG_XEN_SCSI_FRONTEND=m
CONFIG_XEN_GRANT_DEV=y
# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
CONFIG_XEN_SCRUB_PAGES=y
diff -r 66faefe721eb -r 3b3701ad4eec buildconfigs/linux-defconfig_xen0_x86_64
--- a/buildconfigs/linux-defconfig_xen0_x86_64 Mon Jun 02 09:58:27 2008 +0100
+++ b/buildconfigs/linux-defconfig_xen0_x86_64 Mon Jun 02 09:58:56 2008 +0100
@@ -1362,6 +1362,7 @@ CONFIG_XEN_PCIDEV_BACKEND_PASS=y
# CONFIG_XEN_SCSI_BACKEND is not set
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
+CONFIG_XEN_SCSI_FRONTEND=m
CONFIG_XEN_GRANT_DEV=y
# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
CONFIG_XEN_SCRUB_PAGES=y
diff -r 66faefe721eb -r 3b3701ad4eec buildconfigs/linux-defconfig_xenU_ia64
--- a/buildconfigs/linux-defconfig_xenU_ia64 Mon Jun 02 09:58:27 2008 +0100
+++ b/buildconfigs/linux-defconfig_xenU_ia64 Mon Jun 02 09:58:56 2008 +0100
@@ -1492,6 +1492,7 @@ CONFIG_XEN_XENBUS_DEV=y
# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
+CONFIG_XEN_SCSI_FRONTEND=m
# CONFIG_XEN_GRANT_DEV is not set
# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
CONFIG_XEN_FRAMEBUFFER=y
diff -r 66faefe721eb -r 3b3701ad4eec buildconfigs/linux-defconfig_xenU_x86_32
--- a/buildconfigs/linux-defconfig_xenU_x86_32 Mon Jun 02 09:58:27 2008 +0100
+++ b/buildconfigs/linux-defconfig_xenU_x86_32 Mon Jun 02 09:58:56 2008 +0100
@@ -916,6 +916,7 @@ CONFIG_XEN_XENBUS_DEV=y
# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
+CONFIG_XEN_SCSI_FRONTEND=m
# CONFIG_XEN_GRANT_DEV is not set
# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
CONFIG_XEN_SCRUB_PAGES=y
diff -r 66faefe721eb -r 3b3701ad4eec buildconfigs/linux-defconfig_xenU_x86_64
--- a/buildconfigs/linux-defconfig_xenU_x86_64 Mon Jun 02 09:58:27 2008 +0100
+++ b/buildconfigs/linux-defconfig_xenU_x86_64 Mon Jun 02 09:58:56 2008 +0100
@@ -878,6 +878,7 @@ CONFIG_XEN_XENBUS_DEV=y
# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
+CONFIG_XEN_SCSI_FRONTEND=m
CONFIG_XEN_GRANT_DEV=y
# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
CONFIG_XEN_SCRUB_PAGES=y
diff -r 66faefe721eb -r 3b3701ad4eec buildconfigs/linux-defconfig_xen_ia64
--- a/buildconfigs/linux-defconfig_xen_ia64 Mon Jun 02 09:58:27 2008 +0100
+++ b/buildconfigs/linux-defconfig_xen_ia64 Mon Jun 02 09:58:56 2008 +0100
@@ -1684,6 +1684,7 @@ CONFIG_XEN_SCSI_BACKEND=m
CONFIG_XEN_SCSI_BACKEND=m
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
+CONFIG_XEN_SCSI_FRONTEND=m
CONFIG_XEN_GRANT_DEV=y
# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
CONFIG_XEN_FRAMEBUFFER=y
diff -r 66faefe721eb -r 3b3701ad4eec buildconfigs/linux-defconfig_xen_x86_32
--- a/buildconfigs/linux-defconfig_xen_x86_32 Mon Jun 02 09:58:27 2008 +0100
+++ b/buildconfigs/linux-defconfig_xen_x86_32 Mon Jun 02 09:58:56 2008 +0100
@@ -3279,6 +3279,7 @@ CONFIG_XEN_SCSI_BACKEND=m
CONFIG_XEN_SCSI_BACKEND=m
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
+CONFIG_XEN_SCSI_FRONTEND=m
CONFIG_XEN_GRANT_DEV=y
# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
CONFIG_XEN_FRAMEBUFFER=y
diff -r 66faefe721eb -r 3b3701ad4eec buildconfigs/linux-defconfig_xen_x86_64
--- a/buildconfigs/linux-defconfig_xen_x86_64 Mon Jun 02 09:58:27 2008 +0100
+++ b/buildconfigs/linux-defconfig_xen_x86_64 Mon Jun 02 09:58:56 2008 +0100
@@ -3109,6 +3109,7 @@ CONFIG_XEN_SCSI_BACKEND=m
CONFIG_XEN_SCSI_BACKEND=m
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
+CONFIG_XEN_SCSI_FRONTEND=m
CONFIG_XEN_GRANT_DEV=y
# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
CONFIG_XEN_FRAMEBUFFER=y
diff -r 66faefe721eb -r 3b3701ad4eec drivers/xen/Kconfig
--- a/drivers/xen/Kconfig Mon Jun 02 09:58:27 2008 +0100
+++ b/drivers/xen/Kconfig Mon Jun 02 09:58:56 2008 +0100
@@ -199,6 +199,14 @@ config XEN_NETDEV_ACCEL_SFC_FRONTEND
select XEN_NETDEV_ACCEL_SFC_UTIL
default m
+config XEN_SCSI_FRONTEND
+ tristate "SCSI frontend driver"
+ depends on SCSI
+ default m
+ help
+ The SCSI frontend driver allows the kernel to access SCSI Devices
+ within another guest OS.
+
config XEN_GRANT_DEV
tristate "User-space granted page access driver"
default XEN_PRIVILEGED_GUEST
diff -r 66faefe721eb -r 3b3701ad4eec drivers/xen/Makefile
--- a/drivers/xen/Makefile Mon Jun 02 09:58:27 2008 +0100
+++ b/drivers/xen/Makefile Mon Jun 02 09:58:56 2008 +0100
@@ -17,6 +17,7 @@ obj-$(CONFIG_XEN_FRAMEBUFFER) += fbfron
obj-$(CONFIG_XEN_FRAMEBUFFER) += fbfront/
obj-$(CONFIG_XEN_KEYBOARD) += fbfront/
obj-$(CONFIG_XEN_SCSI_BACKEND) += scsiback/
+obj-$(CONFIG_XEN_SCSI_FRONTEND) += scsifront/
obj-$(CONFIG_XEN_PRIVCMD) += privcmd/
obj-$(CONFIG_XEN_GRANT_DEV) += gntdev/
obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL) += sfc_netutil/
diff -r 66faefe721eb -r 3b3701ad4eec drivers/xen/scsifront/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/Makefile Mon Jun 02 09:58:56 2008 +0100
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_XEN_SCSI_FRONTEND) := xenscsi.o
+xenscsi-objs := scsifront.o xenbus.o
diff -r 66faefe721eb -r 3b3701ad4eec drivers/xen/scsifront/common.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/common.h Mon Jun 02 09:58:56 2008 +0100
@@ -0,0 +1,132 @@
+/*
+ * Xen SCSI frontend driver
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __XEN_DRIVERS_SCSIFRONT_H__
+#define __XEN_DRIVERS_SCSIFRONT_H__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <xen/xenbus.h>
+#include <xen/gnttab.h>
+#include <xen/evtchn.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/io/vscsiif.h>
+#include <asm/delay.h>
+
+
+#define GRANT_INVALID_REF 0
+#define VSCSI_IN_ABORT 1
+#define VSCSI_IN_RESET 2
+
+/* tuning point*/
+#define VSCSIIF_DEFAULT_CMD_PER_LUN 10
+#define VSCSIIF_MAX_TARGET 64
+#define VSCSIIF_MAX_LUN 255
+
+#define VSCSIIF_RING_SIZE \
+ __RING_SIZE((struct vscsiif_sring *)0, PAGE_SIZE)
+#define VSCSIIF_MAX_REQS VSCSIIF_RING_SIZE
+
+struct vscsifrnt_shadow {
+ uint16_t next_free;
+
+ /* command between backend and frontend
+ * VSCSIIF_ACT_SCSI_CDB or VSCSIIF_ACT_SCSI_RESET */
+ unsigned char act;
+
+ /* do reset function */
+ wait_queue_head_t wq_reset; /* reset work queue */
+ int wait_reset; /* reset work queue condition */
+ int32_t rslt_reset; /* reset response status */
+ /* (SUCESS or FAILED) */
+
+ /* for DMA_TO_DEVICE(1), DMA_FROM_DEVICE(2), DMA_NONE(3)
+ requests */
+ unsigned int sc_data_direction;
+
+ /* Number of pieces of scatter-gather */
+ unsigned int nr_segments;
+
+ /* requested struct scsi_cmnd is stored from kernel */
+ unsigned long req_scsi_cmnd;
+ int gref[VSCSIIF_SG_TABLESIZE];
+};
+
+struct vscsifrnt_info {
+ struct xenbus_device *dev;
+
+ struct Scsi_Host *host;
+
+ spinlock_t io_lock;
+ spinlock_t shadow_lock;
+ unsigned int evtchn;
+ unsigned int irq;
+
+ grant_ref_t ring_ref;
+ struct vscsiif_front_ring ring;
+ struct vscsiif_response ring_res;
+
+ struct vscsifrnt_shadow shadow[VSCSIIF_MAX_REQS];
+ uint32_t shadow_free;
+
+ struct task_struct *kthread;
+ wait_queue_head_t wq;
+ unsigned int waiting_resp;
+
+ /* abort reset condition bit*/
+ atomic_t abort_reset_cond;
+
+};
+
+#define DPRINTK(_f, _a...) \
+ pr_debug("(file=%s, line=%d) " _f, \
+ __FILE__ , __LINE__ , ## _a )
+
+int scsifront_xenbus_init(void);
+void scsifront_xenbus_unregister(void);
+int scsifront_schedule(void *data);
+irqreturn_t scsifront_intr(int irq, void *dev_id, struct pt_regs *ptregs);
+int scsifront_cmd_done(struct vscsifrnt_info *info);
+
+
+#endif /* __XEN_DRIVERS_SCSIFRONT_H__ */
diff -r 66faefe721eb -r 3b3701ad4eec drivers/xen/scsifront/scsifront.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/scsifront.c Mon Jun 02 09:58:56 2008 +0100
@@ -0,0 +1,519 @@
+/*
+ * Xen SCSI frontend driver
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+#include <linux/version.h>
+#include "common.h"
+
+static int get_id_from_freelist(struct vscsifrnt_info *info)
+{
+ unsigned long flags;
+ uint32_t free;
+
+ spin_lock_irqsave(&info->shadow_lock, flags);
+
+ free = info->shadow_free;
+ BUG_ON(free > VSCSIIF_MAX_REQS);
+ info->shadow_free = info->shadow[free].next_free;
+ info->shadow[free].next_free = 0x0fff;
+
+ info->shadow[free].wait_reset = 0;
+
+ spin_unlock_irqrestore(&info->shadow_lock, flags);
+
+ return free;
+}
+
+static void add_id_to_freelist(struct vscsifrnt_info *info, uint32_t id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->shadow_lock, flags);
+
+ info->shadow[id].next_free = info->shadow_free;
+ info->shadow[id].req_scsi_cmnd = 0;
+ info->shadow_free = id;
+
+ spin_unlock_irqrestore(&info->shadow_lock, flags);
+}
+
+
+struct vscsiif_request * scsifront_pre_request(struct vscsifrnt_info *info)
+{
+ struct vscsiif_front_ring *ring = &(info->ring);
+ vscsiif_request_t *ring_req;
+ uint32_t id;
+
+ ring_req = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+
+ ring->req_prod_pvt++;
+
+ id = get_id_from_freelist(info); /* use id by response */
+ ring_req->rqid = (uint16_t)id;
+
+ return ring_req;
+}
+
+
+static void scsifront_notify_work(struct vscsifrnt_info *info)
+{
+ info->waiting_resp = 1;
+ wake_up(&info->wq);
+}
+
+
+static void scsifront_do_request(struct vscsifrnt_info *info)
+{
+ struct vscsiif_front_ring *ring = &(info->ring);
+ unsigned int irq = info->irq;
+ int notify;
+
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify);
+ if (notify)
+ notify_remote_via_irq(irq);
+}
+
+irqreturn_t scsifront_intr(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ scsifront_notify_work((struct vscsifrnt_info *)dev_id);
+ return IRQ_HANDLED;
+}
+
+
+static void scsifront_gnttab_done(struct vscsifrnt_shadow *s, uint32_t id)
+{
+ int i;
+
+ if (s->sc_data_direction == DMA_NONE)
+ return;
+
+ if (s->nr_segments) {
+ for (i = 0; i < s->nr_segments; i++) {
+ if (unlikely(gnttab_query_foreign_access(
+ s->gref[i]) != 0)) {
+ printk(KERN_ALERT "scsifront: "
+ "grant still in use by backend.\n");
+ BUG();
+ }
+ gnttab_end_foreign_access(s->gref[i], 0UL);
+ }
+ }
+
+ return;
+}
+
+
+static void scsifront_cdb_cmd_done(struct vscsifrnt_info *info,
+ vscsiif_response_t *ring_res)
+{
+ struct scsi_cmnd *sc;
+ uint32_t id;
+ uint8_t sense_len;
+
+ id = ring_res->rqid;
+ sc = (struct scsi_cmnd *)info->shadow[id].req_scsi_cmnd;
+
+ if (sc == NULL)
+ BUG();
+
+ scsifront_gnttab_done(&info->shadow[id], id);
+ add_id_to_freelist(info, id);
+
+ rmb();
+ if (atomic_read(&info->abort_reset_cond) == VSCSI_IN_RESET) {
+ sc->result = (DID_RESET << 16);
+ } else {
+ sc->result = ring_res->rslt;
+ }
+
+ sc->resid = 0;
+
+ if (ring_res->sense_len > VSCSIIF_SENSE_BUFFERSIZE)
+ sense_len = VSCSIIF_SENSE_BUFFERSIZE;
+ else
+ sense_len = ring_res->sense_len;
+
+ if (sense_len)
+ memcpy(sc->sense_buffer, ring_res->sense_buffer, sense_len);
+
+ sc->scsi_done(sc);
+
+ return;
+}
+
+
+static void scsifront_sync_cmd_done(struct vscsifrnt_info *info,
+ vscsiif_response_t *ring_res)
+{
+ uint16_t id = ring_res->rqid;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->shadow_lock, flags);
+ info->shadow[id].wait_reset = 1;
+ info->shadow[id].rslt_reset = ring_res->rslt;
+ spin_unlock_irqrestore(&info->shadow_lock, flags);
+
+ wake_up(&(info->shadow[id].wq_reset));
+}
+
+
+int scsifront_cmd_done(struct vscsifrnt_info *info)
+{
+ vscsiif_response_t *ring_res;
+
+ RING_IDX i, rp;
+ int more_to_do = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->io_lock, flags);
+
+ rp = info->ring.sring->rsp_prod;
+ rmb();
+ for (i = info->ring.rsp_cons; i != rp; i++) {
+
+ ring_res = RING_GET_RESPONSE(&info->ring, i);
+
+ if (info->shadow[ring_res->rqid].act == VSCSIIF_ACT_SCSI_CDB)
+ scsifront_cdb_cmd_done(info, ring_res);
+ else
+ scsifront_sync_cmd_done(info, ring_res);
+ }
+
+ info->ring.rsp_cons = i;
+
+ if (i != info->ring.req_prod_pvt) {
+ RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do);
+ } else {
+ info->ring.sring->rsp_event = i + 1;
+ }
+
+ spin_unlock_irqrestore(&info->io_lock, flags);
+
+ return more_to_do;
+}
+
+
+
+
+int scsifront_schedule(void *data)
+{
+ struct vscsifrnt_info *info = (struct vscsifrnt_info *)data;
+
+ while (!kthread_should_stop()) {
+ wait_event_interruptible(
+ info->wq,
+ info->waiting_resp || kthread_should_stop());
+
+ info->waiting_resp = 0;
+ smp_mb();
+
+ if (scsifront_cmd_done(info))
+ info->waiting_resp = 1;
+ }
+
+ info->kthread = NULL;
+
+ return 0;
+}
+
+
+
+static int map_data_for_request(struct vscsifrnt_info *info,
+ struct scsi_cmnd *sc, vscsiif_request_t *ring_req, uint32_t id)
+{
+ grant_ref_t gref_head;
+ struct page *page;
+ int err, i, ref, ref_cnt = 0;
+ int write = (sc->sc_data_direction == DMA_TO_DEVICE);
+ int nr_pages, off, len, bytes;
+ unsigned long buffer_pfn;
+ unsigned int data_len = 0;
+
+ if (sc->sc_data_direction == DMA_NONE)
+ return 0;
+
+ err = gnttab_alloc_grant_references(VSCSIIF_SG_TABLESIZE, &gref_head);
+ if (err) {
+ printk(KERN_ERR "scsifront: gnttab_alloc_grant_references()
error\n");
+ return -ENOMEM;
+ }
+
+ if (sc->use_sg) {
+ /* quoted scsi_lib.c/scsi_req_map_sg . */
+ struct scatterlist *sg = (struct scatterlist
*)sc->request_buffer;
+ nr_pages = (sc->request_bufflen + sg[0].offset + PAGE_SIZE - 1)
>> PAGE_SHIFT;
+
+ if (nr_pages > VSCSIIF_SG_TABLESIZE) {
+ printk(KERN_ERR "scsifront: Unable to map
request_buffer for command!\n");
+ ref_cnt = (-E2BIG);
+ goto big_to_sg;
+ }
+
+ for (i = 0; i < sc->use_sg; i++) {
+ page = sg[i].page;
+ off = sg[i].offset;
+ len = sg[i].length;
+ data_len += len;
+
+ buffer_pfn = page_to_phys(page) >> PAGE_SHIFT;
+
+ while (len > 0) {
+ bytes = min_t(unsigned int, len, PAGE_SIZE -
off);
+
+ ref = gnttab_claim_grant_reference(&gref_head);
+ BUG_ON(ref == -ENOSPC);
+
+ gnttab_grant_foreign_access_ref(ref,
info->dev->otherend_id,
+ buffer_pfn, write);
+
+ info->shadow[id].gref[ref_cnt] = ref;
+ ring_req->seg[ref_cnt].gref = ref;
+ ring_req->seg[ref_cnt].offset = (uint16_t)off;
+ ring_req->seg[ref_cnt].length =
(uint16_t)bytes;
+
+ buffer_pfn++;
+ len -= bytes;
+ off = 0;
+ ref_cnt++;
+ }
+ }
+ } else if (sc->request_bufflen) {
+ unsigned long end = ((unsigned long)sc->request_buffer
+ + sc->request_bufflen + PAGE_SIZE - 1)
>> PAGE_SHIFT;
+ unsigned long start = (unsigned long)sc->request_buffer >>
PAGE_SHIFT;
+
+ page = virt_to_page(sc->request_buffer);
+ nr_pages = end - start;
+ len = sc->request_bufflen;
+
+ if (nr_pages > VSCSIIF_SG_TABLESIZE) {
+ ref_cnt = (-E2BIG);
+ goto big_to_sg;
+ }
+
+ buffer_pfn = page_to_phys(page) >> PAGE_SHIFT;
+
+ off = offset_in_page((unsigned long)sc->request_buffer);
+ for (i = 0; i < nr_pages; i++) {
+ bytes = PAGE_SIZE - off;
+
+ if (bytes > len)
+ bytes = len;
+
+ ref = gnttab_claim_grant_reference(&gref_head);
+ BUG_ON(ref == -ENOSPC);
+
+ gnttab_grant_foreign_access_ref(ref,
info->dev->otherend_id,
+ buffer_pfn, write);
+
+ info->shadow[id].gref[i] = ref;
+ ring_req->seg[i].gref = ref;
+ ring_req->seg[i].offset = (uint16_t)off;
+ ring_req->seg[i].length = (uint16_t)bytes;
+
+ buffer_pfn++;
+ len -= bytes;
+ off = 0;
+ ref_cnt++;
+ }
+ }
+
+big_to_sg:
+
+ gnttab_free_grant_references(gref_head);
+
+ return ref_cnt;
+}
+
+static int scsifront_queuecommand(struct scsi_cmnd *sc,
+ void (*done)(struct scsi_cmnd *))
+{
+ struct vscsifrnt_info *info =
+ (struct vscsifrnt_info *) sc->device->host->hostdata;
+ vscsiif_request_t *ring_req;
+ int ref_cnt;
+ uint16_t rqid;
+
+ if (RING_FULL(&info->ring)) {
+ goto out_host_busy;
+ }
+
+ sc->scsi_done = done;
+ sc->result = 0;
+
+ ring_req = scsifront_pre_request(info);
+ rqid = ring_req->rqid;
+ ring_req->act = VSCSIIF_ACT_SCSI_CDB;
+
+ ring_req->id = sc->device->id;
+ ring_req->lun = sc->device->lun;
+ ring_req->channel = sc->device->channel;
+ ring_req->cmd_len = sc->cmd_len;
+
+ BUG_ON(sc->cmd_len > VSCSIIF_MAX_COMMAND_SIZE);
+
+ if ( sc->cmd_len )
+ memcpy(ring_req->cmnd, sc->cmnd, sc->cmd_len);
+ else
+ memset(ring_req->cmnd, 0, VSCSIIF_MAX_COMMAND_SIZE);
+
+ ring_req->sc_data_direction = (uint8_t)sc->sc_data_direction;
+ ring_req->timeout_per_command = (sc->timeout_per_command / HZ);
+
+ info->shadow[rqid].req_scsi_cmnd = (unsigned long)sc;
+ info->shadow[rqid].sc_data_direction = sc->sc_data_direction;
+ info->shadow[rqid].act = ring_req->act;
+
+ ref_cnt = map_data_for_request(info, sc, ring_req, rqid);
+ if (ref_cnt < 0) {
+ add_id_to_freelist(info, rqid);
+ if (ref_cnt == (-ENOMEM))
+ goto out_host_busy;
+ else {
+ sc->result = (DID_ERROR << 16);
+ goto out_fail_command;
+ }
+ }
+
+ ring_req->nr_segments = (uint8_t)ref_cnt;
+ info->shadow[rqid].nr_segments = ref_cnt;
+
+ scsifront_do_request(info);
+
+ return 0;
+
+out_host_busy:
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+out_fail_command:
+ done(sc);
+ return 0;
+}
+
+
+static int scsifront_eh_abort_handler(struct scsi_cmnd *sc)
+{
+ return (FAILED);
+}
+
+/* vscsi supports only device_reset, because it is each of LUNs */
+static int scsifront_dev_reset_handler(struct scsi_cmnd *sc)
+{
+ struct Scsi_Host *host = sc->device->host;
+ struct vscsifrnt_info *info =
+ (struct vscsifrnt_info *) sc->device->host->hostdata;
+
+ vscsiif_request_t *ring_req;
+ int err;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
+ spin_lock_irq(host->host_lock);
+#endif
+
+ atomic_set(&info->abort_reset_cond, VSCSI_IN_RESET);
+ while (RING_HAS_UNCONSUMED_RESPONSES(&info->ring)) {
+ if (!scsifront_cmd_done(info))
+ break;
+ }
+
+ ring_req = scsifront_pre_request(info);
+ ring_req->act = VSCSIIF_ACT_SCSI_RESET;
+
+ info->shadow[ring_req->rqid].act = VSCSIIF_ACT_SCSI_RESET;
+
+ ring_req->channel = sc->device->channel;
+ ring_req->id = sc->device->id;
+ ring_req->lun = sc->device->lun;
+ ring_req->cmd_len = sc->cmd_len;
+
+ if ( sc->cmd_len )
+ memcpy(ring_req->cmnd, sc->cmnd, sc->cmd_len);
+ else
+ memset(ring_req->cmnd, 0, VSCSIIF_MAX_COMMAND_SIZE);
+
+ ring_req->sc_data_direction = (uint8_t)sc->sc_data_direction;
+ ring_req->timeout_per_command = (sc->timeout_per_command / HZ);
+ ring_req->nr_segments = 0;
+
+ spin_unlock_irq(host->host_lock);
+ scsifront_do_request(info);
+ wait_event_interruptible(info->shadow[ring_req->rqid].wq_reset,
+ info->shadow[ring_req->rqid].wait_reset);
+
+ spin_lock_irq(host->host_lock);
+
+ err = info->shadow[ring_req->rqid].rslt_reset;
+ atomic_set(&info->abort_reset_cond, 0);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
+ spin_unlock_irq(host->host_lock);
+#endif
+
+ return (err);
+}
+
+
+struct scsi_host_template scsifront_sht = {
+ .module = THIS_MODULE,
+ .name = "Xen SCSI frontend driver",
+ .queuecommand = scsifront_queuecommand,
+ .eh_abort_handler = scsifront_eh_abort_handler,
+ .eh_device_reset_handler= scsifront_dev_reset_handler,
+ .cmd_per_lun = VSCSIIF_DEFAULT_CMD_PER_LUN,
+ .can_queue = VSCSIIF_MAX_REQS,
+ .this_id = -1,
+ .sg_tablesize = VSCSIIF_SG_TABLESIZE,
+ .use_clustering = DISABLE_CLUSTERING,
+ .proc_name = "scsifront",
+};
+
+
+static int __init scsifront_init(void)
+{
+ int err;
+
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ err = scsifront_xenbus_init();
+
+ return err;
+}
+
+static void __exit scsifront_exit(void)
+{
+ scsifront_xenbus_unregister();
+}
+
+module_init(scsifront_init);
+module_exit(scsifront_exit);
+
+MODULE_DESCRIPTION("Xen SCSI frontend driver");
+MODULE_LICENSE("GPL");
diff -r 66faefe721eb -r 3b3701ad4eec drivers/xen/scsifront/xenbus.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/xenbus.c Mon Jun 02 09:58:56 2008 +0100
@@ -0,0 +1,446 @@
+/*
+ * Xen SCSI frontend driver
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+#include <linux/version.h>
+#include "common.h"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
+ #define DEFAULT_TASK_COMM_LEN 16
+#else
+ #define DEFAULT_TASK_COMM_LEN TASK_COMM_LEN
+#endif
+
+extern struct scsi_host_template scsifront_sht;
+
+static void scsifront_free(struct vscsifrnt_info *info)
+{
+ struct Scsi_Host *host = info->host;
+
+ if (scsi_host_get(host) != NULL)
+ scsi_host_put(host);
+
+ if (info->ring_ref != GRANT_INVALID_REF) {
+ gnttab_end_foreign_access(info->ring_ref,
+ (unsigned long)info->ring.sring);
+ info->ring_ref = GRANT_INVALID_REF;
+ info->ring.sring = NULL;
+ }
+
+ if (info->irq)
+ unbind_from_irqhandler(info->irq, info);
+ info->irq = 0;
+}
+
+
+static int scsifront_alloc_ring(struct vscsifrnt_info *info)
+{
+ struct xenbus_device *dev = info->dev;
+ struct vscsiif_sring *sring;
+ int err = -ENOMEM;
+
+
+ info->ring_ref = GRANT_INVALID_REF;
+
+ /***** Frontend to Backend ring start *****/
+ sring = (struct vscsiif_sring *) __get_free_page(GFP_KERNEL);
+ if (!sring) {
+ xenbus_dev_fatal(dev, err, "fail to allocate shared ring (Front
to Back)");
+ return err;
+ }
+ SHARED_RING_INIT(sring);
+ FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+ err = xenbus_grant_ring(dev, virt_to_mfn(sring));
+ if (err < 0) {
+ free_page((unsigned long) sring);
+ info->ring.sring = NULL;
+ xenbus_dev_fatal(dev, err, "fail to grant shared ring (Front to
Back)");
+ goto free_sring;
+ }
+ info->ring_ref = err;
+
+ err = bind_listening_port_to_irqhandler(
+ dev->otherend_id, scsifront_intr,
+ SA_SAMPLE_RANDOM, "scsifront", info);
+
+ if (err <= 0) {
+ xenbus_dev_fatal(dev, err, "bind_listening_port_to_irqhandler");
+ goto fail;
+ }
+ info->irq = err;
+
+ return 0;
+fail:
+ /* free resource */
+free_sring:
+ scsifront_free(info);
+
+ return err;
+}
+
+
+static int scsifront_init_ring(struct vscsifrnt_info *info)
+{
+ struct xenbus_device *dev = info->dev;
+ struct xenbus_transaction xbt;
+ int err;
+
+ DPRINTK("%s\n",__FUNCTION__);
+
+ err = scsifront_alloc_ring(info);
+ if (err)
+ return err;
+ DPRINTK("%u %u\n", info->ring_ref, info->evtchn);
+
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "starting transaction");
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u",
+ info->ring_ref);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "%s", "writing ring-ref");
+ goto fail;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+ irq_to_evtchn_port(info->irq));
+
+ if (err) {
+ xenbus_dev_fatal(dev, err, "%s", "writing event-channel");
+ goto fail;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "vhostno", "%u",
+ info->host->host_no);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "%s", "writing vhostno");
+ goto fail;
+ }
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err) {
+ if (err == -EAGAIN)
+ goto again;
+ xenbus_dev_fatal(dev, err, "completing transaction");
+ } else
+ xenbus_switch_state(dev, XenbusStateInitialised);
+
+ return 0;
+
+fail:
+ xenbus_transaction_end(xbt, 1);
+ /* free resource */
+ scsifront_free(info);
+
+ return err;
+}
+
+
+static int scsifront_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ struct vscsifrnt_info *info;
+ struct Scsi_Host *host;
+ int i, err = -ENOMEM;
+ char name[DEFAULT_TASK_COMM_LEN];
+
+ host = scsi_host_alloc(&scsifront_sht, sizeof(*info));
+ if (!host) {
+ xenbus_dev_fatal(dev, err, "fail to allocate scsi host");
+ return err;
+ }
+ info = (struct vscsifrnt_info *) host->hostdata;
+ info->host = host;
+
+
+ dev->dev.driver_data = info;
+ info->dev = dev;
+
+ for (i = 0; i < VSCSIIF_MAX_REQS; i++) {
+ info->shadow[i].next_free = i + 1;
+ init_waitqueue_head(&(info->shadow[i].wq_reset));
+ info->shadow[i].wait_reset = 0;
+ }
+ info->shadow[VSCSIIF_MAX_REQS - 1].next_free = 0x0fff;
+
+ atomic_set(&info->abort_reset_cond, 0);
+
+ err = scsifront_init_ring(info);
+ if (err) {
+ scsi_host_put(host);
+ return err;
+ }
+
+ init_waitqueue_head(&info->wq);
+ spin_lock_init(&info->io_lock);
+ spin_lock_init(&info->shadow_lock);
+
+ snprintf(name, DEFAULT_TASK_COMM_LEN, "vscsiif.%d",
info->host->host_no);
+
+ info->kthread = kthread_run(scsifront_schedule, info, name);
+ if (IS_ERR(info->kthread)) {
+ err = PTR_ERR(info->kthread);
+ info->kthread = NULL;
+ }
+
+ host->max_id = VSCSIIF_MAX_TARGET;
+ host->max_channel = 0;
+ host->max_lun = VSCSIIF_MAX_LUN;
+ host->max_sectors = (VSCSIIF_SG_TABLESIZE * PAGE_SIZE / 512);
+
+ err = scsi_add_host(host, &dev->dev);
+ if (err) {
+ printk(KERN_ERR "scsifront: fail to add scsi host %d\n", err);
+ return err;
+ }
+
+ xenbus_switch_state(dev, XenbusStateInitialised);
+
+ #if 0
+ /* All SCSI device scan */
+ scsi_scan_host(host);
+
+ err = xenbus_printf(XBT_NIL, dev->nodename, "hotplug-status", "%s",
+ "connected");
+ if (err) {
+ xenbus_dev_fatal(dev, err, "%s", "writing hotplug-status");
+ return err;
+ }
+ #endif
+ return 0;
+}
+
+static int scsifront_remove(struct xenbus_device *dev)
+{
+ struct vscsifrnt_info *info = dev->dev.driver_data;
+
+ DPRINTK("%s: %s removed\n",__FUNCTION__ ,dev->nodename);
+
+ if (info->kthread) {
+ kthread_stop(info->kthread);
+ info->kthread = NULL;
+ }
+
+ scsifront_free(info);
+
+ return 0;
+}
+
+
+static int scsifront_disconnect(struct vscsifrnt_info *info)
+{
+ struct xenbus_device *dev = info->dev;
+ struct Scsi_Host *host = info->host;
+
+ unsigned long flags;
+
+ DPRINTK("%s: %s disconnect\n",__FUNCTION__ ,dev->nodename);
+
+ spin_lock_irqsave(host->host_lock, flags);
+ while (RING_HAS_UNCONSUMED_RESPONSES(&info->ring)) {
+ if (!scsifront_cmd_done(info))
+ break;
+ }
+
+ spin_unlock_irqrestore(host->host_lock, flags);
+
+ spin_lock(&info->io_lock);
+
+ scsi_remove_host(host);
+ scsi_host_put(host);
+
+ spin_unlock(&info->io_lock);
+
+
+ xenbus_frontend_closed(dev);
+
+ return 0;
+}
+
+#define VSCSIFRONT_OP_ADD_LUN 1
+#define VSCSIFRONT_OP_DEL_LUN 2
+
+static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op)
+{
+ struct xenbus_device *dev = info->dev;
+ int i, err = 0;
+ char str[64], state_str[64];
+ char **dir;
+ unsigned int dir_n = 0;
+ unsigned int device_state;
+ unsigned int hst, chn, tgt, lun;
+ struct scsi_device *sdev;
+
+ dir = xenbus_directory(XBT_NIL, dev->otherend, "vscsi-devs", &dir_n);
+ if (IS_ERR(dir))
+ return;
+
+ for (i = 0; i < dir_n; i++) {
+ /* read status */
+ snprintf(str, sizeof(str), "vscsi-devs/%s/state", dir[i]);
+ err = xenbus_scanf(XBT_NIL, dev->otherend, str, "%u",
+ &device_state);
+ if (XENBUS_EXIST_ERR(err))
+ goto fail;
+
+ /* virtual SCSI device */
+ snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", dir[i]);
+ err = xenbus_scanf(XBT_NIL, dev->otherend, str,
+ "%u:%u:%u:%u", &hst, &chn, &tgt, &lun);
+ if (XENBUS_EXIST_ERR(err))
+ goto fail;
+
+ /* front device state path */
+ snprintf(state_str, sizeof(state_str), "vscsi-devs/%s/state",
dir[i]);
+
+ switch (op) {
+ case VSCSIFRONT_OP_ADD_LUN:
+ if (device_state == XenbusStateInitialised) {
+ sdev = scsi_device_lookup(info->host, chn, tgt,
lun);
+ if (sdev) {
+ xenbus_printf(XBT_NIL, dev->nodename,
+ state_str, "%d",
XenbusStateClosing);
+ } else {
+ scsi_add_device(info->host, chn, tgt,
lun);
+ xenbus_printf(XBT_NIL, dev->nodename,
+ state_str, "%d",
XenbusStateInitialised);
+ }
+ }
+ break;
+ case VSCSIFRONT_OP_DEL_LUN:
+ if (device_state == XenbusStateClosing) {
+ sdev = scsi_device_lookup(info->host, chn, tgt,
lun);
+ if (sdev) {
+ scsi_remove_device(sdev);
+ scsi_device_put(sdev);
+ xenbus_printf(XBT_NIL, dev->nodename,
+ state_str, "%d",
XenbusStateClosing);
+ } else {
+ err = PTR_ERR(sdev);
+ goto scsi_del_fail;
+ }
+ }
+ break;
+ default:
+ goto fail;
+ break;
+ }
+ }
+
+ kfree(dir);
+ return;
+
+fail:
+ kfree(dir);
+ xenbus_dev_fatal(dev, err, "read or write %s ", str);
+ return;
+
+scsi_del_fail:
+ kfree(dir);
+ printk(KERN_ERR "scsifront: fail to del scsi lun %d\n", err);
+ return;
+
+}
+
+
+
+
+static void scsifront_backend_changed(struct xenbus_device *dev,
+ enum xenbus_state backend_state)
+{
+ struct vscsifrnt_info *info = dev->dev.driver_data;
+
+ DPRINTK("%p %u %u\n", dev, dev->state, backend_state);
+
+ switch (backend_state) {
+ case XenbusStateUnknown:
+ case XenbusStateInitialising:
+ case XenbusStateInitWait:
+ case XenbusStateClosed:
+ break;
+
+ case XenbusStateInitialised:
+ break;
+
+ case XenbusStateConnected:
+ if (xenbus_read_driver_state(dev->nodename) ==
+ XenbusStateInitialised) {
+ scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN);
+ }
+ xenbus_switch_state(dev, XenbusStateConnected);
+ break;
+
+ case XenbusStateClosing:
+ scsifront_disconnect(info);
+ break;
+
+ case XenbusStateReconfiguring:
+ scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_DEL_LUN);
+ xenbus_switch_state(dev, XenbusStateReconfiguring);
+ break;
+
+ case XenbusStateReconfigured:
+ scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN);
+ xenbus_switch_state(dev, XenbusStateConnected);
+ break;
+ }
+}
+
+
+static struct xenbus_device_id scsifront_ids[] = {
+ { "vscsi" },
+ { "" }
+};
+
+
+static struct xenbus_driver scsifront_driver = {
+ .name = "vscsi",
+ .owner = THIS_MODULE,
+ .ids = scsifront_ids,
+ .probe = scsifront_probe,
+ .remove = scsifront_remove,
+/* .resume = scsifront_resume, */
+ .otherend_changed = scsifront_backend_changed,
+};
+
+int scsifront_xenbus_init(void)
+{
+ return xenbus_register_frontend(&scsifront_driver);
+}
+
+void scsifront_xenbus_unregister(void)
+{
+ xenbus_unregister_driver(&scsifront_driver);
+}
+
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|