WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

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

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [linux-2.6.18-xen] pvSCSI backend driver
From: "Xen patchbot-linux-2.6.18-xen" <patchbot-linux-2.6.18-xen@xxxxxxxxxxxxxxxxxxx>
Date: Mon, 02 Jun 2008 08:40:08 -0700
Delivery-date: Mon, 02 Jun 2008 08:40:21 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1212397107 -3600
# Node ID 66faefe721ebb4c9490f3b06b653386d9d2ad4af
# Parent  557a4a0a5eacb83ffb2808c66fd9674e8e26f3e0
pvSCSI backend 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_xen_ia64    |    1 
 buildconfigs/linux-defconfig_xen_x86_32  |    1 
 buildconfigs/linux-defconfig_xen_x86_64  |    1 
 drivers/xen/Kconfig                      |   10 
 drivers/xen/Makefile                     |    1 
 drivers/xen/scsiback/Makefile            |    4 
 drivers/xen/scsiback/common.h            |  181 +++++++
 drivers/xen/scsiback/emulate.c           |  275 +++++++++++
 drivers/xen/scsiback/interface.c         |  184 +++++++
 drivers/xen/scsiback/scsiback.c          |  734 +++++++++++++++++++++++++++++++
 drivers/xen/scsiback/translate.c         |  166 +++++++
 drivers/xen/scsiback/xenbus.c            |  365 +++++++++++++++
 15 files changed, 1925 insertions(+), 1 deletion(-)

diff -r 557a4a0a5eac -r 66faefe721eb buildconfigs/linux-defconfig_xen0_ia64
--- a/buildconfigs/linux-defconfig_xen0_ia64    Fri May 30 19:08:50 2008 +0100
+++ b/buildconfigs/linux-defconfig_xen0_ia64    Mon Jun 02 09:58:27 2008 +0100
@@ -1681,6 +1681,7 @@ CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER=y
 CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER=y
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 CONFIG_XEN_TPMDEV_BACKEND=m
+CONFIG_XEN_SCSI_BACKEND=m
 CONFIG_XEN_BLKDEV_FRONTEND=y
 CONFIG_XEN_NETDEV_FRONTEND=y
 CONFIG_XEN_GRANT_DEV=y
diff -r 557a4a0a5eac -r 66faefe721eb buildconfigs/linux-defconfig_xen0_x86_32
--- a/buildconfigs/linux-defconfig_xen0_x86_32  Fri May 30 19:08:50 2008 +0100
+++ b/buildconfigs/linux-defconfig_xen0_x86_32  Mon Jun 02 09:58:27 2008 +0100
@@ -1418,6 +1418,7 @@ CONFIG_XEN_PCIDEV_BACKEND_PASS=y
 # CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER is not set
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 CONFIG_XEN_TPMDEV_BACKEND=m
+CONFIG_XEN_SCSI_BACKEND=m
 CONFIG_XEN_BLKDEV_FRONTEND=y
 CONFIG_XEN_NETDEV_FRONTEND=y
 CONFIG_XEN_GRANT_DEV=y
diff -r 557a4a0a5eac -r 66faefe721eb buildconfigs/linux-defconfig_xen0_x86_64
--- a/buildconfigs/linux-defconfig_xen0_x86_64  Fri May 30 19:08:50 2008 +0100
+++ b/buildconfigs/linux-defconfig_xen0_x86_64  Mon Jun 02 09:58:27 2008 +0100
@@ -1359,6 +1359,7 @@ CONFIG_XEN_PCIDEV_BACKEND_PASS=y
 # CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER is not set
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 # CONFIG_XEN_TPMDEV_BACKEND is not set
+# CONFIG_XEN_SCSI_BACKEND is not set
 CONFIG_XEN_BLKDEV_FRONTEND=y
 CONFIG_XEN_NETDEV_FRONTEND=y
 CONFIG_XEN_GRANT_DEV=y
diff -r 557a4a0a5eac -r 66faefe721eb buildconfigs/linux-defconfig_xen_ia64
--- a/buildconfigs/linux-defconfig_xen_ia64     Fri May 30 19:08:50 2008 +0100
+++ b/buildconfigs/linux-defconfig_xen_ia64     Mon Jun 02 09:58:27 2008 +0100
@@ -1681,6 +1681,7 @@ CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER=y
 CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER=y
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 CONFIG_XEN_TPMDEV_BACKEND=m
+CONFIG_XEN_SCSI_BACKEND=m
 CONFIG_XEN_BLKDEV_FRONTEND=y
 CONFIG_XEN_NETDEV_FRONTEND=y
 CONFIG_XEN_GRANT_DEV=y
diff -r 557a4a0a5eac -r 66faefe721eb buildconfigs/linux-defconfig_xen_x86_32
--- a/buildconfigs/linux-defconfig_xen_x86_32   Fri May 30 19:08:50 2008 +0100
+++ b/buildconfigs/linux-defconfig_xen_x86_32   Mon Jun 02 09:58:27 2008 +0100
@@ -3276,6 +3276,7 @@ CONFIG_XEN_PCIDEV_BACKEND_VPCI=y
 # CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER is not set
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 CONFIG_XEN_TPMDEV_BACKEND=m
+CONFIG_XEN_SCSI_BACKEND=m
 CONFIG_XEN_BLKDEV_FRONTEND=y
 CONFIG_XEN_NETDEV_FRONTEND=y
 CONFIG_XEN_GRANT_DEV=y
diff -r 557a4a0a5eac -r 66faefe721eb buildconfigs/linux-defconfig_xen_x86_64
--- a/buildconfigs/linux-defconfig_xen_x86_64   Fri May 30 19:08:50 2008 +0100
+++ b/buildconfigs/linux-defconfig_xen_x86_64   Mon Jun 02 09:58:27 2008 +0100
@@ -3106,6 +3106,7 @@ CONFIG_XEN_PCIDEV_BACKEND_PASS=y
 # CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER is not set
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 CONFIG_XEN_TPMDEV_BACKEND=m
+CONFIG_XEN_SCSI_BACKEND=m
 CONFIG_XEN_BLKDEV_FRONTEND=y
 CONFIG_XEN_NETDEV_FRONTEND=y
 CONFIG_XEN_GRANT_DEV=y
diff -r 557a4a0a5eac -r 66faefe721eb drivers/xen/Kconfig
--- a/drivers/xen/Kconfig       Fri May 30 19:08:50 2008 +0100
+++ b/drivers/xen/Kconfig       Mon Jun 02 09:58:27 2008 +0100
@@ -166,9 +166,17 @@ config XEN_TPMDEV_BACKEND
        help
          The TPM-device backend driver
 
+config XEN_SCSI_BACKEND
+       tristate "SCSI backend driver"
+       depends on XEN_BACKEND
+       default n
+       help
+         The SCSI backend driver allows the kernel to export its SCSI Devices
+         to other guests via a high-performance shared-memory interface.
+
 config XEN_BLKDEV_FRONTEND
        tristate "Block-device frontend driver"
-       default y
+       default m
        help
          The block-device frontend driver allows the kernel to access block
          devices mounted within another guest OS. Unless you are building a
diff -r 557a4a0a5eac -r 66faefe721eb drivers/xen/Makefile
--- a/drivers/xen/Makefile      Fri May 30 19:08:50 2008 +0100
+++ b/drivers/xen/Makefile      Mon Jun 02 09:58:27 2008 +0100
@@ -16,6 +16,7 @@ obj-$(CONFIG_XEN_PCIDEV_FRONTEND)     += pci
 obj-$(CONFIG_XEN_PCIDEV_FRONTEND)      += pcifront/
 obj-$(CONFIG_XEN_FRAMEBUFFER)          += fbfront/
 obj-$(CONFIG_XEN_KEYBOARD)             += fbfront/
+obj-$(CONFIG_XEN_SCSI_BACKEND)         += scsiback/
 obj-$(CONFIG_XEN_PRIVCMD)      += privcmd/
 obj-$(CONFIG_XEN_GRANT_DEV)    += gntdev/
 obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL)                += sfc_netutil/
diff -r 557a4a0a5eac -r 66faefe721eb drivers/xen/scsiback/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/Makefile     Mon Jun 02 09:58:27 2008 +0100
@@ -0,0 +1,4 @@
+obj-$(CONFIG_XEN_SCSI_BACKEND) := xen-scsibk.o
+
+xen-scsibk-y   := interface.o scsiback.o xenbus.o translate.o
+
diff -r 557a4a0a5eac -r 66faefe721eb drivers/xen/scsiback/common.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/common.h     Mon Jun 02 09:58:27 2008 +0100
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * Based on the blkback driver code.
+ *
+ * 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 __SCSIIF__BACKEND__COMMON_H__
+#define __SCSIIF__BACKEND__COMMON_H__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/blkdev.h>
+#include <linux/list.h>
+#include <linux/kthread.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_eh.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/pgalloc.h>
+#include <asm/delay.h>
+#include <xen/evtchn.h>
+#include <asm/hypervisor.h>
+#include <xen/gnttab.h>
+#include <xen/driver_util.h>
+#include <xen/xenbus.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/vscsiif.h>
+
+
+
+#define DPRINTK(_f, _a...)                     \
+       pr_debug("(file=%s, line=%d) " _f,      \
+                __FILE__ , __LINE__ , ## _a )
+
+struct ids_tuple {
+       unsigned int hst;               /* host    */
+       unsigned int chn;               /* channel */
+       unsigned int tgt;               /* target  */
+       unsigned int lun;               /* LUN     */
+};
+
+struct v2p_entry {
+       struct ids_tuple v;             /* translate from */
+       struct scsi_device *sdev;       /* translate to   */
+       struct list_head l;
+};
+
+struct vscsibk_info {
+       struct xenbus_device *dev;
+
+       domid_t domid;
+       unsigned int evtchn;
+       unsigned int irq;
+
+       struct vscsiif_back_ring  ring;
+       struct vm_struct *ring_area;
+       grant_handle_t shmem_handle;
+       grant_ref_t shmem_ref;
+
+       spinlock_t ring_lock;
+       atomic_t refcnt;
+
+       spinlock_t v2p_lock;
+       struct list_head v2p_entry_lists;
+
+       struct task_struct *kthread;
+       wait_queue_head_t waiting_to_free;
+       wait_queue_head_t wq;
+       unsigned int waiting_reqs;
+       struct page **mmap_pages;
+
+};
+
+typedef struct {
+       unsigned char act;
+       struct vscsibk_info *info;
+       struct scsi_device *sdev;
+
+       uint16_t rqid;
+       
+       vscsiif_request_t *ring_req;
+       
+       uint8_t nr_segments;
+       uint8_t cmnd[VSCSIIF_MAX_COMMAND_SIZE];
+       uint8_t cmd_len;
+
+       uint8_t sc_data_direction;
+       uint16_t timeout_per_command;
+       
+       uint32_t request_bufflen;
+       struct scatterlist *sgl;
+       grant_ref_t gref[VSCSIIF_SENSE_BUFFERSIZE];
+
+       int32_t rslt;
+       uint8_t sense_buffer[VSCSIIF_SENSE_BUFFERSIZE];
+
+       struct list_head free_list;
+} pending_req_t;
+
+
+
+#define scsiback_get(_b) (atomic_inc(&(_b)->refcnt))
+#define scsiback_put(_b)                               \
+       do {                                            \
+               if (atomic_dec_and_test(&(_b)->refcnt)) \
+                       wake_up(&(_b)->waiting_to_free);\
+       } while (0)
+
+#define VSCSIIF_TIMEOUT                (900*HZ)
+
+
+irqreturn_t scsiback_intr(int, void *, struct pt_regs *);
+int scsiback_init_sring(struct vscsibk_info *info,
+               unsigned long ring_ref, unsigned int evtchn);
+int scsiback_schedule(void *data);
+
+
+struct vscsibk_info *vscsibk_info_alloc(domid_t domid);
+void scsiback_free(struct vscsibk_info *info);
+void scsiback_disconnect(struct vscsibk_info *info);
+int __init scsiback_interface_init(void);
+void __exit scsiback_interface_exit(void);
+int scsiback_xenbus_init(void);
+void scsiback_xenbus_unregister(void);
+
+void scsiback_init_translation_table(struct vscsibk_info *info);
+
+int scsiback_add_translation_entry(struct vscsibk_info *info,
+                       struct scsi_device *sdev, struct ids_tuple *v);
+
+int scsiback_del_translation_entry(struct vscsibk_info *info,
+                               struct ids_tuple *v);
+struct scsi_device *scsiback_do_translation(struct vscsibk_info *info,
+                       struct ids_tuple *v);
+void scsiback_release_translation_entry(struct vscsibk_info *info);
+
+
+void scsiback_cmd_exec(pending_req_t *pending_req);
+
+#if 0 /*SAMPLE CODING(tentative)*//*emulation*/
+void scsiback_dispatch_emulation_cmdexec(vscsiif_request_t *ring_req,
+                               pending_req_t *pending_req);
+#endif
+
+
+#endif /* __SCSIIF__BACKEND__COMMON_H__ */
diff -r 557a4a0a5eac -r 66faefe721eb drivers/xen/scsiback/emulate.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/emulate.c    Mon Jun 02 09:58:27 2008 +0100
@@ -0,0 +1,275 @@
+/*
+ * Xen SCSI backend 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 <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include "comback.h"
+
+/* Following SCSI commands are not defined in scsi/scsi.h */
+#define EXTENDED_COPY          0x83    /* EXTENDED COPY command        */
+#define REPORT_ALIASES         0xa3    /* REPORT ALIASES command       */
+#define CHANGE_ALIASES         0xa4    /* CHANGE ALIASES command       */
+#define SET_PRIORITY           0xa4    /* SET PRIORITY command         */
+
+
+/*
+  The bitmap in order to control emulation.
+  (Bit 3 to 7 are reserved for future use.)
+*/
+#define VSCSIIF_NEED_CMD_EXEC          0x01    /* If this bit is set, cmd exec 
*/
+                                               /* is required.                 
*/
+#define VSCSIIF_NEED_EMULATE_REQBUF    0x02    /* If this bit is set, need     
*/
+                                               /* emulation reqest buff before 
*/
+                                               /* cmd exec.                    
*/
+#define VSCSIIF_NEED_EMULATE_RSPBUF    0x04    /* If this bit is set, need     
*/
+                                               /* emulation resp buff after    
*/
+                                               /* cmd exec.                    
*/
+
+/* Additional Sense Code (ASC) used */
+#define NO_ADDITIONAL_SENSE            0x0
+#define LOGICAL_UNIT_NOT_READY         0x4
+#define UNRECOVERED_READ_ERR           0x11
+#define PARAMETER_LIST_LENGTH_ERR      0x1a
+#define INVALID_OPCODE                 0x20
+#define ADDR_OUT_OF_RANGE              0x21
+#define INVALID_FIELD_IN_CDB           0x24
+#define INVALID_FIELD_IN_PARAM_LIST    0x26
+#define POWERON_RESET                  0x29
+#define SAVING_PARAMS_UNSUP            0x39
+#define THRESHOLD_EXCEEDED             0x5d
+#define LOW_POWER_COND_ON              0x5e
+
+
+
+/* Number os SCSI op_code      */
+#define VSCSI_MAX_SCSI_OP_CODE         256
+static unsigned char bitmap[VSCSI_MAX_SCSI_OP_CODE];
+
+/*
+  Emulation routines for each SCSI op_code.
+*/
+static void (*pre_function[MAX_SCSI_OP_CODE])(pending_request_t *, void *);
+static void (*post_function[MAX_SCSI_OP_CODE])(pending_request_t *, void *);
+
+
+static const int check_condition_result =
+               (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+
+static int __copy_to_sg(struct scatterlist *sg, unsigned int nr_sg,
+              void *buf, unsigned int buflen)
+{
+       void *from = buf;
+       void *to;
+       unsigned int from_rest = buflen;
+       unsigned int to_capa;
+       unsigned int copy_size;
+       unsigned int i;
+
+       for (i = 0; i < nr_sg; i++) {
+               if (sg->page == NULL) {
+                       printk(KERN_WARN "%s: inconsistent length field in "
+                              "scatterlist\n", __FUNCTION__);
+                       return -1;
+               }
+
+               to_capa  = sg->length;
+               copy_size = min_t(to_capa, from_rest);
+
+               to = page_to_virt(sg->page) + (sg->offset);
+               memcpy(to, from, copy_size);
+
+               from_rest  -= copy_size;
+               if (from_rest == 0) {
+                       return 0;
+               }
+               
+               sg++;
+               from += copy_size;
+       }
+
+       printk(KERN_WARN "%s: no space in scatterlist\n",
+              __FUNCTION__);
+       return -1;
+}
+
+static int __copy_from_sg(struct scatterlist *sg, unsigned int nr_sg,
+                void *buf, unsigned int buflen)
+{
+       void *from;
+       void *to = buf;
+       unsigned int from_rest;
+       unsigned int to_capa = buflen;
+       unsigned int copy_size;
+       unsigned int i;
+
+       for (i = 0; i < nr_sg; i++) {
+               if (sg->page == NULL) {
+                       printk(KERN_WARN "%s: inconsistent length field in "
+                              "scatterlist\n", __FUNCTION__);
+                       return -1;
+               }
+
+               from_rest = sg->length;
+               if ((from_rest > 0) && (to_capa < from_rest)) {
+                       printk(KERN_WARN
+                              "%s: no space in destination buffer\n",
+                              __FUNCTION__);
+                       return -1;
+               }
+               copy_size = from_rest;
+
+               from = page_to_virt(sg->page) + (sg->offset);
+               memcpy(to, from, copy_size);
+
+               to_capa  -= copy_size;
+               
+               sg++;
+               to += copy_size;
+       }
+
+       return 0;
+}
+
+
+static void scsiback_mk_sense_buffer(uint8_t *date, uint8_t key, uint8_t asc,
+                               utint_8 asq)
+{
+       data[0] = 0x70;  /* fixed, current */
+       data[2] = key;
+       data[7] = 0xa;    /* implies 18 byte sense buffer */
+       data[12] = asc;
+       data[13] = asq;
+}
+
+
+
+/* tuning point*/
+#define VSCSIIF_RLUN_ARR_SZ            2048
+
+/* quoted scsi_debug.c/resp_report_luns() */
+static void __report_luns(pending_request_t *pending_req, void *data)
+{
+       struct vscsibk_info *info   = pending_req->info;
+       unsigned int        channel = pending_req->sdev->channel;
+       unsigned int        target  = pending_req->sdev->id;
+       unsigned char *cmd = (unsigned char *)pending_req->cmnd;
+       
+       unsigned char rq_buff[VSCSIIF_RLUN_ARR_SZ];
+       unsigned char *sense_buf = pending_req->sense_buffer;
+       unsigned char alloc_len;
+       int select_report = (int)cmd[2];
+       int lun_cnt = 0;
+       
+       struct v2p_entry *entry;
+       struct list_head *head = &(info->v2p_entry_lists);
+       unsigned long flags;
+       
+       struct scsi_lun *one_lun;
+
+       alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
+       if ((alloc_len < 4) || (select_report != 0)) {
+               scsiback_mk_sense_buffer(pending_req->sense_buffer, 
ILLEGAL_REQUEST,
+                       INVALID_FIELD_IN_CDB, 0);
+               pending_req->rslt = check_condition_result;
+               return;
+       }
+
+       memset(rq_buff, 0, VSCSIIF_RLUN_ARR_SZ);
+       __copy_from_sg(pending_req->sgl, pending_req->nr_segments,
+               rq_buff, VSCSIIF_RLUN_ARR_SZ);
+
+
+       rq_buff[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
+       rq_buff[3] = (sizeof(struct scsi_lun) * num) & 0xff;
+
+
+       one_lun = (struct scsi_lun *) &rq_buff[8];
+       spin_lock_irqsave(&info->v2p_lock, flags);
+       list_for_each_entry(entry, head, l) {
+               if ((entry->v.chn == channel) &&
+                   (entry->v.tgt == target) {
+                       lun = entry->v.lun;
+                       upper = (lun >> 8) & 0x3f;
+                       if (upper)
+                               one_lun[lun_cnt].scsi_lun[0] = upper;
+                       one_lun[lun_cnt].scsi_lun[1] = lun & 0xff;
+                       lun_cnt++;
+               }
+       }
+       spin_unlock_irqrestore(&info->v2p_lock, flags);
+
+
+       lun_alloc = (unsigned char *)(one_lun + lun_cnt) - rq_buff;
+       
+       return fill_from_dev_buffer(scp, rq_buff,
+                                   min((int)alloc_len, lun_alloc));
+}
+
+
+
+int __pre_do_emulation(pending_request_t *pending_req, void *data)
+{
+       uint8_t op_code = pending_req->cmnd[0];
+
+       if ((bitmap[op_code] & VSCSIIF_NEED_EMULATE_REQBUF) &&
+           pre_function[op_code] != NULL) {
+               pre_function[op_code](pending_req, data);
+       }
+
+       /*
+           0: no need for native driver call, so should return immediately.
+           1: non emulation or should call native driver 
+              after modifing the request buffer.
+       */
+       return (bitmap[op_code] & VSCSIIF_NEED_CMD_EXEC);
+}
+
+void scsiback_rsp_emulation(pending_request_t *pending_req)
+{
+       uint8_t op_code = pending_req->cdb[0];
+
+       if ((bitmap[op_code] & VSCSIIF_NEED_EMULATE_RSPBUF) &&
+           post_function[op_code] != NULL) {
+               post_function[op_code](pending_req, NULL);
+       }
+
+       return;
+}
+
+
+void scsiback_req_emulation_or_cmdexec(pending_req_t *pending_req)
+{
+       if (__pre_do_emulation(pending_req, NULL))
+               scsiback_cmd_exec(pending_req);
+       else 
+               scsiback_do_resp_with_sense(pending_req);
+}
diff -r 557a4a0a5eac -r 66faefe721eb drivers/xen/scsiback/interface.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/interface.c  Mon Jun 02 09:58:27 2008 +0100
@@ -0,0 +1,184 @@
+/*
+ * interface management.
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * Based on the blkback driver code.
+ *
+ * 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 <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include "common.h"
+
+#include <xen/evtchn.h>
+#include <linux/kthread.h>
+
+
+static kmem_cache_t *scsiback_cachep;
+
+struct vscsibk_info *vscsibk_info_alloc(domid_t domid)
+{
+       struct vscsibk_info *info;
+
+       info = kmem_cache_alloc(scsiback_cachep, GFP_KERNEL);
+       if (!info)
+               return ERR_PTR(-ENOMEM);
+
+       memset(info, 0, sizeof(*info));
+       info->domid = domid;
+       spin_lock_init(&info->ring_lock);
+       atomic_set(&info->refcnt, 1);
+       init_waitqueue_head(&info->wq);
+       init_waitqueue_head(&info->waiting_to_free);
+
+       return info;
+}
+
+static int map_frontend_page( struct vscsibk_info *info,
+                               unsigned long ring_ref)
+{
+       struct gnttab_map_grant_ref op;
+       int err;
+
+       gnttab_set_map_op(&op, (unsigned long)info->ring_area->addr,
+                               GNTMAP_host_map, ring_ref,
+                               info->domid);
+
+       err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
+       BUG_ON(err);
+
+       if (op.status) {
+               printk(KERN_ERR "scsiback: Grant table operation failure !\n");
+               return op.status;
+       }
+
+       info->shmem_ref    = ring_ref;
+       info->shmem_handle = op.handle;
+
+       return 0;
+}
+
+static void unmap_frontend_page(struct vscsibk_info *info)
+{
+       struct gnttab_unmap_grant_ref op;
+       int err;
+
+       gnttab_set_unmap_op(&op, (unsigned long)info->ring_area->addr,
+                               GNTMAP_host_map, info->shmem_handle);
+
+       err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
+       BUG_ON(err);
+
+}
+
+int scsiback_init_sring(struct vscsibk_info *info,
+               unsigned long ring_ref, unsigned int evtchn)
+{
+       struct vscsiif_sring *sring;
+       int err;
+
+       if (info->irq) {
+               printk(KERN_ERR "scsiback: Already connected through?\n");
+               return 0;
+       }
+
+       info->ring_area = alloc_vm_area(PAGE_SIZE);
+       if (!info)
+               return -ENOMEM;
+
+       err = map_frontend_page(info, ring_ref);
+       if (err)
+               goto free_vm;
+
+       sring = (struct vscsiif_sring *) info->ring_area->addr;
+       BACK_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+       err = bind_interdomain_evtchn_to_irqhandler(
+                       info->domid, evtchn,
+                       scsiback_intr, 0, "vscsiif-backend", info);
+
+       if (err < 0)
+               goto unmap_page;
+               
+       info->irq = err;
+       
+       return 0;
+
+unmap_page:
+       unmap_frontend_page(info);
+free_vm:
+       free_vm_area(info->ring_area);
+
+       return err;
+}
+
+void scsiback_disconnect(struct vscsibk_info *info)
+{
+       if (info->kthread) {
+               kthread_stop(info->kthread);
+               info->kthread = NULL;
+       }
+
+       atomic_dec(&info->refcnt);
+       wait_event(info->waiting_to_free, atomic_read(&info->refcnt) == 0);
+       atomic_inc(&info->refcnt);
+
+       if (info->irq) {
+               unbind_from_irqhandler(info->irq, info);
+               info->irq = 0;
+       }
+
+       if (info->ring.sring) {
+               unmap_frontend_page(info);
+               free_vm_area(info->ring_area);
+               info->ring.sring = NULL;
+       }
+}
+
+void scsiback_free(struct vscsibk_info *info)
+{
+       if (atomic_dec_and_test(&info->refcnt))
+               kmem_cache_free(scsiback_cachep, info);
+}
+
+int __init scsiback_interface_init(void)
+{
+       scsiback_cachep = kmem_cache_create("vscsiif_cache",
+               sizeof(struct vscsibk_info), 0, 0, NULL, NULL);
+       if (!scsiback_cachep) {
+               printk(KERN_ERR "scsiback: can't init scsi cache\n");
+               return -ENOMEM;
+       }
+       
+       return 0;
+}
+
+void __exit scsiback_interface_exit(void)
+{
+       kmem_cache_destroy(scsiback_cachep);
+}
diff -r 557a4a0a5eac -r 66faefe721eb drivers/xen/scsiback/scsiback.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/scsiback.c   Mon Jun 02 09:58:27 2008 +0100
@@ -0,0 +1,734 @@
+/*
+ * Xen SCSI backend driver
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * Based on the blkback driver code.
+ *
+ * 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/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <xen/balloon.h>
+#include <asm/hypervisor.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_eh.h>
+
+#include "common.h"
+
+
+#define  NO_ASYNC  1 /*!aync*/
+
+struct list_head pending_free;
+DEFINE_SPINLOCK(pending_free_lock);
+DECLARE_WAIT_QUEUE_HEAD(pending_free_wq);
+
+int vscsiif_reqs = VSCSIIF_BACK_MAX_PENDING_REQS;
+module_param_named(reqs, vscsiif_reqs, int, 0);
+MODULE_PARM_DESC(reqs, "Number of scsiback requests to allocate");
+
+
+#define SCSIBACK_INVALID_HANDLE (~0)
+
+static pending_req_t *pending_reqs;
+static struct page **pending_pages;
+static grant_handle_t *pending_grant_handles;
+
+static int vaddr_pagenr(pending_req_t *req, int seg)
+{
+       return (req - pending_reqs) * VSCSIIF_SG_TABLESIZE + seg;
+}
+
+static unsigned long vaddr(pending_req_t *req, int seg)
+{
+       unsigned long pfn = page_to_pfn(pending_pages[vaddr_pagenr(req, seg)]);
+       return (unsigned long)pfn_to_kaddr(pfn);
+}
+
+#define pending_handle(_req, _seg) \
+       (pending_grant_handles[vaddr_pagenr(_req, _seg)])
+
+
+static void fast_flush_area(pending_req_t *req)
+{
+       struct gnttab_unmap_grant_ref unmap[VSCSIIF_SG_TABLESIZE];
+       unsigned int i, invcount = 0;
+       grant_handle_t handle;
+       int err;
+
+       if (req->nr_segments) {
+               for (i = 0; i < req->nr_segments; i++) {
+                       handle = pending_handle(req, i);
+                       if (handle == SCSIBACK_INVALID_HANDLE)
+                               continue;
+                       gnttab_set_unmap_op(&unmap[i], vaddr(req, i),
+                                               GNTMAP_host_map, handle);
+                       pending_handle(req, i) = SCSIBACK_INVALID_HANDLE;
+                       invcount++;
+               }
+
+               err = HYPERVISOR_grant_table_op(
+                       GNTTABOP_unmap_grant_ref, unmap, invcount);
+               BUG_ON(err);
+               kfree(req->sgl);
+       }
+
+       return;
+}
+
+
+static pending_req_t * alloc_req(struct vscsibk_info *info)
+{
+       pending_req_t *req = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pending_free_lock, flags);
+       if (!list_empty(&pending_free)) {
+               req = list_entry(pending_free.next, pending_req_t, free_list);
+               list_del(&req->free_list);
+       }
+       spin_unlock_irqrestore(&pending_free_lock, flags);
+       return req;
+}
+
+
+static void free_req(pending_req_t *req)
+{
+       unsigned long flags;
+       int was_empty;
+
+       spin_lock_irqsave(&pending_free_lock, flags);
+       was_empty = list_empty(&pending_free);
+       list_add(&req->free_list, &pending_free);
+       spin_unlock_irqrestore(&pending_free_lock, flags);
+       if (was_empty)
+               wake_up(&pending_free_wq);
+}
+
+
+static void scsiback_notify_work(struct vscsibk_info *info)
+{
+       info->waiting_reqs = 1;
+       wake_up(&info->wq);
+}
+
+static void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result,
+                               pending_req_t *pending_req)
+{
+       vscsiif_response_t *ring_res;
+       struct vscsibk_info *info = pending_req->info;
+       int notify;
+       int more_to_do = 1;
+       unsigned long flags;
+
+       DPRINTK("%s\n",__FUNCTION__);
+
+       spin_lock_irqsave(&info->ring_lock, flags);
+
+       rmb();
+       ring_res = RING_GET_RESPONSE(&info->ring, info->ring.rsp_prod_pvt);
+       info->ring.rsp_prod_pvt++;
+
+       ring_res->rslt   = result;
+       ring_res->rqid   = pending_req->rqid;
+
+       if (sense_buffer != NULL) {
+               memcpy(ring_res->sense_buffer, sense_buffer,
+                               VSCSIIF_SENSE_BUFFERSIZE);
+               ring_res->sense_len = VSCSIIF_SENSE_BUFFERSIZE;
+       } else {
+               ring_res->sense_len = 0;
+       }
+
+       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&info->ring, notify);
+       if (info->ring.rsp_prod_pvt == info->ring.req_cons) {
+               RING_FINAL_CHECK_FOR_REQUESTS(&info->ring, more_to_do);
+       } else if (RING_HAS_UNCONSUMED_REQUESTS(&info->ring)) {
+               more_to_do = 1;
+       }
+       
+       spin_unlock_irqrestore(&info->ring_lock, flags);
+
+       if (more_to_do)
+               scsiback_notify_work(info);
+
+       if (notify)
+               notify_remote_via_irq(info->irq);
+
+       scsiback_put(pending_req->info);
+       free_req(pending_req);
+}
+
+#ifdef NO_ASYNC /*!async*/
+static void scsiback_cmd_done(struct request *req, int errors)
+{
+       pending_req_t *pending_req = req->end_io_data;
+       struct scsi_device *sdev = pending_req->sdev;
+       unsigned char *sense_buffer;
+
+       sense_buffer = req->sense;
+
+#else
+static void scsiback_cmd_done(void *data, char *sense_buffer,
+                               int errors, int resid)
+{
+       pending_req_t *pending_req = data;
+       struct scsi_device *sdev = pending_req->sdev;
+
+       DPRINTK("%s\n",__FUNCTION__);
+#endif
+
+       if ((errors != 0) && (pending_req->cmnd[0] != TEST_UNIT_READY)) {
+
+               printk(KERN_ERR "scsiback: %d:%d:%d:%d ",sdev->host->host_no,
+                               sdev->channel, sdev->id, sdev->lun);
+               printk(KERN_ERR "status = 0x%02x, message = 0x%02x, host = 
0x%02x, driver = 0x%02x\n",
+                               status_byte(errors), msg_byte(errors),
+                               host_byte(errors), driver_byte(errors));
+
+               printk(KERN_ERR "scsiback: cmnd[0]=0x%02X nr_segments=%d\n",
+                               pending_req->cmnd[0],
+                               pending_req->nr_segments);
+
+               if (CHECK_CONDITION & status_byte(errors))
+                       __scsi_print_sense("scsiback", sense_buffer, 
SCSI_SENSE_BUFFERSIZE);
+       }
+
+#if 0 /*SAMPLE CODING(tentative)*//*emulation*/
+       scsiback_rsp_emulation(pending_req);
+#endif
+       fast_flush_area(pending_req);
+       scsiback_do_resp_with_sense(sense_buffer, errors, pending_req);
+
+
+#ifdef NO_ASYNC /*!async*/
+       __blk_put_request(req->q, req);
+#endif
+}
+
+
+static int scsiback_gnttab_data_map(vscsiif_request_t *ring_req,
+                                       pending_req_t *pending_req)
+{
+       u32 flags;
+       int write;
+       int i, err = 0;
+       unsigned int data_len = 0;
+       struct gnttab_map_grant_ref map[VSCSIIF_SG_TABLESIZE];
+       struct vscsibk_info *info   = pending_req->info;
+
+       int data_dir = (int)pending_req->sc_data_direction;
+       unsigned int nr_segments = (unsigned int)pending_req->nr_segments;
+
+       write = (data_dir == DMA_TO_DEVICE);
+
+       if (nr_segments) {
+               /* free of (sgl) in fast_flush_area()*/
+               pending_req->sgl = kmalloc(sizeof(struct scatterlist) * 
nr_segments,
+                                               GFP_KERNEL);
+               if (!pending_req->sgl) {
+                       printk(KERN_ERR "scsiback: %s: kmalloc() error.\n", 
__FUNCTION__);
+                       return -ENOMEM;
+               }
+
+               for (i = 0; i < nr_segments; i++) {
+                       flags = GNTMAP_host_map;
+                       if (write)
+                               flags |= GNTMAP_readonly;
+                       gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags,
+                                               ring_req->seg[i].gref,
+                                               info->domid);
+               }
+
+               err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, 
nr_segments);
+               BUG_ON(err);
+
+               for (i = 0; i < nr_segments; i++) {
+                       if (unlikely(map[i].status != 0)) {
+                               printk(KERN_ERR "scsiback: invalid buffer -- 
could not remap it\n");
+                               map[i].handle = SCSIBACK_INVALID_HANDLE;
+                               err |= 1;
+                       }
+
+                       pending_handle(pending_req, i) = map[i].handle;
+
+                       if (err)
+                               continue;
+
+                       set_phys_to_machine(__pa(vaddr(
+                               pending_req, i)) >> PAGE_SHIFT,
+                               FOREIGN_FRAME(map[i].dev_bus_addr >> 
PAGE_SHIFT));
+
+                       pending_req->sgl[i].page   = 
virt_to_page(vaddr(pending_req, i));
+                       pending_req->sgl[i].offset = ring_req->seg[i].offset;
+                       pending_req->sgl[i].length = ring_req->seg[i].length;
+                       data_len += pending_req->sgl[i].length;
+               }
+
+               if (err)
+                       goto fail_flush;
+       }
+       
+       pending_req->request_bufflen = data_len;
+       
+       return 0;
+       
+fail_flush:
+       fast_flush_area(pending_req);
+       return -ENOMEM;
+}
+
+
+#ifdef NO_ASYNC /*!async*/
+
+/* quoted scsi_lib.c/scsi_merge_bio */
+static int scsiback_merge_bio(struct request *rq, struct bio *bio)
+{
+       struct request_queue *q = rq->q;
+
+       bio->bi_flags &= ~(1 << BIO_SEG_VALID);
+       if (rq_data_dir(rq) == WRITE)
+               bio->bi_rw |= (1 << BIO_RW);
+
+       blk_queue_bounce(q, &bio);
+
+       if (!rq->bio)
+               blk_rq_bio_prep(q, rq, bio);
+       else if (!q->back_merge_fn(q, rq, bio))
+               return -EINVAL;
+       else {
+               rq->biotail->bi_next = bio;
+               rq->biotail          = bio;
+               rq->hard_nr_sectors += bio_sectors(bio);
+               rq->nr_sectors       = rq->hard_nr_sectors;
+       }
+
+       return 0;
+}
+
+
+/* quoted scsi_lib.c/scsi_bi_endio */
+static int scsiback_bi_endio(struct bio *bio, unsigned int bytes_done, int 
error)
+{
+       if (bio->bi_size)
+               return 1;
+
+       bio_put(bio);
+       return 0;
+}
+
+
+
+/* quoted scsi_lib.c/scsi_req_map_sg . */
+static int requset_map_sg(struct request *rq, pending_req_t *pending_req, 
unsigned int count)
+{
+       struct request_queue *q = rq->q;
+       int nr_pages;
+       unsigned int nsegs = count;
+
+       unsigned int data_len = 0, len, bytes, off;
+       struct page *page;
+       struct bio *bio = NULL;
+       int i, err, nr_vecs = 0;
+
+       for (i = 0; i < nsegs; i++) {
+               page = pending_req->sgl[i].page;
+               off = (unsigned int)pending_req->sgl[i].offset;
+               len = (unsigned int)pending_req->sgl[i].length;
+               data_len += len;
+
+               nr_pages = (len + off + PAGE_SIZE - 1) >> PAGE_SHIFT;
+               while (len > 0) {
+                       bytes = min_t(unsigned int, len, PAGE_SIZE - off);
+
+                       if (!bio) {
+                               nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages);
+                               nr_pages -= nr_vecs;
+                               bio = bio_alloc(GFP_KERNEL, nr_vecs);
+                               if (!bio) {
+                                       err = -ENOMEM;
+                                       goto free_bios;
+                               }
+                               bio->bi_end_io = scsiback_bi_endio;
+                       }
+
+                       if (bio_add_pc_page(q, bio, page, bytes, off) !=
+                                               bytes) {
+                               bio_put(bio);
+                               err = -EINVAL;
+                               goto free_bios;
+                       }
+
+                       if (bio->bi_vcnt >= nr_vecs) {
+                               err = scsiback_merge_bio(rq, bio);
+                               if (err) {
+                                       bio_endio(bio, bio->bi_size, 0);
+                                       goto free_bios;
+                               }
+                               bio = NULL;
+                       }
+
+                       page++;
+                       len -= bytes;
+                       off = 0;
+               }
+       }
+
+       rq->buffer   = rq->data = NULL;
+       rq->data_len = data_len;
+
+       return 0;
+
+free_bios:
+       while ((bio = rq->bio) != NULL) {
+               rq->bio = bio->bi_next;
+               /*
+                * call endio instead of bio_put incase it was bounced
+                */
+               bio_endio(bio, bio->bi_size, 0);
+       }
+
+       return err;
+}
+
+#endif
+
+void scsiback_cmd_exec(pending_req_t *pending_req)
+{
+       int err;
+
+       int cmd_len  = (int)pending_req->cmd_len;
+       int data_dir = (int)pending_req->sc_data_direction;
+       unsigned int nr_segments = (unsigned int)pending_req->nr_segments;
+       unsigned int timeout;
+#ifdef NO_ASYNC /*!async*/
+       struct request *rq;
+       int write;
+#else
+       unsigned int data_len = pending_req->request_bufflen;
+#endif
+
+       DPRINTK("%s\n",__FUNCTION__);
+
+       /* because it doesn't timeout backend earlier than frontend.*/
+       if (pending_req->timeout_per_command)
+               timeout = (pending_req->timeout_per_command * HZ * 2);
+       else
+               timeout = VSCSIIF_TIMEOUT;
+
+#ifdef NO_ASYNC /*!async*/
+       err = 0;
+       write = (data_dir == DMA_TO_DEVICE);
+       rq = blk_get_request(pending_req->sdev->request_queue, write, 
GFP_KERNEL);
+
+       rq->flags  |= REQ_BLOCK_PC;
+       rq->cmd_len = cmd_len;
+       memcpy(rq->cmd, pending_req->cmnd, cmd_len);
+
+       memset(pending_req->sense_buffer, 0, VSCSIIF_SENSE_BUFFERSIZE);
+       rq->sense       = pending_req->sense_buffer;
+       rq->sense_len = 0;
+
+       rq->retries   = 0;
+       rq->timeout   = timeout;
+       rq->end_io_data = pending_req;
+
+       if (nr_segments) {
+
+               if (requset_map_sg(rq, pending_req, nr_segments)) {
+                       printk(KERN_ERR "scsiback: SG Request Map Error\n");
+                       return;
+               }
+       }
+
+       blk_execute_rq_nowait(rq->q, NULL, rq, 1, scsiback_cmd_done);
+
+#else   /*async*/
+       /* not allowed to retry in backend.                   */
+       /* timeout of backend is longer than that of brontend.*/
+       err = scsi_execute_async(pending_req->sdev, &(pending_req->cmnd[0]),
+               cmd_len, data_dir, &(pending_req->sgl[0]), data_len, 
nr_segments, timeout, 0,
+               pending_req, scsiback_cmd_done, GFP_ATOMIC);
+               
+#endif /*!async*/
+
+       if (err) 
+               scsiback_do_resp_with_sense(NULL, (DRIVER_ERROR << 24), 
pending_req);
+
+       return ;
+}
+
+
+static void scsiback_device_reset_exec(pending_req_t *pending_req)
+{
+       struct vscsibk_info *info = pending_req->info;
+       int err;
+       struct scsi_device *sdev = pending_req->sdev;
+
+       scsiback_get(info);
+
+       err = scsi_reset_provider(sdev, SCSI_TRY_RESET_DEVICE);
+
+       scsiback_do_resp_with_sense(NULL, err, pending_req);
+
+       notify_remote_via_irq(info->irq);
+       return;
+}
+
+
+irqreturn_t scsiback_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+       scsiback_notify_work((struct vscsibk_info *)dev_id);
+       return IRQ_HANDLED;
+}
+
+static int prepare_pending_reqs(struct vscsibk_info *info,
+               vscsiif_request_t *ring_req, pending_req_t *pending_req)
+{
+       struct scsi_device *sdev;
+       struct ids_tuple vir;
+       int err = -EINVAL;
+
+       DPRINTK("%s\n",__FUNCTION__);
+
+       pending_req->rqid       = ring_req->rqid;
+       pending_req->act        = ring_req->act;
+
+       pending_req->info       = info;
+
+       vir.chn = ring_req->channel;
+       vir.tgt = ring_req->id;
+       vir.lun = ring_req->lun;
+
+       sdev = scsiback_do_translation(info, &vir);
+       if (!sdev) {
+               pending_req->sdev = NULL;
+               printk(KERN_ERR "scsiback: doesn't exist.\n");
+               err = -ENODEV;
+               goto invald_value;
+       }
+       pending_req->sdev = sdev;
+
+       /* request range check from frontend */
+       if ((ring_req->sc_data_direction != DMA_BIDIRECTIONAL) &&
+               (ring_req->sc_data_direction != DMA_TO_DEVICE) &&
+               (ring_req->sc_data_direction != DMA_FROM_DEVICE) &&
+               (ring_req->sc_data_direction != DMA_NONE)) {
+               printk(KERN_ERR "scsiback: invalid parameter data_dir = %d\n",
+                       ring_req->sc_data_direction);
+               err = -EINVAL;
+               goto invald_value;
+       }
+
+       if (ring_req->nr_segments > VSCSIIF_SG_TABLESIZE) {
+               printk(KERN_ERR "scsiback: invalid parameter nr_seg = %d\n",
+                       ring_req->nr_segments);
+               err = -EINVAL;
+               goto invald_value;
+       }
+       pending_req->nr_segments = ring_req->nr_segments;
+
+       if (ring_req->cmd_len > VSCSIIF_MAX_COMMAND_SIZE) {
+               printk(KERN_ERR "scsiback: invalid parameter cmd_len = %d\n",
+                       ring_req->cmd_len);
+               err = -EINVAL;
+               goto invald_value;
+       }
+       memcpy(pending_req->cmnd, ring_req->cmnd, ring_req->cmd_len);
+       pending_req->cmd_len = ring_req->cmd_len;
+       
+       pending_req->sc_data_direction = ring_req->sc_data_direction;
+       pending_req->timeout_per_command = ring_req->timeout_per_command;
+
+       if(scsiback_gnttab_data_map(ring_req, pending_req)) {
+               printk(KERN_ERR "scsiback: invalid buffer\n");
+               err = -EINVAL;
+               goto invald_value;
+       }
+
+       return 0;
+
+invald_value:
+       return err;
+}
+
+
+static int scsiback_do_cmd_fn(struct vscsibk_info *info)
+{
+       struct vscsiif_back_ring *ring = &info->ring;
+       vscsiif_request_t  *ring_req;
+
+       pending_req_t *pending_req;
+       RING_IDX rc, rp;
+       int err, more_to_do = 0;
+
+       DPRINTK("%s\n",__FUNCTION__);
+
+       rc = ring->req_cons;
+       rp = ring->sring->req_prod;
+       rmb();
+
+       while ((rc != rp)) {
+               if (RING_REQUEST_CONS_OVERFLOW(ring, rc))
+                       break;
+               pending_req = alloc_req(info);
+               if (NULL == pending_req) {
+                       more_to_do = 1;
+                       break;
+               }
+
+               ring_req = RING_GET_REQUEST(ring, rc);
+               ring->req_cons = ++rc;
+
+               scsiback_get(info);
+               err = prepare_pending_reqs(info, ring_req,
+                                               pending_req);
+               if (err == -EINVAL) {
+                       scsiback_do_resp_with_sense(NULL, (DRIVER_ERROR << 24),
+                               pending_req);
+                       continue;
+               } else if (err == -ENODEV) {
+                       scsiback_do_resp_with_sense(NULL, (DID_NO_CONNECT << 
16),
+                               pending_req);                   
+               }
+
+               if (pending_req->act == VSCSIIF_ACT_SCSI_CDB) {
+#if 0 /*SAMPLE CODING(tentative)*//*emulation*/
+                       scsiback_req_emulation_or_through(pending_req);
+#else
+                       scsiback_cmd_exec(pending_req);
+#endif
+               } else if (pending_req->act == VSCSIIF_ACT_SCSI_RESET) {
+                       scsiback_device_reset_exec(pending_req);
+               } else {
+                       printk(KERN_ERR "scsiback: invalid parameter for 
request\n");
+                       scsiback_do_resp_with_sense(NULL, (DRIVER_ERROR << 24),
+                               pending_req);
+                       continue;
+               }
+       }
+
+       if (RING_HAS_UNCONSUMED_REQUESTS(ring))
+               more_to_do = 1;
+
+       return more_to_do;
+}
+
+
+int scsiback_schedule(void *data)
+{
+       struct vscsibk_info *info = (struct vscsibk_info *)data;
+
+       DPRINTK("%s\n",__FUNCTION__);
+
+       scsiback_get(info);
+
+       while (!kthread_should_stop()) {
+               wait_event_interruptible(
+                       info->wq,
+                       info->waiting_reqs || kthread_should_stop());
+               wait_event_interruptible(
+                       pending_free_wq,
+                       !list_empty(&pending_free) || kthread_should_stop());
+
+               info->waiting_reqs = 0;
+               smp_mb();
+
+               if (scsiback_do_cmd_fn(info))
+                       info->waiting_reqs = 1;
+       }
+
+       info->kthread = NULL;
+       scsiback_put(info);
+
+       return 0;
+}
+
+
+static int __init scsiback_init(void)
+{
+       int i, mmap_pages;
+
+       if (!is_running_on_xen())
+               return -ENODEV;
+
+       mmap_pages = vscsiif_reqs * VSCSIIF_SG_TABLESIZE;
+
+       pending_reqs          = kmalloc(sizeof(pending_reqs[0]) *
+                                       vscsiif_reqs, GFP_KERNEL);
+       pending_grant_handles = kmalloc(sizeof(pending_grant_handles[0]) *
+                                       mmap_pages, GFP_KERNEL);
+       pending_pages         = alloc_empty_pages_and_pagevec(mmap_pages);
+
+       if (!pending_reqs || !pending_grant_handles || !pending_pages)
+               goto out_of_memory;
+
+       for (i = 0; i < mmap_pages; i++)
+               pending_grant_handles[i] = SCSIBACK_INVALID_HANDLE;
+
+       if (scsiback_interface_init() < 0)
+               goto out_of_memory;
+
+       memset(pending_reqs, 0, sizeof(pending_reqs));
+       INIT_LIST_HEAD(&pending_free);
+
+       for (i = 0; i < vscsiif_reqs; i++)
+               list_add_tail(&pending_reqs[i].free_list, &pending_free);
+
+       if (scsiback_xenbus_init())
+               goto out_of_memory;
+
+       return 0;
+
+out_of_memory:
+       kfree(pending_reqs);
+       kfree(pending_grant_handles);
+       free_empty_pages_and_pagevec(pending_pages, mmap_pages);
+       printk(KERN_ERR "scsiback: %s: out of memory\n", __FUNCTION__);
+       return -ENOMEM;
+}
+
+static void __exit scsiback_exit(void)
+{
+       scsiback_xenbus_unregister();
+       scsiback_interface_exit();
+       kfree(pending_reqs);
+       kfree(pending_grant_handles);
+       free_empty_pages_and_pagevec(pending_pages, (vscsiif_reqs * 
VSCSIIF_SG_TABLESIZE));
+
+}
+
+module_init(scsiback_init);
+module_exit(scsiback_exit);
+
+MODULE_DESCRIPTION("Xen SCSI backend driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff -r 557a4a0a5eac -r 66faefe721eb drivers/xen/scsiback/translate.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/translate.c  Mon Jun 02 09:58:27 2008 +0100
@@ -0,0 +1,166 @@
+/*
+ * Xen SCSI backend 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/list.h>
+#include <linux/gfp.h>
+
+#include "common.h"
+
+/*
+  Initialize the translation entry list
+*/
+void scsiback_init_translation_table(struct vscsibk_info *info)
+{
+       INIT_LIST_HEAD(&info->v2p_entry_lists);
+       spin_lock_init(&info->v2p_lock);
+}
+
+
+/*
+  Add a new translation entry
+*/
+int scsiback_add_translation_entry(struct vscsibk_info *info,
+                       struct scsi_device *sdev, struct ids_tuple *v)
+{
+       int err = 0;
+       struct v2p_entry *entry;
+       struct v2p_entry *new;
+       struct list_head *head = &(info->v2p_entry_lists);
+       unsigned long flags;
+       
+       spin_lock_irqsave(&info->v2p_lock, flags);
+
+       /* Check double assignment to identical virtual ID */
+       list_for_each_entry(entry, head, l) {
+               if ((entry->v.chn == v->chn) &&
+                   (entry->v.tgt == v->tgt) &&
+                   (entry->v.lun == v->lun)) {
+                       printk(KERN_WARNING "scsiback: Virtual ID is already 
used. "
+                              "Assignment was not performed.\n");
+                       err = -EEXIST;
+                       goto out;
+               }
+
+       }
+
+       /* Create a new translation entry and add to the list */
+       if ((new = kmalloc(sizeof(struct v2p_entry), GFP_KERNEL)) == NULL) {
+               printk(KERN_ERR "scsiback: %s: kmalloc() error.\n", 
__FUNCTION__);
+               err = -ENOMEM;
+               goto out;
+       }
+       new->v = *v;
+       new->sdev = sdev;
+       list_add(&new->l, head);
+
+out:   
+       spin_unlock_irqrestore(&info->v2p_lock, flags);
+       return err;
+}
+
+
+/*
+  Delete the translation entry specfied
+*/
+int scsiback_del_translation_entry(struct vscsibk_info *info,
+                               struct ids_tuple *v)
+{
+       struct v2p_entry *entry;
+       struct list_head *head = &(info->v2p_entry_lists);
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->v2p_lock, flags);
+       /* Find out the translation entry specified */
+       list_for_each_entry(entry, head, l) {
+               if ((entry->v.chn == v->chn) &&
+                   (entry->v.tgt == v->tgt) &&
+                   (entry->v.lun == v->lun)) {
+                       goto found;
+               }
+       }
+
+       spin_unlock_irqrestore(&info->v2p_lock, flags);
+       return 0;
+
+found:
+       /* Delete the translation entry specfied */
+       list_del(&entry->l);
+       kfree(entry);
+
+       spin_unlock_irqrestore(&info->v2p_lock, flags);
+       return 0;
+}
+
+
+/*
+  Perform virtual to physical translation
+*/
+struct scsi_device *scsiback_do_translation(struct vscsibk_info *info,
+                       struct ids_tuple *v)
+{
+       struct v2p_entry *entry;
+       struct list_head *head = &(info->v2p_entry_lists);
+       struct scsi_device *sdev = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->v2p_lock, flags);
+       list_for_each_entry(entry, head, l) {
+               if ((entry->v.chn == v->chn) &&
+                   (entry->v.tgt == v->tgt) &&
+                   (entry->v.lun == v->lun)) {
+                       sdev = entry->sdev;
+                       goto out;
+               }
+       }
+out:
+       spin_unlock_irqrestore(&info->v2p_lock, flags);
+       return sdev;
+}
+
+
+/*
+  Release the translation entry specfied
+*/
+void scsiback_release_translation_entry(struct vscsibk_info *info)
+{
+       struct v2p_entry *entry, *tmp;
+       struct list_head *head = &(info->v2p_entry_lists);
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->v2p_lock, flags);
+       list_for_each_entry_safe(entry, tmp, head, l) {
+               list_del(&entry->l);
+               kfree(entry);
+       }
+
+       spin_unlock_irqrestore(&info->v2p_lock, flags);
+       return;
+
+}
diff -r 557a4a0a5eac -r 66faefe721eb drivers/xen/scsiback/xenbus.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/xenbus.c     Mon Jun 02 09:58:27 2008 +0100
@@ -0,0 +1,365 @@
+/*
+ * Xen SCSI backend driver
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * Based on the blkback driver code.
+ *
+ * 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 <stdarg.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+
+#include "common.h"
+
+struct backend_info
+{
+       struct xenbus_device *dev;
+       struct vscsibk_info *info;
+};
+
+
+static int __vscsiif_name(struct backend_info *be, char *buf)
+{
+       struct xenbus_device *dev = be->dev;
+       unsigned int domid, id;
+
+       sscanf(dev->nodename, "backend/vscsi/%u/%u", &domid, &id);
+       snprintf(buf, TASK_COMM_LEN, "vscsi.%u.%u", be->info->domid, id);
+
+       return 0;
+}
+
+static int scsiback_map(struct backend_info *be)
+{
+       struct xenbus_device *dev = be->dev;
+       unsigned long ring_ref;
+       unsigned int evtchn;
+       int err;
+       char name[TASK_COMM_LEN];
+
+       err = xenbus_gather(XBT_NIL, dev->otherend,
+                       "ring-ref", "%lu", &ring_ref,
+                       "event-channel", "%u", &evtchn, NULL);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "reading %s ring", dev->otherend);
+               return err;
+       }
+
+       err = scsiback_init_sring(be->info, ring_ref, evtchn);
+       if (err)
+               return err;
+
+       err = __vscsiif_name(be, name);
+       if (err) {
+               xenbus_dev_error(dev, err, "get scsiback dev name");
+               return err;
+       }
+
+       be->info->kthread = kthread_run(scsiback_schedule, be->info, name);
+       if (IS_ERR(be->info->kthread)) {
+               err = PTR_ERR(be->info->kthread);
+               be->info->kthread = NULL;
+               xenbus_dev_error(be->dev, err, "start vscsiif");
+               return err;
+       }
+
+       return 0;
+}
+
+
+struct scsi_device *scsiback_get_scsi_device(struct ids_tuple *phy)
+{
+       struct Scsi_Host *shost;
+       struct scsi_device *sdev = NULL;
+
+       shost = scsi_host_lookup(phy->hst);
+       if (IS_ERR(shost)) {
+               printk(KERN_ERR "scsiback: host%d doesn't exist.\n",
+                       phy->hst);
+               goto invald_value;
+       }
+       sdev   = scsi_device_lookup(shost, phy->chn, phy->tgt, phy->lun);
+       if (!sdev) {
+               printk(KERN_ERR "scsiback: %d:%d:%d:%d doesn't exist.\n",
+                       phy->hst, phy->chn, phy->tgt, phy->lun);
+               goto invald_value;
+       }
+
+invald_value:
+       return (sdev);
+}
+
+#define VSCSIBACK_OP_ADD_OR_DEL_LUN    1
+
+static void scsiback_do_lun_hotplug(struct backend_info *be, int op)
+{
+       int i, err = 0;
+       struct ids_tuple phy, vir;
+       int device_state;
+       char str[64], state_str[64];
+       char **dir;
+       unsigned int dir_n = 0;
+       struct xenbus_device *dev = be->dev;
+       struct scsi_device *sdev;
+       struct xenbus_transaction xbt;
+
+
+       err = xenbus_transaction_start(&xbt);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "starting transaction");
+       }
+
+       dir = xenbus_directory(xbt, dev->nodename, "vscsi-devs", &dir_n);
+       if (IS_ERR(dir))
+               return;
+
+       for (i = 0; i < dir_n; i++) {
+               
+               /* read status */
+               snprintf(state_str, sizeof(state_str), "vscsi-devs/%s/state", 
dir[i]);
+               err = xenbus_scanf(xbt, dev->nodename, state_str, "%u",
+                       &device_state);
+               if (XENBUS_EXIST_ERR(err))
+                       continue;
+
+               /* physical SCSI device */
+               snprintf(str, sizeof(str), "vscsi-devs/%s/p-dev", dir[i]);
+               err = xenbus_scanf(xbt, dev->nodename, str,
+                       "%u:%u:%u:%u", &phy.hst, &phy.chn, &phy.tgt, &phy.lun);
+               if (XENBUS_EXIST_ERR(err)) {
+                       xenbus_printf(xbt, dev->nodename, state_str,
+                                       "%d", XenbusStateClosing);
+                       continue;
+               }
+
+               /* virtual SCSI device */
+               snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", dir[i]);
+               err = xenbus_scanf(xbt, dev->nodename, str,
+                       "%u:%u:%u:%u", &vir.hst, &vir.chn, &vir.tgt, &vir.lun);
+               if (XENBUS_EXIST_ERR(err)) {
+                       xenbus_printf(xbt, dev->nodename, state_str,
+                                       "%d", XenbusStateClosing);
+                       continue;
+               }
+
+               switch (op) {
+               case VSCSIBACK_OP_ADD_OR_DEL_LUN:
+                       if (device_state == XenbusStateInitialising) {
+                               sdev = scsiback_get_scsi_device(&phy);
+                               if (!sdev) {
+                                       xenbus_printf(xbt, dev->nodename, 
state_str,
+                                                       "%d", 
XenbusStateClosing);
+                               } else {
+                                       err = 
scsiback_add_translation_entry(be->info, sdev, &vir);
+                                       if (!err) {
+                                               xenbus_printf(xbt, 
dev->nodename, state_str,
+                                                       "%d", 
XenbusStateInitialised);
+                                       } else {
+                                               xenbus_printf(xbt, 
dev->nodename, state_str,
+                                                       "%d", 
XenbusStateClosing);                                              
+                                       }
+                               }
+                       }
+
+                       if (device_state == XenbusStateClosing) {
+                               err = scsiback_del_translation_entry(be->info, 
&vir);
+                               if (err)
+                                       goto fail;
+                               else {
+                                       xenbus_printf(xbt, dev->nodename, 
state_str,
+                                               "%d", XenbusStateClosed);       
                                        
+                               }
+                       }
+
+                       break;
+               /*When it is necessary, processing is added here.*/
+               default:
+                       break;
+               }
+       }
+
+       xenbus_transaction_end(xbt, 0);
+       kfree(dir);
+       return ;
+fail :
+       xenbus_transaction_end(xbt, 1);
+       kfree(dir);
+       xenbus_dev_fatal(dev, err, "read or write %s ", str);
+       return;
+}
+
+
+static void scsiback_frontend_changed(struct xenbus_device *dev,
+                                       enum xenbus_state frontend_state)
+{
+       struct backend_info *be = dev->dev.driver_data;
+       int err;
+
+       switch (frontend_state) {
+       case XenbusStateInitialising:
+               break;
+       case XenbusStateInitialised:
+               err = scsiback_map(be);
+               if (err)
+                       break;
+
+               scsiback_do_lun_hotplug(be, VSCSIBACK_OP_ADD_OR_DEL_LUN);
+               err = xenbus_switch_state(dev, XenbusStateConnected);
+               if (err)
+                       xenbus_dev_fatal(dev, err, "switching to Connected 
state",
+                                       dev->nodename);
+               break;
+       case XenbusStateConnected:
+               if (dev->state == XenbusStateConnected)
+                       break;
+                       
+               err = xenbus_switch_state(dev, XenbusStateConnected);
+               if (err)
+                       xenbus_dev_fatal(dev, err, "switching to Connected 
state",
+                                       dev->nodename);
+               break;
+
+       case XenbusStateClosing:
+               scsiback_disconnect(be->info);
+               xenbus_switch_state(dev, XenbusStateClosing);
+               break;
+
+       case XenbusStateClosed:
+               xenbus_switch_state(dev, XenbusStateClosed);
+               if (xenbus_dev_is_online(dev))
+                       break;
+
+       case XenbusStateReconfiguring:
+               scsiback_do_lun_hotplug(be, VSCSIBACK_OP_ADD_OR_DEL_LUN);
+               err = xenbus_switch_state(dev, XenbusStateReconfigured);
+               if (err)
+                       xenbus_dev_fatal(dev, err, "switching to Reconfigured 
state",
+                                       dev->nodename);
+               break;
+
+       case XenbusStateUnknown:
+               device_unregister(&dev->dev);
+               break;
+       default:
+               xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
+                                       frontend_state);
+               break;
+       }
+}
+
+
+static int scsiback_remove(struct xenbus_device *dev)
+{
+       struct backend_info *be = dev->dev.driver_data;
+
+       if (be->info) {
+               scsiback_disconnect(be->info);
+               scsiback_release_translation_entry(be->info);
+               scsiback_free(be->info);
+               be->info = NULL;
+       }
+
+       kfree(be);
+       dev->dev.driver_data = NULL;
+
+       return 0;
+}
+
+
+static int scsiback_probe(struct xenbus_device *dev,
+                          const struct xenbus_device_id *id)
+{
+       int err;
+
+       struct backend_info *be = kzalloc(sizeof(struct backend_info),
+                                         GFP_KERNEL);
+
+       DPRINTK("%p %d\n", dev, dev->otherend_id);
+
+       if (!be) {
+               xenbus_dev_fatal(dev, -ENOMEM,
+                                "allocating backend structure");
+               return -ENOMEM;
+       }
+       be->dev = dev;
+       dev->dev.driver_data = be;
+
+       be->info = vscsibk_info_alloc(dev->otherend_id);
+       if (IS_ERR(be->info)) {
+               err = PTR_ERR(be->info);
+               be->info = NULL;
+               xenbus_dev_fatal(dev, err, "creating scsihost interface");
+               goto fail;
+       }
+
+       be->info->dev = dev;
+       be->info->irq = 0;
+
+       scsiback_init_translation_table(be->info);
+
+       err = xenbus_switch_state(dev, XenbusStateInitWait);
+       if (err)
+               goto fail;
+
+       return 0;
+
+
+fail:
+       printk(KERN_WARNING "scsiback: %s failed\n",__FUNCTION__);
+       scsiback_remove(dev);
+
+       return err;
+}
+
+
+static struct xenbus_device_id scsiback_ids[] = {
+       { "vscsi" },
+       { "" }
+};
+
+static struct xenbus_driver scsiback = {
+       .name                   = "vscsi",
+       .owner                  = THIS_MODULE,
+       .ids                    = scsiback_ids,
+       .probe                  = scsiback_probe,
+       .remove                 = scsiback_remove,
+       .otherend_changed       = scsiback_frontend_changed
+};
+
+int scsiback_xenbus_init(void)
+{
+       return xenbus_register_backend(&scsiback);
+}
+
+void scsiback_xenbus_unregister(void)
+{
+       xenbus_unregister_driver(&scsiback);
+}

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [linux-2.6.18-xen] pvSCSI backend driver, Xen patchbot-linux-2.6.18-xen <=