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

[Xen-devel] [PATCH 2/4] add scsifront/scsiback drivers



This addes scsifront/scsiback drivers.


Signed-off-by: FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx>

diff -r 105d5d6b4e0d -r 95ca3ffbdbfd buildconfigs/linux-defconfig_xen_x86_32
--- a/buildconfigs/linux-defconfig_xen_x86_32   Wed Jan 03 01:34:02 2007 +0900
+++ b/buildconfigs/linux-defconfig_xen_x86_32   Wed Jan 03 01:35:35 2007 +0900
@@ -1050,13 +1050,14 @@ CONFIG_IDEDMA_AUTO=y
 # SCSI device support
 #
 CONFIG_RAID_ATTRS=m
-CONFIG_SCSI=m
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
 CONFIG_SCSI_PROC_FS=y
 
 #
 # SCSI support type (disk, tape, CD-ROM)
 #
-CONFIG_BLK_DEV_SD=m
+CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=m
@@ -1158,6 +1159,7 @@ CONFIG_SCSI_DC390T=m
 CONFIG_SCSI_DC390T=m
 CONFIG_SCSI_NSP32=m
 CONFIG_SCSI_DEBUG=m
+CONFIG_SCSI_SRP=y
 
 #
 # PCMCIA SCSI adapter support
@@ -3027,12 +3029,14 @@ CONFIG_XEN_PCIDEV_BACKEND_VPCI=y
 # CONFIG_XEN_PCIDEV_BACKEND_SLOT is not set
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 CONFIG_XEN_BLKDEV_BACKEND=y
+CONFIG_XEN_SCSI_BACKEND=y
 CONFIG_XEN_BLKDEV_TAP=y
 CONFIG_XEN_NETDEV_BACKEND=y
 # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
 CONFIG_XEN_NETDEV_LOOPBACK=y
 # CONFIG_XEN_TPMDEV_BACKEND is not set
 CONFIG_XEN_BLKDEV_FRONTEND=y
+CONFIG_XEN_SCSI_FRONTEND=y
 CONFIG_XEN_NETDEV_FRONTEND=y
 CONFIG_XEN_FRAMEBUFFER=y
 CONFIG_XEN_KEYBOARD=y
diff -r 105d5d6b4e0d -r 95ca3ffbdbfd linux-2.6-xen-sparse/drivers/xen/Kconfig
--- a/linux-2.6-xen-sparse/drivers/xen/Kconfig  Wed Jan 03 01:34:02 2007 +0900
+++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig  Wed Jan 03 01:35:35 2007 +0900
@@ -44,6 +44,17 @@ config XEN_BACKEND
         help
           Support for backend device drivers that provide I/O services
           to other virtual machines.
+
+config XEN_SCSI_BACKEND
+       tristate "SCSI backend driver"
+       depends on XEN_BACKEND && SCSI_TGT
+       default y
+       help
+         The SCSI backend driver allows the kernel to export its SCSI HBAs
+         to other guests via a high-performance shared-memory interface.
+         SCSI requests are redirected to userspace through netlink interface.
+         The user-space daemon can export disk images, which may be implemented
+         as files, in memory, or on other hosts across the network.
 
 config XEN_BLKDEV_BACKEND
        tristate "Block-device backend driver"
@@ -162,6 +173,14 @@ config XEN_BLKDEV_FRONTEND
          dedicated device-driver domain, or your master control domain
          (domain 0), then you almost certainly want to say Y here.
 
+config XEN_SCSI_FRONTEND
+       tristate "SCSI frontend driver"
+       depends on XEN && SCSI
+       default y
+       help
+         The SCSI frontend driver allows the kernel to access SCSI HBAs
+         within another guest OS.
+
 config XEN_NETDEV_FRONTEND
        tristate "Network-device frontend driver"
        depends on XEN && NET
diff -r 105d5d6b4e0d -r 95ca3ffbdbfd linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile Wed Jan 03 01:34:02 2007 +0900
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Wed Jan 03 01:35:35 2007 +0900
@@ -8,10 +8,12 @@ obj-$(CONFIG_XEN_BALLOON)             += balloon/
 obj-$(CONFIG_XEN_BALLOON)              += balloon/
 obj-$(CONFIG_XEN_DEVMEM)               += char/
 obj-$(CONFIG_XEN_BLKDEV_BACKEND)       += blkback/
+obj-$(CONFIG_XEN_SCSI_BACKEND)         += scsiback/
 obj-$(CONFIG_XEN_BLKDEV_TAP)           += blktap/
 obj-$(CONFIG_XEN_NETDEV_BACKEND)       += netback/
 obj-$(CONFIG_XEN_TPMDEV_BACKEND)       += tpmback/
 obj-$(CONFIG_XEN_BLKDEV_FRONTEND)      += blkfront/
+obj-$(CONFIG_XEN_SCSI_FRONTEND)                += scsifront/
 obj-$(CONFIG_XEN_NETDEV_FRONTEND)      += netfront/
 obj-$(CONFIG_XEN_PCIDEV_BACKEND)       += pciback/
 obj-$(CONFIG_XEN_PCIDEV_FRONTEND)      += pcifront/
diff -r 105d5d6b4e0d -r 95ca3ffbdbfd 
linux-2.6-xen-sparse/drivers/xen/scsiback/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/scsiback/Makefile        Wed Jan 03 
01:35:35 2007 +0900
@@ -0,0 +1,2 @@
+obj-$(CONFIG_XEN_SCSI_BACKEND) += scsibk.o
+scsibk-y                       += interface.o scsiback.o
diff -r 105d5d6b4e0d -r 95ca3ffbdbfd 
linux-2.6-xen-sparse/drivers/xen/scsiback/interface.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/scsiback/interface.c     Wed Jan 03 
01:35:35 2007 +0900
@@ -0,0 +1,153 @@
+/******************************************************************************
+ * arch/xen/drivers/blkif/backend/interface.c
+ *
+ * Block-device interface management.
+ *
+ * Copyright (c) 2004, Keir Fraser
+ *
+ * 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 <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/uio.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/srp.h>
+#include <xen/driver_util.h>
+#include <xen/evtchn.h>
+#include <xen/xenbus.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/io/scsi.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/grant_table.h>
+#include <xen/gnttab.h>
+#include <asm/hypervisor.h>
+#include "scsiback_priv.h"
+
+static int map_frontend_page(struct scsiback_info *info, unsigned long 
shared_page)
+{
+       struct gnttab_map_grant_ref op;
+       int err;
+
+       gnttab_set_map_op(&op, (unsigned long)info->ring_area->addr,
+                         GNTMAP_host_map, shared_page,
+                         info->dev->otherend_id);
+
+       lock_vm_area(info->ring_area);
+       err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
+       unlock_vm_area(info->ring_area);
+       BUG_ON(err);
+
+       if (op.status) {
+               printk(" Grant table operation failure !\n");
+               return op.status;
+       }
+
+       info->shmem_ref = shared_page;
+       info->shmem_handle = op.handle;
+
+#ifdef CONFIG_XEN_IA64_DOM0_NON_VP
+       /* on some arch's, map_grant_ref behaves like mmap, in that the
+        * passed address is a hint and a different address may be returned */
+       info->ring_area->addr = gnttab_map_vaddr(op);
+#endif
+
+       return 0;
+}
+
+static void unmap_frontend_page(struct scsiback_info *info)
+{
+       struct gnttab_unmap_grant_ref op;
+       int err;
+
+       op.host_addr    = (unsigned long)info->ring_area->addr;
+       op.handle       = info->shmem_handle;
+       op.dev_bus_addr = 0;
+
+       lock_vm_area(info->ring_area);
+       err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
+       unlock_vm_area(info->ring_area);
+       BUG_ON(err);
+}
+
+int scsiback_init_sring(struct scsiback_info *info,
+                        unsigned long shared_page, unsigned int evtchn)
+{
+       struct scsi_sring *sring;
+       int err;
+       struct evtchn_bind_interdomain bind_interdomain;
+
+       if (info->irq) {
+               printk("Already connected through?\n");
+               return 0;
+       }
+
+       info->ring_area = alloc_vm_area(PAGE_SIZE);
+       if (!info)
+               return -ENOMEM;
+
+       err = map_frontend_page(info, shared_page);
+       if (err)
+               goto free_vm;
+
+       bind_interdomain.remote_dom = info->dev->otherend_id;
+       bind_interdomain.remote_port = evtchn;
+
+       err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
+                                         &bind_interdomain);
+       if (err)
+               goto unmap_page;
+
+       info->evtchn = bind_interdomain.local_port;
+
+       sring = (struct scsi_sring *) info->ring_area->addr;
+       BACK_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+       info->irq = bind_evtchn_to_irqhandler(info->evtchn, scsiback_intr,
+                                             0, "scsi-backend", info);
+       return 0;
+
+unmap_page:
+       unmap_frontend_page(info);
+free_vm:
+       free_vm_area(info->ring_area);
+       return err;
+}
+
+void scsiback_exit_sring(struct scsiback_info *info)
+{
+       /* Already disconnected? */
+       if (info->irq)
+               unbind_from_irqhandler(info->irq, info);
+
+       if (info->ring.sring) {
+               unmap_frontend_page(info);
+               free_vm_area(info->ring_area);
+       }
+}
diff -r 105d5d6b4e0d -r 95ca3ffbdbfd 
linux-2.6-xen-sparse/drivers/xen/scsiback/scsiback.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/scsiback/scsiback.c      Wed Jan 03 
01:35:35 2007 +0900
@@ -0,0 +1,712 @@
+/*
+ * Xen SCSI backend driver
+ *
+ * Copyright (C) 2006 FUJITA Tomonori <tomof@xxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Based on the blktap driver code.
+ *
+ * Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield
+ *
+ */
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/uio.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_tgt.h>
+#include <scsi/srp.h>
+#include <scsi/libsrp.h>
+#include <xen/evtchn.h>
+#include <xen/balloon.h>
+#include <xen/xenbus.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/io/scsi.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/grant_table.h>
+#include <xen/gnttab.h>
+#include <asm/hypervisor.h>
+#include "scsiback_priv.h"
+
+#define INVALID_GRANT_HANDLE   0xFFFF
+
+#define eprintk(fmt, args...)                                          \
+do {                                                                   \
+       printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);          \
+} while (0)
+
+#define dprintk(fmt, args...)                                          \
+do {                                                                   \
+       if (debug)                                                      \
+               printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);  \
+} while (0)
+
+static unsigned int debug = 0;
+static int major;
+static struct workqueue_struct *scsibkd;
+
+module_param(debug, int, 0644);
+
+static int req_index(struct scsiback_info *info, struct scsi_request *req)
+{
+       return (req - RING_GET_REQUEST(&info->ring, 0));
+}
+
+static int __idx(struct scsiback_info *info, struct scsi_request *req,
+                     int idx)
+{
+       return req_index(info, req) * SRP_MAX_INDIRECT + idx;
+}
+
+static unsigned long idx_to_uaddr(struct scsiback_info *info,
+                                 struct scsi_request *req, int i)
+{
+       return info->ustart + (__idx(info, req, i) << PAGE_SHIFT);
+}
+
+static unsigned long idx_to_kaddr(struct scsiback_info *info,
+                                 struct scsi_request *req, int i)
+{
+       struct page *page = info->mmap_pages[__idx(info, req, i)];
+       unsigned long pfn = page_to_pfn(page);
+       return (unsigned long)pfn_to_kaddr(pfn);
+}
+
+static int scsiback_send_rsp(struct scsiback_info *info, struct scsi_cmnd *sc,
+                            void (*done)(struct scsi_cmnd *))
+{
+       struct scsi_back_ring *ring = &info->ring;
+       struct scsi_response *rsp;
+       struct scsi_request *req = (struct scsi_request *) sc->SCp.ptr;
+       struct srp_cmd *cmd = (struct srp_cmd *) req->buf;
+       struct srp_rsp *srsp;
+       int notify;
+
+       rsp = RING_GET_RESPONSE(ring, ring->rsp_prod_pvt);
+       srsp = (struct srp_rsp *) rsp->buf;
+       srsp->opcode = SRP_RSP;
+       srsp->tag = cmd->tag;
+       srsp->resp_data_len = 0;
+       srsp->status = NO_SENSE;
+       srsp->data_in_res_cnt = 0;
+       srsp->data_out_res_cnt = 0;
+       srsp->flags &= ~SRP_RSP_FLAG_RSPVALID;
+
+       ring->rsp_prod_pvt++;
+
+       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(ring, notify);
+
+       notify_remote_via_irq(info->irq);
+
+       done(sc);
+       return 0;
+}
+
+static int scsiback_cmd_done_fn(struct scsi_cmnd *sc, struct scatterlist *sg,
+                               int nsg, struct srp_direct_buf *md, int nmd,
+                               enum dma_data_direction dir, unsigned int len)
+{
+       struct Scsi_Host *host;
+       struct scsiback_info *info;
+       struct scsi_request *req;
+       struct vm_area_struct *vma;
+       struct gnttab_unmap_grant_ref unmap[SRP_MAX_INDIRECT * 2];
+       int i, op, err, offset;
+       u64 kaddr, uaddr, ptep;
+
+       host = (struct Scsi_Host *) sc->host_scribble;
+       info = (struct scsiback_info *) host->hostdata;
+       req = (struct scsi_request *) sc->SCp.ptr;
+       vma = info->mmap_vma;
+
+       dprintk("%p %d %d %d %u %p\n", req, nsg, nmd, dir, len, vma);
+
+       for (i = 0; i < nmd; i++) {
+               struct page *page, **map = vma->vm_private_data;
+
+               uaddr = idx_to_uaddr(info, req, i);
+               kaddr = idx_to_kaddr(info, req, i);
+
+               dprintk("%d %llx %llx\n", i, uaddr, kaddr);
+
+               page = pfn_to_page(__pa(kaddr) >> PAGE_SHIFT);
+               ClearPageReserved(page);
+               offset = (uaddr - vma->vm_start) >> PAGE_SHIFT;
+               map[offset] = NULL;
+
+       }
+
+       if (vma && xen_feature(XENFEAT_auto_translated_physmap)) {
+               down_write(&vma->vm_mm->mmap_sem);
+               zap_page_range(vma, idx_to_uaddr(info, req, 0),
+                              nmd << PAGE_SHIFT, NULL);
+               up_write(&vma->vm_mm->mmap_sem);
+       }
+
+       for (op = i = 0; i < nmd; i++) {
+               uaddr = idx_to_uaddr(info, req, i);
+               kaddr = idx_to_kaddr(info, req, i);
+
+               dprintk("%d %d %llx %llx\n", i, op, uaddr, kaddr);
+
+               gnttab_set_unmap_op(&unmap[op], kaddr, GNTMAP_host_map,
+                                   info->handle[__idx(info, req, i)].k);
+
+               err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, 
unmap, op);
+               BUG_ON(err);
+               op++;
+
+               if (info->handle[__idx(info, req, i)].u != 
INVALID_GRANT_HANDLE) {
+
+                       err = create_lookup_pte_addr(vma->vm_mm, uaddr, &ptep);
+                       BUG_ON(err); /* FIXME */
+
+                       dprintk("%d %d %llx %llx\n", i, op, uaddr, kaddr);
+
+                       gnttab_set_unmap_op(&unmap[op], ptep, GNTMAP_host_map,
+                                           info->handle[__idx(info, req, 
i)].u);
+                       op++;
+               }
+       }
+
+       err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, op);
+       BUG_ON(err);
+
+       if (vma && !xen_feature(XENFEAT_auto_translated_physmap))
+               zap_page_range(vma, idx_to_uaddr(info, req, 0),
+                              nmd << PAGE_SHIFT, NULL);
+
+       dprintk("%p %d %d %d %u %p\n", req, nsg, nmd, dir, len, vma);
+
+       return 0;
+}
+
+static int scsiback_cmd_done(struct scsi_cmnd *sc,
+                             void (*done)(struct scsi_cmnd *))
+{
+       struct Scsi_Host *host = (struct Scsi_Host *) sc->host_scribble;
+       struct scsiback_info *info = (struct scsiback_info *) host->hostdata;
+       struct scsi_request *req = (struct scsi_request *) sc->SCp.ptr;
+       struct srp_cmd *cmd = (struct srp_cmd *) req->buf;
+
+       srp_transfer_data(sc, cmd, scsiback_cmd_done_fn, 0, 0);
+       scsiback_send_rsp(info, sc, done);
+       return 0;
+}
+
+static int scsiback_eh_abort_handler(struct scsi_cmnd *scmd)
+{
+       BUG_ON(1);
+       return 0;
+}
+
+static struct scsi_host_template scsiback_sht = {
+       .module                 = THIS_MODULE,
+       .name                   = "scsiback",
+       .can_queue              = SRP_CAN_QUEUE,
+       .sg_tablesize           = SG_ALL,
+       .use_clustering         = DISABLE_CLUSTERING,
+       .transfer_response      = scsiback_cmd_done,
+       .eh_abort_handler       = scsiback_eh_abort_handler,
+};
+
+struct scsiback_srp_arg {
+       struct scsiback_info *info;
+       struct scsi_request *req;
+};
+
+static int scsiback_cmd_fn(struct scsi_cmnd *sc, struct scatterlist *sg,
+                          int nsg, struct srp_direct_buf *md, int nmd,
+                          enum dma_data_direction dir, unsigned int len)
+{
+       struct scsiback_srp_arg *arg = (struct scsiback_srp_arg *) sc;
+       struct scsiback_info *info = arg->info;
+       struct scsi_request *req = arg->req;
+       struct vm_area_struct *vma = info->mmap_vma;
+       struct gnttab_map_grant_ref map[SRP_MAX_INDIRECT * 2];
+       struct page *page;
+       struct iovec *iov;
+       int i, op, err;
+       u64 uaddr, kaddr, ptep;
+       u32 flags;
+
+       /* TODO: replace iovec */
+       iov = (struct iovec *)
+               (info->uring + SRP_SG_SIZE * req_index(info, req));
+       memset(iov, 0, SRP_SG_SIZE);
+
+       for (op = i = 0; i < nmd; i++) {
+               uaddr = idx_to_uaddr(info, req, i);
+               kaddr = idx_to_kaddr(info, req, i);
+
+               dprintk("%d %llx %llx %x\n", i, (unsigned long long)uaddr,
+                       (unsigned long long)kaddr, (md + i)->key);
+
+               page = virt_to_page(kaddr);
+
+               flags = GNTMAP_host_map;
+               if (dir == DMA_TO_DEVICE)
+                       flags |= GNTMAP_readonly;
+
+               gnttab_set_map_op(&map[op], kaddr, flags,
+                                 (md + i)->key,
+                                 info->dev->otherend_id);
+               op++;
+
+               if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+                       err = create_lookup_pte_addr(vma->vm_mm, uaddr, &ptep);
+                       BUG_ON(err); /* FIXME */
+
+                       flags = GNTMAP_host_map | GNTMAP_application_map
+                               | GNTMAP_contains_pte;
+                       if (dir == DMA_TO_DEVICE)
+                               flags |= GNTMAP_readonly;
+
+                       gnttab_set_map_op(&map[op], ptep, flags,
+                                         (md + i)->key,
+                                         info->dev->otherend_id);
+                       op++;
+               }
+       }
+
+       err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, op);
+       BUG_ON(err);
+
+       if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+               for (i = 0; i < nmd; i++) {
+                       int offset, j, idx;
+
+                       j = i * 2;
+                       idx = __idx(info, req, i);
+
+                       uaddr = idx_to_uaddr(info, req, i);
+                       kaddr = idx_to_kaddr(info, req, i);
+
+                       /* FIXME */
+                       BUG_ON(map[j].status);
+                       BUG_ON(map[j + 1].status);
+
+                       info->handle[idx].k = map[j].handle;
+                       info->handle[idx].u = map[j + 1].handle;
+                       set_phys_to_machine(__pa(kaddr) >> PAGE_SHIFT,
+                                           FOREIGN_FRAME(map[j].dev_bus_addr 
>> PAGE_SHIFT));
+                       offset = (uaddr - vma->vm_start) >> PAGE_SHIFT;
+                       page = pfn_to_page(__pa(kaddr) >> PAGE_SHIFT);
+                       ((struct page **) vma->vm_private_data)[offset] = page;
+                       SetPageReserved(page);
+
+                       offset = (md + i)->va & (PAGE_SIZE-1);
+                       iov[i].iov_base = (void *) ((unsigned long) uaddr + 
offset);
+                       iov[i].iov_len = (md + i)->len;
+
+                       dprintk("%llx %d %p %d\n", (unsigned long long)uaddr,
+                               offset, iov[i].iov_base, iov[i].iov_len);
+               }
+       } else {
+               for (i = 0; i < nmd; i++) {
+                       int offset, idx;
+
+                       uaddr = idx_to_uaddr(info, req, i);
+                       kaddr = idx_to_kaddr(info, req, i);
+
+                       /* FIXME */
+                       BUG_ON(map[i].status);
+
+                       idx = __idx(info, req, i);
+                       info->handle[idx].k = map[i].handle;
+                       info->handle[idx].u = INVALID_GRANT_HANDLE;
+
+                       offset = (uaddr - vma->vm_start) >> PAGE_SHIFT;
+                       page = pfn_to_page(__pa(kaddr) >> PAGE_SHIFT);
+                       ((struct page **) vma->vm_private_data)[offset] = page;
+                       SetPageReserved(page);
+
+                       offset = (md + i)->va & (PAGE_SIZE-1);
+                       iov[i].iov_base = (void *) ((unsigned long) uaddr + 
offset);
+                       iov[i].iov_len = (md + i)->len;
+
+                       dprintk("%llx %d %p %d\n", (unsigned long long)uaddr,
+                               offset, iov[i].iov_base, iov[i].iov_len);
+               }
+       }
+       return 0;
+}
+
+static void scsiback_worker(void *data)
+{
+       struct scsiback_info *info = data;
+       struct scsi_back_ring *ring = &info->ring;
+       struct scsi_request *req;
+       struct srp_cmd *cmd;
+       struct vm_area_struct *vma = info->mmap_vma;
+       struct scsiback_srp_arg arg;
+       RING_IDX rc, rp;
+       u64 addr;
+
+       rc = ring->req_cons;
+       rp = ring->sring->req_prod;
+       rmb();
+
+       while ((rc != rp) && !RING_REQUEST_CONS_OVERFLOW(ring, rc)) {
+               dprintk("%u %u\n", rc, rp);
+               req = RING_GET_REQUEST(ring, rc);
+               ring->req_cons = ++rc;
+               cmd = (struct srp_cmd *) req->buf;
+
+               arg.info = info;
+               arg.req = req;
+
+               dprintk("%x %x\n", cmd->opcode, cmd->cdb[0]);
+               srp_transfer_data((struct scsi_cmnd *)&arg, cmd,
+                                 scsiback_cmd_fn, 0, 0);
+               addr = vma->vm_start + SRP_SG_SIZE * req_index(info, req);
+               srp_cmd_queue(info->host, cmd, req, addr);
+       }
+}
+
+irqreturn_t scsiback_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct scsiback_info *info = (struct scsiback_info *) dev_id;
+
+       queue_work(scsibkd, &info->scsiback_work);
+
+       return IRQ_HANDLED;
+}
+
+static int scsiback_connect(struct scsiback_info *info)
+{
+       struct xenbus_device *dev = info->dev;
+       unsigned long ring_ref;
+       unsigned int evtchn;
+       int err;
+
+       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;
+       }
+
+       return scsiback_init_sring(info, ring_ref, evtchn);
+}
+
+static void scsiback_frontend_changed(struct xenbus_device *dev,
+                                      enum xenbus_state frontend_state)
+{
+       struct scsiback_info *info = dev->dev.driver_data;
+       int err;
+
+       dprintk("%p %u %u\n", dev, dev->state, frontend_state);
+       switch (frontend_state) {
+       case XenbusStateInitialising:
+               break;
+
+       case XenbusStateInitialised:
+       case XenbusStateConnected:
+               if (dev->state == XenbusStateConnected)
+                       break;
+
+               err = scsiback_connect(info);
+               if (err)
+                       break;
+
+               err = xenbus_switch_state(dev, XenbusStateConnected);
+               if (err)
+                       xenbus_dev_fatal(dev, err, "switching to Connected 
state",
+                                        dev->nodename);
+               break;
+
+       case XenbusStateClosing:
+               xenbus_switch_state(dev, XenbusStateClosing);
+               break;
+
+       case XenbusStateClosed:
+               xenbus_switch_state(dev, XenbusStateClosed);
+               if (xenbus_dev_is_online(dev))
+                       break;
+
+       case XenbusStateUnknown:
+               /*
+                * wordaround.
+                */
+               if (info->host->host_no)
+                       device_unregister(&dev->dev);
+               break;
+       default:
+               xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
+                                frontend_state);
+               break;
+       }
+}
+
+static void scsiback_backend_changed(struct xenbus_watch *watch,
+                                     const char **vec, unsigned int len)
+{
+       struct scsiback_info *info =
+               container_of(watch, struct scsiback_info, backend_watch);
+
+       dprintk("%p %u\n", info->dev, info->dev->state);
+
+       /* TODO */
+}
+
+static int scsiback_probe(struct xenbus_device *dev,
+                          const struct xenbus_device_id *id)
+{
+       int err, nr;
+       struct Scsi_Host *host;
+       struct scsiback_info *info;
+       struct xenbus_transaction xbt;
+
+       dprintk("%p %d\n", dev, dev->otherend_id);
+
+       host = scsi_host_alloc(&scsiback_sht, sizeof(struct scsiback_info));
+       if (!host)
+               return -ENOMEM;
+       err = scsi_tgt_alloc_queue(host);
+       if (err)
+               goto put_host;
+
+       err = scsi_add_host(host, &dev->dev);
+       if (err)
+               goto put_host;
+
+       info = (struct scsiback_info *) host->hostdata;
+       dev->dev.driver_data = info;
+       info->dev = dev;
+       info->host = host;
+
+       info->uring = get_zeroed_page(GFP_KERNEL);
+       if (!info->uring)
+               goto put_host;
+       SetPageReserved(virt_to_page(info->uring));
+
+       nr = SRP_RING_PAGES + SRP_MAPPED_PAGES;
+       info->mmap_pages = alloc_empty_pages_and_pagevec(nr);
+       if (!info->mmap_pages)
+               goto free_ring;
+
+       INIT_WORK(&info->scsiback_work, scsiback_worker, info);
+
+       err = xenbus_transaction_start(&xbt);
+       if (err)
+               eprintk("fail to transcation %d\n", err);
+
+       err = xenbus_printf(xbt, dev->nodename, "hostno", "%u", host->host_no);
+       if (err)
+               eprintk("fail to transcation %d\n", err);
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err)
+               eprintk("fail to transcation %d\n", err);
+
+       err = xenbus_watch_path2(dev, dev->nodename,
+                                "scsi-host",
+                                &info->backend_watch,
+                                scsiback_backend_changed);
+       if (err)
+               goto free_page;
+
+       err = xenbus_switch_state(dev, XenbusStateInitWait);
+       if (err)
+               goto stop_watch;
+
+       return 0;
+
+stop_watch:
+       /* free resource */
+free_page:
+       free_empty_pages_and_pagevec(info->mmap_pages, nr);
+free_ring:
+       free_page(info->uring);
+put_host:
+       scsi_host_put(host);
+       return err;
+}
+
+static int scsiback_remove(struct xenbus_device *dev)
+{
+       struct scsiback_info *info = dev->dev.driver_data;
+       struct Scsi_Host *host = info->host;
+
+       dprintk("%p %u\n", host, host->host_no);
+
+       return 0;
+}
+
+/* should we free the resource in scsiback_remove? */
+static int scsiback_release(struct inode *inode, struct file *filp)
+{
+       unsigned int hostno = MINOR(filp->f_dentry->d_inode->i_rdev);
+       struct scsiback_info *info;
+       struct Scsi_Host *host;
+
+       host = scsi_host_lookup(hostno);
+       if (!host) {
+               eprintk("no scsi host %d\n", hostno);
+               return -EAGAIN;
+       }
+       info = (struct scsiback_info *)host->hostdata;
+
+       ClearPageReserved(virt_to_page(info->uring));
+       free_page(info->uring);
+
+       /* TODO */
+#if 0
+       vma = info->mmap_vma;
+       if (vma) {
+               zap_page_range(vma, vma->vm_start,
+                              vma->vm_end - vma->vm_start, NULL);
+               info->mmap_vma = NULL;
+       }
+#endif
+       free_empty_pages_and_pagevec(info->mmap_pages,
+                                    SRP_RING_PAGES + SRP_MAPPED_PAGES);
+       scsi_remove_host(host);
+       scsi_tgt_free_queue(host);
+       scsi_host_put(host);
+
+       return 0;
+}
+
+static struct page *scsiback_nopage(struct vm_area_struct *vma,
+                                   unsigned long address, int *type)
+{
+       return NOPAGE_SIGBUS;
+}
+
+struct vm_operations_struct scsiback_vm_ops = {
+       .nopage                 = scsiback_nopage,
+};
+
+static int scsiback_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       int i, err;
+       unsigned long nr;
+       unsigned int hostno = MINOR(filp->f_dentry->d_inode->i_rdev);
+       struct page **map;
+       struct scsiback_info *info;
+       struct Scsi_Host *host;
+
+       dprintk("%u start %lx, end %lx\n", hostno, vma->vm_start, vma->vm_end);
+
+       host = scsi_host_lookup(hostno);
+       if (!host) {
+               eprintk("no scsi host %d\n", hostno);
+               return -EAGAIN;
+       }
+       info = (struct scsiback_info *)host->hostdata;
+
+       vma->vm_flags |= VM_RESERVED;
+       vma->vm_ops = &scsiback_vm_ops;
+
+       nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+       if (nr != SRP_RING_PAGES + SRP_MAPPED_PAGES) {
+               eprintk("you _must_ map exactly %lu pages!\n", nr);
+               err = -EINVAL;
+               goto host_put;
+       }
+
+       err = remap_pfn_range(vma, vma->vm_start,
+                             __pa(info->uring) >> PAGE_SHIFT,
+                             PAGE_SIZE, vma->vm_page_prot);
+       if (err) {
+               eprintk("fail to map frontend ring %d!\n", err);
+               goto host_put;
+       }
+
+       /* Mark this VM as containing foreign pages, and set up mappings. */
+       map = kzalloc(nr * sizeof(struct page_struct *), GFP_KERNEL);
+       if (!map) {
+               eprintk("Couldn't alloc VM_FOREIGN map.\n");
+               err = -ENOMEM;
+               zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, 
NULL);
+               goto host_put;
+       }
+
+       for (i = 0; i < nr; i++)
+               map[i] = NULL;
+
+       vma->vm_private_data = map;
+       vma->vm_flags |= VM_FOREIGN;
+
+       info->ustart = vma->vm_start + (SRP_RING_PAGES << PAGE_SHIFT);
+
+       dprintk("%d %u start %lx, end %lx ustart %llx\n",
+               err, hostno, vma->vm_start, vma->vm_end, info->ustart);
+
+       info->mmap_vma = vma;
+host_put:
+       scsi_host_put(host);
+
+       return err;
+}
+
+static struct file_operations scsiback_fops = {
+       .owner                  = THIS_MODULE,
+       .mmap                   = scsiback_mmap,
+       .release                = scsiback_release,
+};
+
+static struct xenbus_device_id scsiback_ids[] = {
+       { "scsi" },
+       { "" }
+};
+
+static struct xenbus_driver scsiback = {
+       .name                   = "scsi",
+       .owner                  = THIS_MODULE,
+       .ids                    = scsiback_ids,
+       .probe                  = scsiback_probe,
+       .remove                 = scsiback_remove,
+       .otherend_changed       = scsiback_frontend_changed
+};
+
+static int __init scsiback_init(void)
+{
+       int err = -ENOMEM;
+
+       if (!is_running_on_xen())
+               return -ENODEV;
+
+       major = register_chrdev(0, "scsiback", &scsiback_fops);
+       if (major < 0)
+               return major;
+
+       scsibkd = create_singlethread_workqueue("scsibkd");
+       if (!scsibkd)
+               goto free_dev;
+
+       err = xenbus_register_backend(&scsiback);
+       if (err)
+               goto destroy_wq;
+       return 0;
+free_dev:
+       unregister_chrdev(major, "scsiback");
+destroy_wq:
+       destroy_workqueue(scsibkd);
+       return err;
+}
+
+module_init(scsiback_init);
+
+MODULE_AUTHOR("FUJITA Tomonori");
+MODULE_DESCRIPTION("Xen SCSI backend driver");
+MODULE_LICENSE("GPL");
diff -r 105d5d6b4e0d -r 95ca3ffbdbfd 
linux-2.6-xen-sparse/drivers/xen/scsiback/scsiback_priv.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/scsiback/scsiback_priv.h Wed Jan 03 
01:35:35 2007 +0900
@@ -0,0 +1,35 @@
+struct grant_handle_pair {
+        grant_handle_t k;
+        grant_handle_t u;
+};
+
+struct scsiback_info {
+       struct xenbus_device *dev;
+       struct Scsi_Host *host;
+       struct xenbus_watch backend_watch;
+
+       unsigned int evtchn;
+       unsigned int irq;
+
+       struct scsi_back_ring ring;
+       struct vm_struct *ring_area;
+
+       grant_handle_t shmem_handle;
+       grant_ref_t    shmem_ref;
+
+       struct work_struct scsiback_work;
+
+       /* Add something tgt code to support this kind of stuff? */
+       unsigned long uring;
+
+       struct vm_area_struct *mmap_vma;
+       struct page **mmap_pages;
+       u64 ustart;
+
+       struct grant_handle_pair handle[SRP_CAN_QUEUE * SRP_MAX_INDIRECT];
+};
+
+extern irqreturn_t scsiback_intr(int, void *, struct pt_regs *);
+extern int scsiback_init_sring(struct scsiback_info *,
+                              unsigned long, unsigned int);
+extern void scsiback_exit_sring(struct scsiback_info *);
diff -r 105d5d6b4e0d -r 95ca3ffbdbfd 
linux-2.6-xen-sparse/drivers/xen/scsifront/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/scsifront/Makefile       Wed Jan 03 
01:35:35 2007 +0900
@@ -0,0 +1,1 @@
+obj-$(CONFIG_XEN_SCSI_FRONTEND)        += scsifront.o
diff -r 105d5d6b4e0d -r 95ca3ffbdbfd 
linux-2.6-xen-sparse/drivers/xen/scsifront/scsifront.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/scsifront/scsifront.c    Wed Jan 03 
01:35:35 2007 +0900
@@ -0,0 +1,472 @@
+/*
+ * Xen SCSI frontend driver
+ *
+ * Copyright (C) 2006 FUJITA Tomonori <tomof@xxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/uio.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/srp.h>
+#include <xen/evtchn.h>
+#include <xen/xenbus.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/io/scsi.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/grant_table.h>
+#include <xen/gnttab.h>
+#include <asm/hypervisor.h>
+
+#define eprintk(fmt, args...)                                  \
+do {                                                           \
+       printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);  \
+} while (0)
+
+#define dprintk eprintk
+
+static unsigned int debug = 0;
+module_param(debug, int, 0644);
+
+struct scsifront_info {
+       struct xenbus_device *dev;
+       struct Scsi_Host *host;
+       unsigned int evtchn;
+       unsigned int irq;
+       unsigned long ring_ref;
+       struct scsi_front_ring ring;
+};
+
+static int map_data_for_srp_cmd(struct scsifront_info *info,
+                               struct scsi_cmnd *sc, struct srp_cmd *cmd)
+{
+       struct scatterlist *sg = sc->request_buffer;
+       struct srp_direct_buf *buf;
+       grant_ref_t gref_head;
+       int err, i, ref;
+       u8 fmt;
+
+       if (!sg || sc->sc_data_direction == DMA_NONE)
+               return 0;
+
+       err = gnttab_alloc_grant_references(SRP_MAX_INDIRECT, &gref_head);
+       if (err)
+               return -ENOMEM;
+
+       if (sc->use_sg == 1) {
+               buf = (void *) cmd->add_data;
+               fmt = SRP_DATA_DESC_DIRECT;
+
+               ref = gnttab_claim_grant_reference(&gref_head);
+               gnttab_grant_foreign_access_ref(ref, info->dev->otherend_id,
+                                               page_to_phys(sg->page) >> 
PAGE_SHIFT, 0);
+
+               buf->va = sg->offset;
+               buf->key = ref;
+               buf->len = sg->length;
+       } else {
+               struct srp_indirect_buf *ind = (void *) cmd->add_data;
+               int total = 0;
+               fmt = SRP_DATA_DESC_INDIRECT;
+
+               if (sc->sc_data_direction == DMA_TO_DEVICE)
+                       cmd->data_out_desc_cnt = sc->use_sg;
+               else
+                       cmd->data_in_desc_cnt = sc->use_sg;
+
+               ind->table_desc.va = (u64) (unsigned long)ind->desc_list;
+               ind->table_desc.key = 0;
+               ind->table_desc.len = sizeof(*buf) * sc->use_sg;
+
+               buf = (struct srp_direct_buf *) ind->desc_list;
+               for (i = 0; i < sc->use_sg; i++, sg++) {
+                       ref = gnttab_claim_grant_reference(&gref_head);
+                       gnttab_grant_foreign_access_ref(ref, 
info->dev->otherend_id,
+                                                       page_to_phys(sg->page) 
>> PAGE_SHIFT,
+                                                       0);
+                       buf[i].va = sg->offset;
+                       buf[i].key = ref;
+                       buf[i].len = sg->length;
+                       total += sg->length;
+               }
+
+               ind->len = total;
+       }
+
+       if (sc->sc_data_direction == DMA_TO_DEVICE)
+               cmd->buf_fmt = fmt << 4;
+       else
+               cmd->buf_fmt = fmt;
+
+       gnttab_free_grant_references(gref_head);
+
+       return 0;
+}
+
+static int scsifront_queuecommand(struct scsi_cmnd *sc,
+                                  void (*done)(struct scsi_cmnd *))
+{
+       struct Scsi_Host *host = sc->device->host;
+       struct scsifront_info *info = (struct scsifront_info *) host->hostdata;
+       struct scsi_request *ring_req;
+       struct scsi_front_ring *ring = &info->ring;
+       struct srp_cmd *cmd;
+       int err, notify;
+
+       if (info->dev->state != XenbusStateConnected || RING_FULL(ring)) {
+               eprintk("busy %u!\n", info->dev->state);
+               return SCSI_MLQUEUE_HOST_BUSY;
+       }
+       sc->scsi_done = done;
+       sc->result = 0;
+
+       ring_req = RING_GET_REQUEST(ring, ring->req_prod_pvt);
+       cmd = (struct srp_cmd *) ring_req->buf;
+
+       memset(cmd, 0, SRP_MAX_IU_LEN);
+       cmd->opcode = SRP_CMD;
+       int_to_scsilun(sc->device->lun, (struct scsi_lun *) &cmd->lun);
+       cmd->tag = (long) sc;
+       memcpy(cmd->cdb, sc->cmnd, sc->cmd_len);
+
+       err = map_data_for_srp_cmd(info, sc, cmd);
+       if (err)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
+       ring->req_prod_pvt++;
+
+       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify);
+       notify_remote_via_irq(info->irq);
+
+       return 0;
+}
+
+static int scsifront_eh_abort_handler(struct scsi_cmnd *sc)
+{
+       BUG();
+       return 0;
+}
+
+static void scsifront_cmd_done(struct scsifront_info *info, int idx)
+{
+       struct scsi_front_ring *ring = &info->ring;
+       struct scsi_request *ring_req;
+       struct srp_cmd *cmd;
+       struct scsi_cmnd *sc;
+       struct srp_direct_buf *buf;
+       int i;
+
+       ring_req = RING_GET_REQUEST(ring, idx);
+       cmd = (struct srp_cmd *) ring_req->buf;
+       sc = (struct scsi_cmnd *) (long) cmd->tag;
+
+       if (!sc->request_buffer || (sc->sc_data_direction != DMA_TO_DEVICE &&
+                                   sc->sc_data_direction != DMA_FROM_DEVICE))
+               return;
+
+       if (sc->use_sg == 1) {
+               buf = (void *) cmd->add_data;
+               gnttab_end_foreign_access(buf->key, 0, 0UL);
+       } else {
+               struct srp_indirect_buf *ind = (void *) cmd->add_data;
+               buf = (struct srp_direct_buf *) ind->desc_list;
+
+               for (i = 0; i < sc->use_sg; i++, buf++)
+                       gnttab_end_foreign_access(buf->key, 0, 0UL);
+       }
+}
+
+static irqreturn_t scsifront_intr(int irq, void *dev_id,
+                                  struct pt_regs *ptregs)
+{
+       struct scsifront_info *info = (struct scsifront_info *) dev_id;
+       struct scsi_front_ring *ring = &info->ring;
+       struct scsi_response *ring_res;
+       struct scsi_cmnd *sc;
+       struct srp_rsp *rsp;
+       int i, rp;
+
+       if (info->dev->state != XenbusStateConnected)
+               return IRQ_HANDLED;
+
+again:
+       rp = info->ring.sring->rsp_prod;
+       rmb();
+
+       for (i = info->ring.rsp_cons; i != rp; i++) {
+               ring_res = RING_GET_RESPONSE(ring, i);
+
+               rsp = (struct srp_rsp *) ring_res->buf;
+               sc = ((void *) (unsigned long) rsp->tag);
+               sc->result = rsp->status;
+
+               scsifront_cmd_done(info, i);
+
+               if (rsp->flags & SRP_RSP_FLAG_SNSVALID) {
+                       memcpy(sc->sense_buffer, rsp->data +
+                              be32_to_cpu(rsp->resp_data_len),
+                              min_t(int, be32_to_cpu(rsp->sense_data_len),
+                                    SCSI_SENSE_BUFFERSIZE));
+               }
+
+               if (rsp->flags & (SRP_RSP_FLAG_DOOVER | SRP_RSP_FLAG_DOUNDER))
+                       sc->resid = be32_to_cpu(rsp->data_out_res_cnt);
+               else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | 
SRP_RSP_FLAG_DIUNDER))
+                       sc->resid = be32_to_cpu(rsp->data_in_res_cnt);
+
+               sc->scsi_done(sc);
+       }
+
+       info->ring.rsp_cons = i;
+       if (i != info->ring.req_prod_pvt) {
+               int more_to_do;
+               RING_FINAL_CHECK_FOR_RESPONSES(ring, more_to_do);
+               if (more_to_do)
+                       goto again;
+       } else
+               ring->sring->rsp_event = i + 1;
+
+       return IRQ_HANDLED;
+}
+
+static int scsifront_alloc_ring(struct scsifront_info *info)
+{
+       struct xenbus_device *dev = info->dev;
+       struct scsi_sring *sring;
+       int err = -ENOMEM;
+
+       sring = (struct scsi_sring *) __get_free_page(GFP_KERNEL);
+       if (!sring) {
+               xenbus_dev_fatal(dev, err, "fail to allocate shared ring");
+               return err;
+       }
+
+       SHARED_RING_INIT(sring);
+       FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
+       dprintk("%u\n", RING_SIZE(&info->ring));
+
+       err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
+       if (err < 0) {
+               xenbus_dev_fatal(dev, err, "fail to grant shared ring");
+               goto free_sring;
+       }
+       info->ring_ref = err;
+
+       err = xenbus_alloc_evtchn(dev, &info->evtchn);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "fail to allocate evtchn");
+               return err;
+       }
+
+       err = bind_evtchn_to_irqhandler(info->evtchn, scsifront_intr,
+                                       SA_SAMPLE_RANDOM, "scsifront", info);
+       if (err <= 0) {
+               xenbus_dev_fatal(dev, err, "bind_evtchn_to_irqhandler failed");
+               goto fail;
+       }
+       info->irq = err;
+
+       return 0;
+fail:
+       /* free resource */
+free_sring:
+       free_page((unsigned long) sring);
+
+       return err;
+}
+
+static int scsifront_init_ring(struct scsifront_info *info)
+{
+       struct xenbus_device *dev = info->dev;
+       struct xenbus_transaction xbt;
+       int err;
+
+       dprintk("");
+
+       err = scsifront_alloc_ring(info);
+       if (err)
+               return err;
+       dprintk("%lu %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", "%lu",
+                           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",
+                           info->evtchn);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "%s", "writing event-channel");
+               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 */
+       return err;
+}
+
+static struct scsi_host_template scsifront_sht = {
+       .module                 = THIS_MODULE,
+       .name                   = "Xen SCSI frontend driver",
+       .queuecommand           = scsifront_queuecommand,
+       .eh_abort_handler       = scsifront_eh_abort_handler,
+       .cmd_per_lun            = SRP_CAN_QUEUE,
+       .can_queue              = SRP_CAN_QUEUE,
+       .this_id                = -1,
+       .sg_tablesize           = SRP_MAX_INDIRECT,
+       .use_clustering         = DISABLE_CLUSTERING,
+       .proc_name              = "scsifront",
+};
+
+static int scsifront_probe(struct xenbus_device *dev,
+                           const struct xenbus_device_id *id)
+{
+       struct Scsi_Host *host;
+       struct scsifront_info *info;
+       int err = -ENOMEM;
+
+       host = scsi_host_alloc(&scsifront_sht, sizeof(*info));
+       if (!host) {
+               xenbus_dev_fatal(dev, err, "fail to allocate scsi host");
+               return err;
+       }
+       info = (struct scsifront_info *) host->hostdata;
+       dev->dev.driver_data = info;
+       info->dev = dev;
+       info->host = host;
+
+       err = scsifront_init_ring(info);
+       if (err)
+               scsi_host_put(host);
+
+       return err;
+}
+
+static int scsifront_connect(struct scsifront_info *info)
+{
+       struct xenbus_device *dev = info->dev;
+       struct Scsi_Host *host = info->host;
+       int err = -ENOMEM;
+
+       dprintk("%u\n", dev->state);
+       if (dev->state == XenbusStateConnected)
+               return 0;
+
+       xenbus_switch_state(dev, XenbusStateConnected);
+
+       host->max_id = 1;
+       host->max_channel = 0;
+
+       err = scsi_add_host(host, &dev->dev);
+       if (err) {
+               eprintk("fail to add scsi host %d\n", err);
+               return err;
+       }
+       scsi_scan_host(host);
+
+       return 0;
+}
+
+static int scsifront_remove(struct xenbus_device *dev)
+{
+       struct scsifront_info *info = dev->dev.driver_data;
+
+       scsi_remove_host(info->host);
+       scsi_host_put(info->host);
+
+       return 0;
+}
+
+static void scsifront_backend_changed(struct xenbus_device *dev,
+                                      XenbusState backend_state)
+{
+       struct scsifront_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 XenbusStateInitialised:
+       case XenbusStateClosed:
+               break;
+
+       case XenbusStateConnected:
+               scsifront_connect(info);
+               break;
+
+       case XenbusStateClosing:
+               break;
+       }
+}
+
+static struct xenbus_device_id scsifront_ids[] = {
+       { "scsi" },
+       { "" }
+};
+
+static struct xenbus_driver scsifront = {
+       .name                   = "scsi",
+       .owner                  = THIS_MODULE,
+       .ids                    = scsifront_ids,
+       .probe                  = scsifront_probe,
+       .remove                 = scsifront_remove,
+/*     .resume                 = scsifront_resume, */
+       .otherend_changed       = scsifront_backend_changed,
+};
+
+static int __init scsifront_init(void)
+{
+       if (!is_running_on_xen())
+               return -ENODEV;
+
+       return xenbus_register_frontend(&scsifront);
+}
+static void scsifront_exit(void)
+{
+       return xenbus_unregister_driver(&scsifront);
+}
+
+module_init(scsifront_init);
+module_exit(scsifront_exit);
+
+MODULE_AUTHOR("FUJITA Tomonori");
+MODULE_DESCRIPTION("Xen SCSI frontend driver");
+MODULE_LICENSE("GPL");
diff -r 105d5d6b4e0d -r 95ca3ffbdbfd xen/include/public/io/scsi.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/public/io/scsi.h      Wed Jan 03 01:35:35 2007 +0900
@@ -0,0 +1,42 @@
+#ifndef __XEN__PUBLIC_IO_SCSI_H__
+#define __XEN__PUBLIC_IO_SCSI_H__
+
+#include "ring.h"
+
+#define SRP_MAX_IU_LEN 256
+#define SRP_CAN_QUEUE 8
+
+struct scsi_request {
+       char buf[SRP_MAX_IU_LEN];
+};
+
+struct scsi_response {
+       char buf[sizeof(struct srp_rsp)];
+};
+
+DEFINE_RING_TYPES(scsi, struct scsi_request, struct scsi_response);
+
+#define SRP_MAX_INDIRECT ((SRP_MAX_IU_LEN -                    \
+                         sizeof (struct srp_cmd) -             \
+                         sizeof (struct srp_indirect_buf)) / 16)
+
+#define SRP_MAPPED_PAGES (SRP_CAN_QUEUE * SRP_MAX_INDIRECT)
+#define SRP_SG_SIZE (sizeof(struct iovec) * SRP_MAX_INDIRECT)
+#define SRP_RING_PAGES (((SRP_SG_SIZE * SRP_CAN_QUEUE)         \
+                       + PAGE_SIZE - 1) >> PAGE_SHIFT)
+
+/*
+ * We use iovec structure so the combination of 32-bit user-space tgtd
+ * and 64-bit kernel does not work.
+ */
+
+/*
+ * srp_cmd             : 48 bytes
+ * srp_direct_buf      : 16 bytes
+ * srp_indirect_buf    : 20 bytes
+ * SRP_MAX_INDIRECT    : 11
+ * SRP_MAX_MAPPED_PAGES        : 88
+ * SRP_RING_PAGES      : 1
+ */
+
+#endif

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


 


Rackspace

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