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 3/6] scsiback driver

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH 3/6] scsiback driver
From: FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx>
Date: Wed, 02 Aug 2006 17:32:23 +0900
Delivery-date: Wed, 02 Aug 2006 01:35:43 -0700
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
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [PATCH 3/6] scsiback driver, FUJITA Tomonori <=