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] [3/4] PV driver for FC transport layer (pv-scsi frontend driver)
Date: Fri, 29 Jun 2007 20:07:32 +0900	[thread overview]
Message-ID: <20070629200701.69EF.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: scsifront.patch --]
[-- Type: application/octet-stream, Size: 14169 bytes --]

# HG changeset patch
# User Jun Kamada <kama@jp.fujitsu.com>
# Date 1183108159 -32400
# Node ID 0f169b36be81293df09f1c66b6284dc00270854f
# Parent  06db0e13731c650c5b2ddf6d8048f9c89d89a012
add scsifront 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 06db0e13731c -r 0f169b36be81 drivers/xen/scsifront/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/Makefile	Fri Jun 29 18:09:19 2007 +0900
@@ -0,0 +1,4 @@
+obj-$(CONFIG_XEN_SCSI_FRONTEND)	:= xenscsi.o
+
+xenscsi-objs := scsifront.o
+
diff -r 06db0e13731c -r 0f169b36be81 drivers/xen/scsifront/scsifront.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/scsifront.c	Fri Jun 29 18:09:19 2007 +0900
@@ -0,0 +1,524 @@
+/*
+ * Xen SCSI frontend driver
+ *
+ * Copyright (c) 2007, FUJITSU Limited
+ *
+ * Based on the scsifront driver code by FUJITA Tomonori
+ *
+ * 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/scatterlist.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 <xen/evtchn.h>
+#include <xen/xenbus.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/io/scsiif.h>
+#include <xen/interface/io/ring.h>
+#include <xen/gnttab.h>
+#include <asm/hypervisor.h>
+
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
+#define GRANT_INVALID_REF 0
+
+
+#define DPRINTK(_f, _a...)			\
+	pr_debug("(file=%s, line=%d) " _f,	\
+		 __FILE__ , __LINE__ , ## _a )
+
+
+struct scsi_shadow {
+	struct scsiif_request ring_req;
+	unsigned long req_scsi_cmnd;
+};
+
+#define SCSI_RING_SIZE __RING_SIZE((struct scsiif_sring *)0, PAGE_SIZE)
+
+struct scsifront_info {
+	struct xenbus_device *dev;
+	struct Scsi_Host *host;
+	unsigned int evtchn;
+	unsigned int irq;
+	unsigned long ring_ref;
+	struct scsiif_front_ring ring;
+	struct scsi_shadow shadow[SCSI_RING_SIZE];
+	unsigned long shadow_free;
+};
+
+
+static inline int GET_ID_FROM_FREELIST(
+	struct scsifront_info *info)
+{
+	unsigned long free = info->shadow_free;
+	BUG_ON(free > SCSI_RING_SIZE);
+	info->shadow_free = info->shadow[free].ring_req.rqid;
+	info->shadow[free].ring_req.rqid = 0x0fffffee; /* debug */
+	return free;
+}
+
+static inline void ADD_ID_TO_FREELIST(
+	struct scsifront_info *info, unsigned long id)
+{
+	info->shadow[id].ring_req.rqid  = info->shadow_free;
+	info->shadow[id].req_scsi_cmnd = 0;
+	info->shadow_free = id;
+}
+
+static void scsifront_free(struct scsifront_info *info)
+{
+	
+	scsi_remove_host(info->host);
+	scsi_host_put(info->host);
+
+	flush_scheduled_work();
+
+	if (info->ring_ref != GRANT_INVALID_REF) {
+		gnttab_end_foreign_access(info->ring_ref, 0,
+					(unsigned long)info->ring.sring);
+		info->ring_ref = GRANT_INVALID_REF;
+		info->ring.sring = NULL;
+	}
+
+	if (info->irq)
+		unbind_from_irqhandler(info->irq, info);
+	info->irq = 0;
+}
+
+static int map_data_for_request(struct scsifront_info *info,
+		struct scsi_cmnd *sc, struct scsiif_request *ring_req)
+{
+	struct scatterlist *sg = sc->request_buffer;
+
+	grant_ref_t gref_head;
+	int err, i, ref;
+	int write = (sc->sc_data_direction == DMA_TO_DEVICE);
+
+	if (!sg || sc->sc_data_direction == DMA_NONE)
+		return 0;
+
+	err = gnttab_alloc_grant_references(SG_TABLESIZE, &gref_head);
+	if (err)
+		return -ENOMEM;
+
+	for (i = 0; i < sc->use_sg; i++, sg++) {
+		ref = gnttab_claim_grant_reference(&gref_head);
+		BUG_ON(ref == -ENOSPC);  /*FIXME*/
+
+		gnttab_grant_foreign_access_ref(ref, info->dev->otherend_id,
+			(page_to_phys(sg->page) >> PAGE_SHIFT), write);
+		ring_req->seg[i].gref   = ref;
+		ring_req->seg[i].offset = sg->offset;
+		ring_req->seg[i].length = sg->length;
+	}
+
+	gnttab_free_grant_references(gref_head);
+
+	return 0;
+}
+
+static int scsifront_queuecommand(struct scsi_cmnd *sc,
+					void (*done)(struct scsi_cmnd *))
+{
+	struct Scsi_Host *host = sc->device->host;
+	struct scsifront_info *info = (struct scsifront_info *) host->hostdata;
+	struct scsiif_request *ring_req;
+	struct scsiif_front_ring *ring = &info->ring;
+	int err, notify;
+	unsigned long id;
+
+	if (info->dev->state != XenbusStateConnected || RING_FULL(ring)) {
+		printk("busy %u!\n", info->dev->state);
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+	sc->scsi_done = done;
+	sc->result    = 0;
+
+	ring_req = RING_GET_REQUEST(&info->ring, ring->req_prod_pvt);
+
+	ring_req->id      = sc->device->id;
+	ring_req->lun     = sc->device->lun;
+	ring_req->channel = sc->device->channel;
+	ring_req->cmd_len = sc->cmd_len;
+
+	BUG_ON(sc->cmd_len > MAX_COMMAND_SIZE);
+
+	if ( sc->cmd_len )
+		memcpy(ring_req->cmnd, sc->cmnd, sc->cmd_len);
+	else
+		memset(ring_req->cmnd, 0, MAX_COMMAND_SIZE);
+
+	ring_req->use_sg              = sc->use_sg;
+	ring_req->sc_data_direction   = sc->sc_data_direction;
+	ring_req->request_bufflen     = sc->request_bufflen;
+	ring_req->retries             = sc->retries;
+	ring_req->timeout_per_command = sc->timeout_per_command;
+
+	id = GET_ID_FROM_FREELIST(info);	/* use id by response */
+	info->shadow[id].req_scsi_cmnd = (unsigned long)sc;
+	ring_req->rqid                 = id;
+	err = map_data_for_request(info, sc, ring_req);
+	if (err) {
+		printk("%s error\n",__FUNCTION__);
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+
+	ring->req_prod_pvt++;
+
+	info->shadow[id].ring_req = *ring_req;
+
+	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify);
+
+	if (notify)
+		notify_remote_via_irq(info->irq);
+
+	return 0;
+}
+
+static int scsifront_eh_abort_handler(struct scsi_cmnd *sc)
+{
+	/* not implemented */
+	BUG();
+	return 0;
+}
+
+static void scsifront_cmd_done(struct scsi_shadow *s)
+{
+	int i;
+
+	if (!s->ring_req.request_bufflen ||
+		(s->ring_req.sc_data_direction != DMA_TO_DEVICE &&
+			s->ring_req.sc_data_direction != DMA_FROM_DEVICE)) {
+		return;
+	}
+
+	if (!s->ring_req.use_sg)
+		return;
+
+	for (i = 0; i < s->ring_req.use_sg; i++ )
+		gnttab_end_foreign_access(s->ring_req.seg[i].gref, 0, 0UL);
+}
+
+static irqreturn_t scsifront_intr(int irq, void *dev_id,
+					struct pt_regs *ptregs)
+{
+	struct scsifront_info *info = (struct scsifront_info *) dev_id;
+	struct scsiif_front_ring *ring = &info->ring;
+	struct scsiif_response *ring_res;
+
+	struct scsi_cmnd *sc;
+	int i, rp;
+	unsigned long id;
+
+	if (info->dev->state != XenbusStateConnected)
+		return IRQ_HANDLED;
+
+again:
+	rp = info->ring.sring->rsp_prod;
+	rmb();
+
+	for (i = info->ring.rsp_cons; i != rp; i++) {
+		ring_res = RING_GET_RESPONSE(ring, i);
+
+		id = ring_res->rqid;
+		sc = (struct scsi_cmnd *)info->shadow[id].req_scsi_cmnd;
+		scsifront_cmd_done(&info->shadow[id]);
+
+		ADD_ID_TO_FREELIST(info, id);
+
+		sc->result = ring_res->result;
+		sc->resid  = 0;
+
+		BUG_ON(ring_res->sense_len > SCSI_SENSE_BUFFERSIZE);
+
+		if (ring_res->sense_len)
+			memcpy(sc->sense_buffer, ring_res->sense_buffer,
+				ring_res->sense_len);
+
+		sc->scsi_done(sc);
+	}
+
+	info->ring.rsp_cons = i;
+	if (i != info->ring.req_prod_pvt) {
+		int more_to_do;
+		RING_FINAL_CHECK_FOR_RESPONSES(ring, more_to_do);
+		if (more_to_do)
+			goto again;
+	} else
+		ring->sring->rsp_event = i + 1;
+
+	return IRQ_HANDLED;
+}
+
+static int scsifront_alloc_ring(struct scsifront_info *info)
+{
+	struct xenbus_device *dev = info->dev;
+	struct scsiif_sring *sring;
+	int err = -ENOMEM;
+
+	info->ring_ref = GRANT_INVALID_REF;
+
+	sring = (struct scsiif_sring *) __get_free_page(GFP_KERNEL);
+	if (!sring) {
+		xenbus_dev_fatal(dev, err, "fail to allocate shared ring");
+		return err;
+	}
+
+	SHARED_RING_INIT(sring);
+	FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
+	DPRINTK("0x%x\n", RING_SIZE(&info->ring));
+
+	err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
+	if (err < 0) {
+		xenbus_dev_fatal(dev, err, "fail to grant shared ring");
+		goto free_sring;
+	}
+	info->ring_ref = err;
+	err = bind_listening_port_to_irqhandler(
+			dev->otherend_id, scsifront_intr,
+			SA_SAMPLE_RANDOM, "scsifront", info);
+
+	if (err <= 0) {
+		xenbus_dev_fatal(dev, err, "bind_listening_port_to_irqhandler");
+		goto fail;
+	}
+	info->irq = err;
+
+	return 0;
+fail:
+	/* free resource */
+free_sring:
+	free_page((unsigned long) sring);
+	scsifront_free(info);
+
+	return err;
+}
+
+static int scsifront_init_ring(struct scsifront_info *info)
+{
+	struct xenbus_device *dev = info->dev;
+	struct xenbus_transaction xbt;
+	int err;
+
+	DPRINTK("");
+
+	err = scsifront_alloc_ring(info);
+	if (err)
+		return err;
+	DPRINTK("%lu %u\n", info->ring_ref, info->evtchn);
+
+again:
+	err = xenbus_transaction_start(&xbt);
+	if (err) {
+		xenbus_dev_fatal(dev, err, "starting transaction");
+	}
+
+	err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%lu",
+				info->ring_ref);
+	if (err) {
+		xenbus_dev_fatal(dev, err, "%s", "writing ring-ref");
+		goto fail;
+	}
+
+#ifdef XEN303 /*FJVMIO xen3.0.5*/
+	err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+				info->evtchn);
+#else
+	err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+				irq_to_evtchn_port(info->irq));
+#endif
+	if (err) {
+		xenbus_dev_fatal(dev, err, "%s", "writing event-channel");
+		goto fail;
+	}
+
+	err = xenbus_transaction_end(xbt, 0);
+	if (err) {
+		if (err == -EAGAIN)
+			goto again;
+		xenbus_dev_fatal(dev, err, "completing transaction");
+	} else
+		xenbus_switch_state(dev, XenbusStateInitialised);
+
+	return 0;
+fail:
+	xenbus_transaction_end(xbt, 1);
+	/* free resource */
+	scsifront_free(info);
+	
+	return err;
+}
+
+static struct scsi_host_template scsifront_sht = {
+	.module			= THIS_MODULE,
+	.name			= "Xen SCSI frontend driver",
+	.queuecommand		= scsifront_queuecommand,
+	.eh_abort_handler	= scsifront_eh_abort_handler,
+	.cmd_per_lun		= CAN_QUEUE,
+	.can_queue		= CAN_QUEUE,
+	.this_id 		= -1,
+	.sg_tablesize		= SG_TABLESIZE,
+	.use_clustering		= DISABLE_CLUSTERING,
+	.proc_name		= "scsifront",
+};
+
+static int scsifront_connect(struct scsifront_info *info)
+{
+	struct xenbus_device *dev = info->dev;
+	struct Scsi_Host *host = info->host;
+	int err = -ENOMEM;
+
+	DPRINTK("%u\n", dev->state);
+	if (dev->state == XenbusStateConnected)
+		return 0;
+
+	xenbus_switch_state(dev, XenbusStateConnected);
+
+	/* FIXME */
+	host->max_id      = 1;
+	host->max_channel = 0;
+
+	err = scsi_add_host(host, &dev->dev);
+	if (err) {
+		printk("fail to add scsi host %d\n", err);
+		return err;
+	}
+
+	scsi_scan_host(host);
+
+	return 0;
+}
+
+static int scsifront_probe(struct xenbus_device *dev,
+				const struct xenbus_device_id *id)
+{
+	struct Scsi_Host *host;
+	struct scsifront_info *info;
+	int i, err = -ENOMEM;
+
+	host = scsi_host_alloc(&scsifront_sht, sizeof(*info));
+	if (!host) {
+		xenbus_dev_fatal(dev, err, "fail to allocate scsi host");
+		return err;
+	}
+	info = (struct scsifront_info *) host->hostdata;
+	dev->dev.driver_data = info;
+	info->dev  = dev;
+	info->host = host;
+
+	for (i = 0; i < SCSI_RING_SIZE; i++)
+		info->shadow[i].ring_req.rqid = i + 1;
+	info->shadow[SCSI_RING_SIZE - 1].ring_req.rqid = 0x0fffffff;
+
+	err = scsifront_init_ring(info);
+	if (err) {
+		scsi_host_put(host);
+		return err;
+	}
+
+	return 0;
+}
+
+
+static int scsifront_remove(struct xenbus_device *dev)
+{
+	struct scsifront_info *info = dev->dev.driver_data;
+
+	scsifront_free(info);
+	
+	return 0;
+}
+
+static void scsifront_backend_changed(struct xenbus_device *dev,
+					XenbusState backend_state)
+{
+	struct scsifront_info *info = dev->dev.driver_data;
+
+	DPRINTK("%p %u %u\n", dev, dev->state, backend_state);
+
+	switch (backend_state) {
+	case XenbusStateUnknown:
+	case XenbusStateInitialising:
+	case XenbusStateInitWait:
+	case XenbusStateInitialised:
+	case XenbusStateClosed:
+		break;
+
+	case XenbusStateConnected:
+		scsifront_connect(info);
+		break;
+
+	case XenbusStateClosing:
+		break;
+	}
+}
+
+static struct xenbus_device_id scsifront_ids[] = {
+	{ "scsihost" },
+	{ "" }
+};
+
+
+static struct xenbus_driver scsifront_driver = {
+	.name			= "scsihost",
+	.owner			= THIS_MODULE,
+	.ids			= scsifront_ids,
+	.probe			= scsifront_probe,
+	.remove			= scsifront_remove,
+/* 	.resume			= scsifront_resume, */
+	.otherend_changed	= scsifront_backend_changed,
+};
+
+static int __init scsifront_init(void)
+{
+	int err;
+
+	if (!is_running_on_xen())
+		return -ENODEV;
+
+	err = xenbus_register_frontend(&scsifront_driver);
+
+	return err;
+}
+
+static void scsifront_exit(void)
+{
+	xenbus_unregister_driver(&scsifront_driver);
+}
+
+module_init(scsifront_init);
+module_exit(scsifront_exit);
+
+MODULE_DESCRIPTION("Xen SCSI frontend driver");
+MODULE_LICENSE("GPL");

[-- 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:07 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 ` [RFC] [2/4] PV driver for FC transport layer (pv-scsi backend driver) Jun Kamada
2007-06-29 11:07 ` Jun Kamada [this message]
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=20070629200701.69EF.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.