All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jun Kamada <kama@jp.fujitsu.com>
Cc: kama@jp.fujitsu.com, xen-devel@lists.xensource.com
Subject: [RFC] [2/4] PV driver for FC transport layer (pv-scsi backend driver)
Date: Fri, 29 Jun 2007 20:06:55 +0900	[thread overview]
Message-ID: <20070629200619.69EC.KAMA@jp.fujitsu.com> (raw)
In-Reply-To: <20070629195146.69E6.KAMA@jp.fujitsu.com>

[-- Attachment #1: Type: text/plain, Size: 100 bytes --]



Jun Kamada
Linux Technology Development Div.
Server Systems Unit
Fujitsu Ltd.
kama@jp.fujitsu.com

[-- Attachment #2: scsiback.patch --]
[-- Type: application/octet-stream, Size: 27765 bytes --]

# HG changeset patch
# User Jun Kamada <kama@jp.fujitsu.com>
# Date 1183108100 -32400
# Node ID 06db0e13731c650c5b2ddf6d8048f9c89d89a012
# Parent  52f99cf7240f84e89740242828a3c09566139054
add scsiback driver

Signed-off-by: Tomonari Horikoshi <t.horikoshi@jp.fujitsu.com>
Signed-off-by: Tsunehisa Doi <Doi.Tsunehisa@jp.fujitsu.com>
Signed-off-by: Jun Kamada <kama@jp.fujitsu.com>
Signed-off-by: Akira Hayakawa <hayakawa.akira@jp.fujitsu.com>

diff -r 52f99cf7240f -r 06db0e13731c drivers/xen/scsiback/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/Makefile	Fri Jun 29 18:08:20 2007 +0900
@@ -0,0 +1,2 @@
+obj-$(CONFIG_XEN_SCSI_BACKEND)	+= scsibk.o
+scsibk-y			+= interface.o scsiback.o
diff -r 52f99cf7240f -r 06db0e13731c drivers/xen/scsiback/common.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/common.h	Fri Jun 29 18:08:20 2007 +0900
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2007, FUJITSU Limited
+ *
+ * Based on the blkback driver code.
+ *
+ * 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.
+ */
+
+#ifndef __SCSIIF__BACKEND__COMMON_H__
+#define __SCSIIF__BACKEND__COMMON_H__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/pgalloc.h>
+#include <xen/evtchn.h>
+#include <asm/hypervisor.h>
+#include <xen/gnttab.h>
+#include <xen/driver_util.h>
+#include <xen/xenbus.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/scsiif.h>
+
+#define DPRINTK(_f, _a...)			\
+	pr_debug("(file=%s, line=%d) " _f,	\
+		 __FILE__ , __LINE__ , ## _a )
+
+struct scsiback_info {
+	struct xenbus_device *dev;
+	struct Scsi_Host *host;
+	struct xenbus_watch backend_watch;
+
+	unsigned int evtchn;
+	unsigned int irq;
+
+	unsigned short host_no;
+
+	scsiif_back_ring_t ring;
+	struct vm_struct *ring_area;
+
+	grant_handle_t shmem_handle;
+	grant_ref_t shmem_ref;
+
+	struct work_struct scsiback_work;
+
+	spinlock_t ring_lock;
+	atomic_t refcnt;
+
+	struct task_struct *kthread;
+	wait_queue_head_t waiting_to_free;
+	wait_queue_head_t wq;
+	unsigned int waiting_reqs;
+
+	struct page **mmap_pages;
+};
+
+irqreturn_t scsiback_intr(int, void *, struct pt_regs *);
+int scsiback_init_sring(struct scsiback_info *,
+				unsigned long, unsigned int);
+int scsiback_schedule(void *data);
+
+
+#define scsiback_get(_b) (atomic_inc(&(_b)->refcnt))
+#define scsiback_put(_b)				\
+	do {						\
+		if (atomic_dec_and_test(&(_b)->refcnt))	\
+			wake_up(&(_b)->waiting_to_free);\
+	} while (0)
+
+struct scsiback_info *scsiinfo_alloc(domid_t domid);
+void scsiback_free(struct scsiback_info *info);
+void scsiback_disconnect(struct scsiback_info *info);
+void __init scsiback_interface_init(void);
+
+#endif /* __SCSIIF__BACKEND__COMMON_H__ */
diff -r 52f99cf7240f -r 06db0e13731c drivers/xen/scsiback/interface.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/interface.c	Fri Jun 29 18:08:20 2007 +0900
@@ -0,0 +1,165 @@
+/*
+ * interface management.
+ *
+ * Copyright (c) 2007, FUJITSU Limited
+ *
+ * Based on the blkback driver code.
+ *
+ * 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 "common.h"
+#include <xen/evtchn.h>
+#include <linux/kthread.h>
+
+static kmem_cache_t *scsiback_cachep;
+
+struct scsiback_info *scsiinfo_alloc(domid_t domid)
+{
+	struct scsiback_info *info;
+
+	info = kmem_cache_alloc(scsiback_cachep, GFP_KERNEL);
+	if (!info)
+		return ERR_PTR(-ENOMEM);
+
+	memset(info, 0, sizeof(*info));
+	spin_lock_init(&info->ring_lock);
+	atomic_set(&info->refcnt, 1);
+	init_waitqueue_head(&info->wq);
+	init_waitqueue_head(&info->waiting_to_free);
+
+	return info;
+}
+
+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);
+
+	err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
+	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;
+
+	return 0;
+}
+
+static void unmap_frontend_page(struct scsiback_info *info)
+{
+	struct gnttab_unmap_grant_ref op;
+	int err;
+
+	gnttab_set_unmap_op(&op, (unsigned long)info->ring_area->addr,
+				GNTMAP_host_map, info->shmem_handle);
+
+	err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
+	BUG_ON(err);
+}
+
+int scsiback_init_sring(struct scsiback_info *info,
+			 unsigned long shared_page, unsigned int evtchn)
+{
+	struct scsiif_sring *sring;
+	int err;
+
+	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;
+
+	sring = (struct scsiif_sring *) info->ring_area->addr;
+	BACK_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+	err = bind_interdomain_evtchn_to_irqhandler(
+			info->dev->otherend_id, evtchn,
+			scsiback_intr, 0, "scsiif-backend", info);
+
+	if (err < 0)
+		goto unmap_page;
+
+	info->irq = err;
+	return 0;
+
+unmap_page:
+	unmap_frontend_page(info);
+free_vm:
+	free_vm_area(info->ring_area);
+	return err;
+}
+
+void scsiback_disconnect(struct scsiback_info *info)
+{
+	if (info->kthread) {
+		kthread_stop(info->kthread);
+		info->kthread = NULL;
+	}
+
+	atomic_dec(&info->refcnt);
+	wait_event(info->waiting_to_free, atomic_read(&info->refcnt) == 0);
+	atomic_inc(&info->refcnt);
+
+	if (info->irq) {
+		unbind_from_irqhandler(info->irq, info);
+		info->irq = 0;
+	}
+
+	if (info->ring.sring) {
+		unmap_frontend_page(info);
+		free_vm_area(info->ring_area);
+		info->ring.sring = NULL;
+	}
+}
+
+void scsiback_free(struct scsiback_info *info)
+{
+	if (!atomic_dec_and_test(&info->refcnt))
+		BUG();
+	kmem_cache_free(scsiback_cachep, info);
+}
+
+void __init scsiback_interface_init(void)
+{
+	scsiback_cachep = kmem_cache_create("scsiif_cache",
+		sizeof(struct scsiback_info), 0, 0, NULL, NULL);
+}
diff -r 52f99cf7240f -r 06db0e13731c drivers/xen/scsiback/scsiback.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/scsiback.c	Fri Jun 29 18:08:20 2007 +0900
@@ -0,0 +1,716 @@
+/*
+ * Xen SCSI backend driver
+ *
+ * Copyright (c) 2007, FUJITSU Limited
+ *
+ * Based on the blkback driver code.
+ *
+ * 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/list.h>
+#include <linux/blkdev.h>
+#include <linux/kthread.h>
+#include <xen/balloon.h>
+#include <asm/hypervisor.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_dbg.h>
+#include "common.h"
+
+
+#define INVALID_GRANT_HANDLE	0xFFFF
+
+typedef struct {
+	struct scsiback_info *info;
+	unsigned long rqid;
+	int use_sg;
+	atomic_t pendcnt;
+	struct request *rq;
+	struct list_head free_list;
+} pending_req_t;
+
+static pending_req_t *pending_reqs;
+static struct list_head pending_free;
+static DEFINE_SPINLOCK(pending_free_lock);
+static DECLARE_WAIT_QUEUE_HEAD(pending_free_wq);
+
+#define SCSIBACK_INVALID_HANDLE (~0)
+
+static struct page **pending_pages;
+static grant_handle_t *pending_grant_handles;
+
+
+static inline int vaddr_pagenr(pending_req_t *req, int seg)
+{
+	return (req - pending_reqs) * SG_TABLESIZE + seg;
+}
+
+static inline unsigned long vaddr(pending_req_t *req, int seg)
+{
+	unsigned long pfn = page_to_pfn(pending_pages[vaddr_pagenr(req, seg)]);
+	return (unsigned long)pfn_to_kaddr(pfn);
+}
+
+#define pending_handle(_req, _seg) \
+	(pending_grant_handles[vaddr_pagenr(_req, _seg)])
+
+
+
+/******************************************************************
+ * misc small helpers
+ */
+static pending_req_t* alloc_req(void)
+{
+	pending_req_t *req = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pending_free_lock, flags);
+	if (!list_empty(&pending_free)) {
+		req = list_entry(pending_free.next, pending_req_t, free_list);
+		list_del(&req->free_list);
+	}
+	spin_unlock_irqrestore(&pending_free_lock, flags);
+	return req;
+}
+
+static void free_req(pending_req_t *req)
+{
+	unsigned long flags;
+	int was_empty;
+
+	spin_lock_irqsave(&pending_free_lock, flags);
+	was_empty = list_empty(&pending_free);
+	list_add(&req->free_list, &pending_free);
+	spin_unlock_irqrestore(&pending_free_lock, flags);
+	if (was_empty)
+		wake_up(&pending_free_wq);
+}
+
+
+static void fast_flush_area(pending_req_t *req)
+{
+	struct gnttab_unmap_grant_ref unmap[SG_TABLESIZE];
+	unsigned int i, invcount = 0;
+	grant_handle_t handle;
+	int err;
+
+	for (i = 0; i < req->use_sg; i++) {
+		handle = pending_handle(req, i);
+		if (handle == SCSIBACK_INVALID_HANDLE)
+			continue;
+		gnttab_set_unmap_op(&unmap[i], vaddr(req, i),
+					GNTMAP_host_map, handle);
+		pending_handle(req, i) = SCSIBACK_INVALID_HANDLE;
+		invcount++;
+	}
+
+	err = HYPERVISOR_grant_table_op(
+		GNTTABOP_unmap_grant_ref, unmap, invcount);
+	BUG_ON(err);
+}
+
+
+/******************************************************************************
+ * NOTIFICATION FROM GUEST OS.
+ */
+static void scsiback_notify_work(struct scsiback_info *info)
+{
+	info->waiting_reqs = 1;
+	wake_up(&info->wq);
+}
+
+irqreturn_t scsiback_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	scsiback_notify_work(dev_id);
+	return IRQ_HANDLED;
+}
+
+static void make_sense(struct scsiback_info *info, struct request *req,
+			int32_t result, uint64_t rqid)
+{
+	struct scsiif_response *resp;
+	unsigned long flags;
+	struct scsiif_back_ring *ring = &info->ring;
+	int more_to_do = 0;
+	int notify;
+
+	spin_lock_irqsave(&info->ring_lock, flags);
+
+	resp = RING_GET_RESPONSE(ring, ring->rsp_prod_pvt);
+	memset(resp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+
+	resp->result = result;
+	resp->rqid   = rqid;
+
+	if (req) {
+		memcpy(resp->sense_buffer, req->sense, req->sense_len);
+		resp->sense_len = req->sense_len;
+	} else
+		resp->sense_len = 0;
+
+	ring->rsp_prod_pvt++;
+
+	RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(ring, notify);
+
+	if (ring->rsp_prod_pvt == ring->req_cons) {
+		RING_FINAL_CHECK_FOR_REQUESTS(ring, more_to_do);
+
+	} else if (RING_HAS_UNCONSUMED_REQUESTS(ring)) {
+		more_to_do = 1;
+	}
+
+	spin_unlock_irqrestore(&info->ring_lock, flags);
+
+	if (more_to_do)
+		scsiback_notify_work(info);
+	if (notify)
+		notify_remote_via_irq(info->irq);
+}
+
+
+static void scsiback_end_cmd_fn(struct request *req, int error)
+{
+	unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
+	pending_req_t *pending_req = req->end_io_data;
+	pending_req->rq = req;
+
+	if (req->errors != 0) {
+		printk("Buffer not up-to-date at end of operation, "
+			"req->errors=0x%08x\n", req->errors);
+		memcpy(sense_buffer, req->sense, req->sense_len);
+		__scsi_print_sense("scsiback_end_cmd_fn", sense_buffer,
+				   req->sense_len);
+	}
+
+	if (atomic_dec_and_test(&pending_req->pendcnt)) {
+		fast_flush_area(pending_req);
+		make_sense(pending_req->info, pending_req->rq, 
+				req->errors, pending_req->rqid);
+		scsiback_put(pending_req->info);
+		free_req(pending_req);
+	}
+	
+	__blk_put_request(req->q, req);
+}
+
+
+/* quoted scsi_lib.c/scsi_merge_bio */
+static int scsiback_merge_bio(struct request *rq, struct bio *bio)
+{
+	struct request_queue *q = rq->q;
+
+	bio->bi_flags &= ~(1 << BIO_SEG_VALID);
+	if (rq_data_dir(rq) == WRITE)
+		bio->bi_rw |= (1 << BIO_RW);
+
+	blk_queue_bounce(q, &bio);
+
+	if (!rq->bio)
+		blk_rq_bio_prep(q, rq, bio);
+	else if (!q->back_merge_fn(q, rq, bio))
+		return -EINVAL;
+	else {
+		rq->biotail->bi_next = bio;
+		rq->biotail          = bio;
+		rq->hard_nr_sectors += bio_sectors(bio);
+		rq->nr_sectors       = rq->hard_nr_sectors;
+	}
+
+	return 0;
+}
+
+
+/* quoted scsi_lib.c/scsi_bi_endio */
+static int scsiback_bi_endio(struct bio *bio, unsigned int bytes_done, int error)
+{
+	if (bio->bi_size)
+		return 1;
+
+	bio_put(bio);
+	return 0;
+}
+
+
+/* quoted scsi_lib.c/scsi_req_map_sg . */
+static int requset_map_sg(struct scsiif_request *ring_req,
+				pending_req_t *pending_req)
+{
+	struct request *rq = pending_req->rq;
+	struct request_queue *q = pending_req->rq->q;
+	int nr_pages;
+	int nsegs = pending_req->use_sg;
+	unsigned int data_len = 0, len, bytes, off;
+	struct page *page;
+	struct bio *bio = NULL;
+	int i, err, nr_vecs = 0;
+
+	for (i = 0; i < nsegs; i++) {
+		page = virt_to_page(vaddr(pending_req, i));
+		off = ring_req->seg[i].offset;
+		len = ring_req->seg[i].length;
+		data_len += len;
+
+		nr_pages = (len + off + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+		while (len > 0) {
+			bytes = min_t(unsigned int, len, PAGE_SIZE - off);
+
+			if (!bio) {
+				nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages);
+				nr_pages -= nr_vecs;
+				bio = bio_alloc(GFP_KERNEL, nr_vecs);
+				if (!bio) {
+					err = -ENOMEM;
+					goto free_bios;
+				}
+				bio->bi_end_io = scsiback_bi_endio;
+			}
+
+			if (bio_add_pc_page(q, bio, page, bytes, off) !=
+						bytes) {
+				bio_put(bio);
+				err = -EINVAL;
+				goto free_bios;
+			}
+
+			if (bio->bi_vcnt >= nr_vecs) {
+				err = scsiback_merge_bio(rq, bio);
+				if (err) {
+					bio_endio(bio, bio->bi_size, 0);
+					goto free_bios;
+				}
+				bio = NULL;
+			}
+
+			page++;
+			len -= bytes;
+			off = 0;
+		}
+	}
+
+	rq->buffer   = rq->data = NULL;
+	rq->data_len = data_len;
+	return 0;
+
+free_bios:
+	while ((bio = rq->bio) != NULL) {
+		rq->bio = bio->bi_next;
+		/*
+		 * call endio instead of bio_put incase it was bounced
+		 */
+		bio_endio(bio, bio->bi_size, 0);
+	}
+	return err;
+}
+
+
+static void scsiback_cmd_exec(struct scsiback_info *info,
+		struct scsiif_request *ring_req, pending_req_t *pending_req)
+{
+
+	struct gnttab_map_grant_ref map[SG_TABLESIZE];
+	struct scsi_device *sdev;
+	char sense[SCSI_SENSE_BUFFERSIZE];
+
+	int i, err = 0;
+	int write = (ring_req->sc_data_direction == DMA_TO_DEVICE);
+	u32 flags, use_sg;
+
+	use_sg = ring_req->use_sg;
+	sdev   = scsi_device_lookup(info->host, ring_req->channel,
+					ring_req->id, ring_req->lun);
+
+	if (sdev == NULL) {
+		printk("Scsi Device Not Found\n");
+		goto fail_response;
+	}
+
+	pending_req->rq     = blk_get_request(sdev->request_queue,
+						write, GFP_KERNEL);
+	pending_req->info   = info;
+	pending_req->rqid   = ring_req->rqid;
+	pending_req->use_sg = use_sg;
+
+
+	pending_req->rq->flags  |= REQ_BLOCK_PC;
+	pending_req->rq->cmd_len = ring_req->cmd_len;
+	memcpy(pending_req->rq->cmd, ring_req->cmnd, ring_req->cmd_len);
+
+	memset(sense, 0, sizeof(sense)); /*FIXME*/
+	pending_req->rq->sense     = sense;
+	pending_req->rq->sense_len = 0;
+
+	pending_req->rq->retries   = ring_req->retries;
+	pending_req->rq->timeout   = ring_req->timeout_per_command;
+
+	pending_req->rq->end_io_data = pending_req;
+
+	for (i = 0; i < use_sg; i++) {
+		flags = GNTMAP_host_map;
+		if (write)
+			flags |= GNTMAP_readonly;
+
+		gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags,
+					ring_req->seg[i].gref,
+					info->dev->otherend_id);
+	}
+
+	if (use_sg) { 
+		err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
+							map, use_sg);
+		BUG_ON(err);
+	}
+
+	for (i = 0; i < use_sg; i++) {		
+		if (unlikely(map[i].status != 0)) {
+			printk("invalid buffer -- could not remap it\n");
+			map[i].handle = SCSIBACK_INVALID_HANDLE;
+			err |= 1;
+		}
+
+		pending_handle(pending_req, i) = map[i].handle;
+
+		if (err)
+			continue;
+
+		set_phys_to_machine(__pa(vaddr(
+			pending_req, i)) >> PAGE_SHIFT,
+			FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT));
+	}
+
+	if (err)
+		goto fail_flush;
+
+	if (use_sg) { 
+		if (requset_map_sg(ring_req, pending_req)) {
+			printk("SG Request Map Error\n");
+			goto fail_map;
+		}
+	}
+
+	atomic_set(&pending_req->pendcnt, 1);
+	scsiback_get(info);
+
+	blk_execute_rq_nowait(pending_req->rq->q, NULL, pending_req->rq,
+				1, scsiback_end_cmd_fn);
+
+	return ;
+
+fail_map:
+fail_flush:
+	fast_flush_area(pending_req);
+fail_response:
+	make_sense(info, NULL, 1, ring_req->rqid);
+	free_req(pending_req);
+	printk("%s error\n",__FUNCTION__);
+}
+
+static int do_scsiback_cmd_fn(struct scsiback_info *info)
+{
+	struct scsiif_back_ring *ring = &info->ring;
+	struct scsiif_request *ring_req;
+
+	pending_req_t *pending_req;
+	RING_IDX rc, rp;
+	int more_to_do = 0;
+
+	rc = ring->req_cons;
+	rp = ring->sring->req_prod;
+	rmb();
+
+	while ((rc != rp) && !RING_REQUEST_CONS_OVERFLOW(ring, rc)) {
+
+		pending_req = alloc_req();
+		if (NULL == pending_req) {
+			more_to_do = 1;
+			break;
+		}
+
+		ring_req = RING_GET_REQUEST(ring, rc);
+		ring->req_cons = ++rc;
+
+		scsiback_cmd_exec(info, ring_req, pending_req);
+	}
+
+	return more_to_do;
+}
+
+int scsiback_schedule(void *data)
+{
+	struct scsiback_info *info = data;
+
+	scsiback_get(info);
+
+	while (!kthread_should_stop()) {
+		wait_event_interruptible(
+			info->wq,
+			info->waiting_reqs || kthread_should_stop());
+		wait_event_interruptible(
+			pending_free_wq,
+			!list_empty(&pending_free) || kthread_should_stop());
+
+		info->waiting_reqs = 0;
+		smp_mb();
+
+		if (do_scsiback_cmd_fn(info))
+			info->waiting_reqs = 1;
+	}
+
+	info->kthread = NULL;
+	scsiback_put(info);
+
+	return 0;
+}
+
+
+static int scsiback_remove(struct xenbus_device *dev)
+{
+	struct scsiback_info *info = dev->dev.driver_data;
+
+	if (info->backend_watch.node) {
+		unregister_xenbus_watch(&info->backend_watch);
+		kfree(info->backend_watch.node);
+		info->backend_watch.node = NULL;
+	}
+
+	if (info) {
+		scsiback_disconnect(info);
+		scsiback_free(info);
+		info = NULL;
+	}
+
+	kfree(info);
+
+	return 0;
+}
+
+
+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;
+	}
+
+	err = scsiback_init_sring(info, ring_ref, evtchn);
+	if (err) {
+		return err;
+	}
+
+	info->kthread = kthread_run(scsiback_schedule, info, "scsiif");
+	if (IS_ERR(info->kthread)) {
+		err = PTR_ERR(info->kthread);
+		info->kthread = NULL;
+		xenbus_dev_error(info->dev, err, "start scsiif");
+	}
+
+	return 0;
+}
+
+static void scsiback_frontend_changed(struct xenbus_device *dev,
+					enum xenbus_state frontend_state)
+{
+	struct scsiback_info *info = dev->dev.driver_data;
+	int err;
+
+	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:
+		scsiback_disconnect(info);
+		xenbus_switch_state(dev, XenbusStateClosing);
+		break;
+
+	case XenbusStateClosed:
+		xenbus_switch_state(dev, XenbusStateClosed);
+		if (xenbus_dev_is_online(dev))
+			break;
+
+	case XenbusStateUnknown:
+		/*
+		 * workaround.
+		 */
+		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);
+
+	printk("%s %p %u\n", __FUNCTION__, info->dev, info->dev->state);
+
+	/*FIXME*/
+}
+
+
+static int scsiback_probe(struct xenbus_device *dev,
+			   const struct xenbus_device_id *id)
+{
+	int err, hostno;
+	struct scsiback_info *info;
+
+
+	DPRINTK("%p %d\n", dev, dev->otherend_id);
+
+	err = xenbus_scanf(XBT_NIL, dev->nodename, "hostno", "%d", &hostno);
+	if (err == -ENOENT ) {
+		printk("error xenbus_scanf hostno=%d\n",hostno);
+		goto fail;
+	}
+
+	info = scsiinfo_alloc(dev->otherend_id);
+	if (IS_ERR(info)) {
+		err = PTR_ERR(info);
+		info = NULL;
+		xenbus_dev_fatal(dev, err, "creating block interface");
+		goto fail;
+	}
+
+	info->host = scsi_host_lookup(hostno);
+
+	dev->dev.driver_data = info;
+
+	info->dev = dev;
+	info->irq = 0;
+
+	err = xenbus_watch_path2(dev, dev->nodename,
+				"scsi-host",
+				&info->backend_watch,
+				scsiback_backend_changed);
+	if (err)
+		goto fail;
+
+	err = xenbus_switch_state(dev, XenbusStateInitWait);
+	if (err)
+		goto fail;
+
+	return 0;
+
+fail:
+	printk("%s failed\n",__FUNCTION__);
+	scsiback_remove(dev);
+
+	return err;
+}
+
+
+static struct xenbus_device_id scsiback_ids[] = {
+	{ "scsihost" },
+	{ "" }
+};
+
+static struct xenbus_driver scsiback = {
+	.name			= "scsihost",
+	.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;
+	int i, mmap_pages;
+
+	if (!is_running_on_xen())
+		return -ENODEV;
+
+	mmap_pages = CAN_QUEUE * SG_TABLESIZE;
+
+	pending_reqs          = kmalloc(sizeof(pending_reqs[0]) *
+					CAN_QUEUE, GFP_KERNEL);
+	pending_grant_handles = kmalloc(sizeof(pending_grant_handles[0]) *
+					mmap_pages, GFP_KERNEL);
+	pending_pages         = alloc_empty_pages_and_pagevec(mmap_pages);
+
+	if (!pending_reqs || !pending_grant_handles || !pending_pages)
+		goto out_of_memory;
+
+	for (i = 0; i < mmap_pages; i++)
+		pending_grant_handles[i] = SCSIBACK_INVALID_HANDLE;
+
+	scsiback_interface_init();
+
+	memset(pending_reqs, 0, sizeof(pending_reqs));
+	INIT_LIST_HEAD(&pending_free);
+
+	for (i = 0; i < CAN_QUEUE; i++)
+		list_add_tail(&pending_reqs[i].free_list, &pending_free);
+
+	err = xenbus_register_backend(&scsiback);
+	if (err)
+		goto out_of_memory;
+
+	return 0;
+
+ out_of_memory:
+	kfree(pending_reqs);
+	kfree(pending_grant_handles);
+	free_empty_pages_and_pagevec(pending_pages, mmap_pages);
+	printk("%s: out of memory\n", __FUNCTION__);
+	return -ENOMEM;
+}
+
+module_init(scsiback_init);
+
+MODULE_DESCRIPTION("Xen SCSI backend driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff -r 52f99cf7240f -r 06db0e13731c include/public/io/scsiif.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/public/io/scsiif.h	Fri Jun 29 18:08:20 2007 +0900
@@ -0,0 +1,49 @@
+/*
+ * Copyright(c) FUJITSU Limited 2007.
+ *
+ * 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.
+ *
+ * Based on the blkback/blkfront driver code.
+ *
+ */
+#ifndef __XEN__PUBLIC_IO_SCSI_H__
+#define __XEN__PUBLIC_IO_SCSI_H__
+
+#include "ring.h"
+#include "../grant_table.h"
+
+#define CAN_QUEUE	8
+#define SG_TABLESIZE	11
+
+struct scsiif_request {
+#define MAX_COMMAND_SIZE	16
+	uint8_t cmnd[MAX_COMMAND_SIZE];
+	uint8_t cmd_len;
+	uint32_t id, lun, channel;
+	uint16_t sc_data_direction;
+	uint16_t use_sg;
+	uint16_t request_bufflen;
+	int32_t retries;
+	int32_t timeout_per_command;
+	uint64_t rqid;
+	struct scsiif_request_segment{
+		grant_ref_t gref;
+		uint32_t offset;
+		uint32_t length;
+	} seg[SG_TABLESIZE];
+};
+
+struct scsiif_response {
+	uint64_t rqid;
+	int32_t result;
+	uint64_t sense_len;
+#define SCSI_SENSE_BUFFERSIZE 	96
+	uint8_t sense_buffer[SCSI_SENSE_BUFFERSIZE];
+};
+
+DEFINE_RING_TYPES(scsiif, struct scsiif_request, struct scsiif_response);
+
+#endif

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

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

  parent reply	other threads:[~2007-06-29 11:06 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-06-29 11:04 [RFC] [0/4] PV driver for FC transport layer Jun Kamada
2007-06-29 11:06 ` [RFC] [1/4] PV driver for FC transport layer (config files for pv-scsi) Jun Kamada
2007-06-29 11:06 ` Jun Kamada [this message]
2007-06-29 11:07 ` [RFC] [3/4] PV driver for FC transport layer (pv-scsi frontend driver) Jun Kamada
2007-06-29 11:08 ` [RFC] [4/4] PV driver for FC transport layer (FC transport layer driver) Jun Kamada
2007-07-03  0:07 ` [RFC] [0/4] PV driver for FC transport layer Ian Pratt
2007-07-04 11:03   ` Jun Kamada
2007-07-06  0:22     ` FUJITA Tomonori
2007-07-06  6:44       ` Jun Kamada
2007-07-06  7:26         ` FUJITA Tomonori
2007-07-06  8:54           ` Jun Kamada
2007-07-06  0:22   ` FUJITA Tomonori

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070629200619.69EC.KAMA@jp.fujitsu.com \
    --to=kama@jp.fujitsu.com \
    --cc=xen-devel@lists.xensource.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.