[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [linux-2.6.18-xen] pvSCSI frontend driver



# 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.