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
|