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-devel

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

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH 2/4] add scsifront/scsiback drivers
From: FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx>
Date: Wed, 03 Jan 2007 02:57:55 +0900
Delivery-date: Tue, 02 Jan 2007 09:59:17 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [PATCH 2/4] add scsifront/scsiback drivers, FUJITA Tomonori <=