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

[Xen-devel] [PATCH 3/6] scsiback driver



# HG changeset patch
# User fujita.tomonori@xxxxxxxxxxxxx
# Node ID 4e1a4618df3a66d8100b3f50c96fafe523858440
# Parent  7111077b493ea53ef055ce38098f8af67f87d749
SCSI backend driver

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

diff -r 7111077b493e -r 4e1a4618df3a 
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 Aug 02 
15:15:04 2006 +0900
@@ -0,0 +1,2 @@
+obj-$(CONFIG_XEN_SCSI_BACKEND) += scsibk.o
+scsibk-y                       += interface.o libsrp.o scsiback.o
diff -r 7111077b493e -r 4e1a4618df3a 
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 Aug 02 
15:15:04 2006 +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 7111077b493e -r 4e1a4618df3a 
linux-2.6-xen-sparse/drivers/xen/scsiback/libsrp.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/scsiback/libsrp.c        Wed Aug 02 
15:15:04 2006 +0900
@@ -0,0 +1,264 @@
+/*
+ * SCSI RDAM Protocol lib functions
+ *
+ * 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/err.h>
+#include <linux/kfifo.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_tgt.h>
+#include <scsi/srp.h>
+#include "libsrp.h"
+
+enum srp_task_attributes {
+       SRP_SIMPLE_TASK = 0,
+       SRP_HEAD_TASK = 1,
+       SRP_ORDERED_TASK = 2,
+       SRP_ACA_TASK = 4
+};
+
+/* tmp - will replace with SCSI logging stuff */
+#define eprintk(fmt, args...)                                  \
+do {                                                           \
+       printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);  \
+} while (0)
+#define dprintk eprintk
+/* #define dprintk(fmt, args...) */
+
+static int data_out_desc_size(struct srp_cmd *cmd)
+{
+       int size = 0;
+       u8 fmt = cmd->buf_fmt >> 4;
+
+       switch (fmt) {
+       case SRP_NO_DATA_DESC:
+               break;
+       case SRP_DATA_DESC_DIRECT:
+               size = sizeof(struct srp_direct_buf);
+               break;
+       case SRP_DATA_DESC_INDIRECT:
+               size = sizeof(struct srp_indirect_buf) +
+                       sizeof(struct srp_direct_buf) * cmd->data_out_desc_cnt;
+               break;
+       default:
+               eprintk("client error. Invalid data_out_format %x\n", fmt);
+               break;
+       }
+       return size;
+}
+
+int srp_rw(struct srp_cmd *cmd)
+{
+       return (cmd->buf_fmt >> 4) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+}
+
+static u8 srp_format(struct srp_cmd *cmd)
+{
+       if (srp_rw(cmd) == DMA_TO_DEVICE)
+               return cmd->buf_fmt >> 4;
+       else
+               return cmd->buf_fmt & ((1U << 4) - 1);
+}
+
+static int srp_offset(struct srp_cmd *cmd)
+{
+       int offset, rw;
+
+       offset = cmd->add_cdb_len * 4;
+       rw = srp_rw(cmd);
+       if (rw == DMA_FROM_DEVICE)
+               offset += data_out_desc_size(cmd);
+
+       return offset;
+}
+
+int srp_nmd(struct srp_cmd *cmd)
+{
+       struct srp_indirect_buf *id;
+       u8 format;
+       int rw, nmd, offset;
+
+       rw = srp_rw(cmd);
+       offset = srp_offset(cmd);
+       format = srp_format(cmd);
+       switch (format) {
+       case SRP_NO_DATA_DESC:
+               nmd = 0;
+               break;
+       case SRP_DATA_DESC_DIRECT:
+               nmd = 1;
+               break;
+       case SRP_DATA_DESC_INDIRECT:
+               id = (struct srp_indirect_buf *)(cmd->add_data + offset);
+               nmd = id->table_desc.len / sizeof(struct srp_direct_buf);
+               break;
+       default:
+               eprintk("Unknown format %x\n", format);
+               nmd = -EINVAL;
+               break;
+       }
+
+       return nmd;
+}
+
+static struct srp_direct_buf *srp_md(struct srp_cmd *cmd, int idx)
+{
+       struct srp_direct_buf *md = NULL;
+       struct srp_indirect_buf *id;
+       int rw, nmd, offset;
+       u8 format;
+
+       rw = srp_rw(cmd);
+       offset = srp_offset(cmd);
+       format = srp_format(cmd);
+       switch (format) {
+       case SRP_DATA_DESC_DIRECT:
+               md = (struct srp_direct_buf *)(cmd->add_data + offset);
+               break;
+       case SRP_DATA_DESC_INDIRECT:
+               id = (struct srp_indirect_buf *)
+                       (cmd->add_data + offset);
+               nmd = id->table_desc.len / sizeof(struct srp_direct_buf);
+
+               /* This should be true for Xen scsifront */
+               if ((rw == DMA_FROM_DEVICE && nmd == cmd->data_in_desc_cnt) ||
+                   (rw == DMA_TO_DEVICE && nmd == cmd->data_out_desc_cnt))
+                       md = &id->desc_list[0];
+               else
+                       BUG_ON(1);
+
+               md = &md[idx];
+               break;
+       case SRP_NO_DATA_DESC:
+       default:
+               eprintk("invalid %x\n", format);
+               break;
+       }
+
+       return md;
+}
+
+u64 srp_key(struct srp_cmd *cmd, int idx)
+{
+       struct srp_direct_buf *md = NULL;
+
+       md = srp_md(cmd, idx);
+       return md ? md->key : 0;
+}
+
+u64 srp_addr(struct srp_cmd *cmd, int idx)
+{
+       struct srp_direct_buf *md = NULL;
+
+       md = srp_md(cmd, idx);
+       return md ? md->va : 0;
+}
+
+u32 srp_len(struct srp_cmd *cmd, int idx)
+{
+       struct srp_direct_buf *md = NULL;
+
+       md = srp_md(cmd, idx);
+       return md ? md->len : 0;
+}
+
+static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
+{
+       struct srp_direct_buf *md;
+       struct srp_indirect_buf *id;
+       int len = 0, offset = cmd->add_cdb_len * 4;
+       u8 fmt;
+
+       if (dir == DMA_TO_DEVICE)
+               fmt = cmd->buf_fmt >> 4;
+       else {
+               fmt = cmd->buf_fmt & ((1U << 4) - 1);
+               offset += data_out_desc_size(cmd);
+       }
+
+       switch (fmt) {
+       case SRP_NO_DATA_DESC:
+               break;
+       case SRP_DATA_DESC_DIRECT:
+               md = (struct srp_direct_buf *) (cmd->add_data + offset);
+               len = md->len;
+               break;
+       case SRP_DATA_DESC_INDIRECT:
+               id = (struct srp_indirect_buf *) (cmd->add_data + offset);
+               len = id->len;
+               break;
+       default:
+               eprintk("invalid data format %x\n", fmt);
+               break;
+       }
+       return len;
+}
+
+int srp_cmd_perform(struct Scsi_Host *host, struct srp_cmd *cmd, void *data, 
u64 uaddr)
+{
+       enum dma_data_direction data_dir;
+       struct scsi_cmnd *sc;
+       int tag, len;
+
+       tag = MSG_SIMPLE_TAG;
+
+       switch (cmd->task_attr) {
+       case SRP_SIMPLE_TASK:
+               tag = MSG_SIMPLE_TAG;
+               break;
+       case SRP_ORDERED_TASK:
+               tag = MSG_ORDERED_TAG;
+               break;
+       case SRP_HEAD_TASK:
+               tag = MSG_HEAD_TAG;
+               break;
+       default:
+               eprintk("Task attribute %d not supported\n", cmd->task_attr);
+               tag = MSG_ORDERED_TAG;
+       }
+
+       if (cmd->buf_fmt >> 4)
+               data_dir = DMA_TO_DEVICE;
+       else
+               data_dir = DMA_FROM_DEVICE;
+       len = vscsis_data_length(cmd, data_dir);
+
+       dprintk("%x %llx %d %d %d %llx\n", cmd->cdb[0],
+               (unsigned long long) cmd->lun, data_dir,
+               len, tag, (unsigned long long) cmd->tag);
+
+       sc = scsi_host_get_command(host, data_dir, GFP_KERNEL);
+       BUG_ON(!sc);
+       memcpy(sc->cmnd, cmd->cdb, MAX_COMMAND_SIZE);
+       sc->request_bufflen = len;
+       sc->request_buffer = (void *) (unsigned long)uaddr;
+       sc->tag = tag;
+       sc->SCp.ptr = data;
+       sc->host_scribble = (void *) host;
+       scsi_tgt_queue_command(sc, (struct scsi_lun *) &cmd->lun, cmd->tag);
+
+       return 0;
+}
+
+MODULE_DESCRIPTION("SCSI RDAM Protocol lib functions");
+MODULE_AUTHOR("FUJITA Tomonori");
+MODULE_LICENSE("GPL");
diff -r 7111077b493e -r 4e1a4618df3a 
linux-2.6-xen-sparse/drivers/xen/scsiback/libsrp.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/scsiback/libsrp.h        Wed Aug 02 
15:15:04 2006 +0900
@@ -0,0 +1,20 @@
+#ifndef __LIBSRP_H__
+#define __LIBSRP_H__
+
+#include <linux/list.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/srp.h>
+
+typedef int (rdma_io_t) (struct scsi_cmnd *, struct scatterlist *, int,
+                        struct srp_direct_buf *, int, unsigned int);
+
+extern int srp_cmd_perform(struct Scsi_Host *, struct srp_cmd *, void *, u64);
+extern int srp_transfer_data(struct scsi_cmnd *, struct srp_cmd *, rdma_io_t);
+extern int srp_nmd(struct srp_cmd *);
+extern int srp_rw(struct srp_cmd *);
+extern u64 srp_key(struct srp_cmd *, int);
+extern u64 srp_addr(struct srp_cmd *, int);
+extern u32 srp_len(struct srp_cmd *, int);
+
+#endif
diff -r 7111077b493e -r 4e1a4618df3a 
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 Aug 02 
15:15:04 2006 +0900
@@ -0,0 +1,579 @@
+/*
+ * 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 <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"
+#include "libsrp.h"
+
+#define eprintk(fmt, args...)                                  \
+do {                                                           \
+       printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);  \
+} while (0)
+
+#define dprintk eprintk
+
+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 vaddr(struct scsiback_info *info, u64 start,
+                          struct scsi_request *req, int i)
+{
+       return start + (__idx(info, req, i) << PAGE_SHIFT);
+}
+
+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(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;
+       struct vm_area_struct *vma = info->mmap_vma;
+       struct gnttab_unmap_grant_ref unmap[SRP_MAX_INDIRECT * 2];
+       int i, op, err, nmd, offset;
+
+       nmd = srp_nmd(cmd);
+       if (!nmd)
+               goto send_rsp;
+       for (op = i = 0; i < nmd; i++) {
+               u64 kaddr, uaddr, ptep;
+               struct page *page, **map = vma->vm_private_data;
+
+               uaddr = vaddr(info, info->ustart, req, i);
+               kaddr = vaddr(info, info->kstart, req, i);
+
+               page = pfn_to_page(__pa(kaddr) >> PAGE_SHIFT);
+               ClearPageReserved(page);
+               offset = (uaddr - vma->vm_start) >> PAGE_SHIFT;
+               map[offset] = NULL;
+
+               gnttab_set_unmap_op(&unmap[op++], kaddr, GNTMAP_host_map,
+                                   info->handle[__idx(info, req, i)].k);
+
+               err = create_lookup_pte_addr(vma->vm_mm, uaddr, &ptep);
+               BUG_ON(err); /* FIXME */
+
+               gnttab_set_unmap_op(&unmap[op++], ptep, GNTMAP_host_map,
+                                   info->handle[__idx(info, req, i)].u);
+       }
+       err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, op);
+       BUG_ON(err);
+
+       zap_page_range(vma, vaddr(info, info->ustart, req, 0),
+                      nmd << PAGE_SHIFT, NULL);
+
+send_rsp:
+       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,
+};
+
+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 scsi_iovec *vec;
+       struct vm_area_struct *vma = info->mmap_vma;
+       struct gnttab_map_grant_ref map[SRP_MAX_INDIRECT * 2];
+       struct page *page;
+       struct iovec *iov;
+       RING_IDX rc, rp;
+       int i, op, nmd, err;
+       u64 uaddr, kaddr, ptep;
+
+       rc = ring->req_cons;
+       rp = ring->sring->req_prod;
+       rmb();
+
+       while ((rc != rp) && !RING_REQUEST_CONS_OVERFLOW(ring, rc)) {
+               eprintk("%u %u\n", rc, rp);
+               req = RING_GET_REQUEST(ring, rc);
+               ring->req_cons = ++rc;
+               cmd = (struct srp_cmd *) req->buf;
+               nmd = srp_nmd(cmd);
+
+               eprintk("%d %x %x\n", nmd, cmd->opcode, cmd->cdb[0]);
+
+               vec = (struct scsi_iovec *)
+                       (info->uring + sizeof(*vec) * req_index(info, req));
+               vec->iovcnt = nmd;
+               if (!nmd)
+                       goto no_data;
+
+               for (op = i = 0; i < nmd; i++) {
+                       u32 flags;
+                       int dir;
+
+                       uaddr = vaddr(info, info->ustart, req, i);
+                       kaddr = vaddr(info, info->kstart, req, i);
+
+                       eprintk("%d %llx %llx\n", i, uaddr, kaddr);
+
+                       page = virt_to_page(kaddr);
+
+                       dir = srp_rw(cmd);
+                       flags = GNTMAP_host_map;
+                       if (dir == DMA_TO_DEVICE)
+                               flags |= GNTMAP_readonly;
+
+                       gnttab_set_map_op(&map[op], kaddr, flags,
+                                         srp_key(cmd, i),
+                                         info->dev->otherend_id);
+                       op++;
+
+                       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,
+                                         srp_key(cmd, i),
+                                         info->dev->otherend_id);
+                       op++;
+               }
+
+               err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, 
op);
+               BUG_ON(err);
+
+               iov = vec->iov;
+               for (i = 0; i < nmd; i++) {
+                       int offset, j, idx;
+
+                       j = i * 2;
+                       idx = __idx(info, req, i);
+
+                       uaddr = vaddr(info, info->ustart, req, i);
+                       kaddr = vaddr(info, info->kstart, req, i);
+
+                       /* FIXME */
+                       BUG_ON(map[j].status || 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 = srp_addr(cmd, i) & (PAGE_SIZE-1);
+                       iov[i].iov_base = (void *) ((unsigned long) uaddr + 
offset);
+                       iov[i].iov_len = srp_len(cmd, i);
+
+                       eprintk("%llx %d %p %d\n", uaddr, offset, 
iov[i].iov_base,
+                               iov[i].iov_len);
+               }
+
+       no_data:
+               srp_cmd_perform(info->host, cmd, req,
+                               vma->vm_start + sizeof(*vec) * req_index(info, 
req));
+       }
+}
+
+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:
+               device_unregister(&dev->dev);
+               break;
+
+       case XenbusStateUnknown:
+       case XenbusStateInitWait:
+       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 i, err, nr = SRP_RING_PAGES + SRP_MAPPED_PAGES;
+       struct Scsi_Host *host;
+       struct scsiback_info *info;
+       struct page *page;
+       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;
+
+       page = balloon_alloc_empty_page_range(nr);
+       if (!page)
+               goto free_ring;
+       SetPageReserved(virt_to_page(info->uring));
+
+       for (i = 0; i < nr; i++)
+               get_page(&page[i]);
+       info->kstart = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
+       info->mmap_page = page;
+
+       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:
+       balloon_dealloc_empty_page_range(info->mmap_page, 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;
+       struct vm_area_struct *vma = info->mmap_vma;
+
+       if (vma) {
+               zap_page_range(vma, vma->vm_start,
+                              vma->vm_end - vma->vm_start, NULL);
+               info->mmap_vma = NULL;
+       }
+
+       free_page(info->uring);
+       balloon_dealloc_empty_page_range(info->mmap_page,
+                                        SRP_RING_PAGES + SRP_MAPPED_PAGES);
+       scsi_remove_host(host);
+       scsi_host_put(host);
+       return 0;
+}
+
+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;
+
+       /* TODO we need to prevent this scsi host from going away. */
+
+       vma->vm_flags |= VM_RESERVED;
+/*     vma->vm_ops = &vscsiback_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;
+       }
+
+       /* not sure if I really need to do this... */
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+       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;
+               goto zap;
+       }
+
+       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("%u start %lx, end %lx ustart %llx\n",
+               hostno, vma->vm_start, vma->vm_end, info->ustart);
+
+       info->mmap_vma = vma;
+zap:
+       if (err)
+               zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, 
NULL);
+host_put:
+       scsi_host_put(host);
+
+       return err;
+}
+
+static struct file_operations scsiback_fops = {
+       .owner                  = THIS_MODULE,
+       .mmap                   = scsiback_mmap,
+};
+
+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;
+
+       eprintk("%u %lu\n", SRP_MAPPED_PAGES, SRP_RING_PAGES);
+
+       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 7111077b493e -r 4e1a4618df3a 
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 Aug 02 
15:15:04 2006 +0900
@@ -0,0 +1,36 @@
+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_page;
+       u64 kstart;
+       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 *);

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


 


Rackspace

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