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: [PATCH 1/6] pvSCSI (SCSI pass through) driver
Date: Tue, 30 Oct 2007 19:39:14 +0900	[thread overview]
Message-ID: <20071030193911.4419.KAMA@jp.fujitsu.com> (raw)
In-Reply-To: <20071025105803.5A32.KAMA@jp.fujitsu.com>

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

This patch is for frontend 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>

-----
Jun Kamada

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

# HG changeset patch
# User t.horikoshi@jp.fujitsu.com
# Date 1193730096 -32400
# Node ID 24e0cb9fe9df6f4a6df226823562bec3089072e6
# Parent  709db80c03c3d7606744a71f48f5186358a5e659
[LINUX][scsifront] add scsi frontend 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 709db80c03c3 -r 24e0cb9fe9df drivers/xen/scsifront/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/Makefile	Tue Oct 30 16:41:36 2007 +0900
@@ -0,0 +1,8 @@
+ifeq ($(CONFIG_XEN_FC),y)
+  EXTRA_CFLAGS += -DCONFIG_XEN_FC
+  obj-$(CONFIG_XEN_SCSI_FRONTEND)	:= xenfcscsi.o
+  xenfcscsi-objs := scsifront.o fcfront.o comfront.o tracefront.o
+else
+  obj-$(CONFIG_XEN_SCSI_FRONTEND)	:= xenscsi.o
+  xenscsi-objs := scsifront.o comfront.o tracefront.o
+endif
diff -r 709db80c03c3 -r 24e0cb9fe9df drivers/xen/scsifront/comfront.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/comfront.c	Tue Oct 30 16:41:36 2007 +0900
@@ -0,0 +1,265 @@
+/*
+ * 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 "comfront.h"
+
+extern int scsifront_cmd_done(struct comfront_info *, struct vscsiif_btf_request *);
+static void comfront_notify_work(struct comfront_info *info);
+#ifdef CONFIG_XEN_FC
+extern void fcfront_cmd_done(struct comfront_info *, struct vscsiif_btf_request *);
+#endif
+
+extern void scsi_trace(unsigned long, unsigned char *, unsigned int);
+
+static inline int GET_ID_FROM_FREELIST(struct comfront_info *info)
+{
+	unsigned long flags;
+	uint32_t free;
+
+	spin_lock_irqsave(&info->shadow_lock, flags);
+
+	free = info->shadow_free;
+	BUG_ON(free > DEFAULT_CAN_QUEUE);
+	info->shadow_free = info->shadow[free].rqid;
+	info->shadow[free].rqid = 0x0fffffee; /* debug */
+
+	info->shadow[free].cond = 0;
+
+	spin_unlock_irqrestore(&info->shadow_lock, flags);
+
+	return free;
+}
+
+void ADD_ID_TO_FREELIST(struct comfront_info *info, uint32_t id)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->shadow_lock, flags);
+
+	info->shadow[id].rqid  = info->shadow_free;
+	info->shadow[id].u.scsi.req_scsi_cmnd = 0;
+	info->shadow_free = id;
+
+	spin_unlock_irqrestore(&info->shadow_lock, flags);
+}
+
+
+/* ------------------------------------------------------------ */
+/* 	for frontend to backend communication                   */
+/* ------------------------------------------------------------ */
+
+int read_ftb_ring_resp_cons(struct comfront_info *info)
+{
+	RING_IDX i, ftb_rp;
+	struct vscsiif_ftb_response *ring_res;
+	int err;
+
+	ftb_rp = info->ftb_ring.sring->rsp_prod;
+	err = SCSIIF_REQ_OKAY;
+	rmb();
+
+	for (i = info->ftb_ring.rsp_cons; i != ftb_rp; i++) {
+		ring_res = RING_GET_RESPONSE(&info->ftb_ring, i);
+		
+		if (ring_res->status == SCSIIF_BTFRING_BUSY) {
+			err = SCSIIF_BTFRING_BUSY;
+			comfront_notify_work(info);
+		}
+	}
+	
+	info->ftb_ring.rsp_cons = i;
+	
+	return err;
+}
+
+struct vscsiif_ftb_request * comfront_pre_request(struct comfront_info *info)
+{
+	struct vscsiif_ftb_front_ring *ring = &(info->ftb_ring);
+	struct vscsiif_ftb_request *ring_req;
+	uint32_t id;
+
+	ring_req = RING_GET_REQUEST(&(info->ftb_ring), ring->req_prod_pvt);
+
+	id = GET_ID_FROM_FREELIST(info);	/* use id by response */
+	ring_req->rqid = id;
+
+	return ring_req;
+}
+
+void comfront_do_request(struct comfront_info *info)
+{
+	struct vscsiif_ftb_front_ring	*ring = &(info->ftb_ring);
+	unsigned int irq = info->irq;
+	int notify;
+
+	ring->req_prod_pvt++;
+	
+	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify);
+
+	if (notify)
+		notify_remote_via_irq(irq);
+
+	/***** Front to Back response consume *****/
+	read_ftb_ring_resp_cons(info);
+}
+
+
+/* ------------------------------------------------------------ */
+/* 	for backend to frontend communication			*/
+/* ------------------------------------------------------------ */
+
+static void comfront_notify_work(struct comfront_info *info)
+{
+
+	info->waiting_resp = 1;
+	wake_up(&info->wq);
+}
+
+irqreturn_t comfront_intr(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+	comfront_notify_work((struct comfront_info *)dev_id);
+	return IRQ_HANDLED;
+}
+
+static void __sync_cmd_done(struct comfront_info *info,
+		      struct vscsiif_btf_request *btf_req)
+{
+	uint32_t id = btf_req->rqid;
+	
+	info->btf_req = *btf_req;
+
+	info->shadow[id].cond++;
+	wake_up(&(info->shadow[id].wq));
+}
+
+int do_comfront_cmd_done(struct comfront_info *info)
+{
+	struct vscsiif_btf_back_ring *btf_ring = &info->btf_ring;
+	struct vscsiif_btf_request   *btf_req;
+
+	int btf_rc, btf_rp;
+	int more_to_do = 0;
+
+	if (info->dev->state != XenbusStateConnected)
+		return 0;
+
+	/***** Back to Front request consume *****/
+	DPRINTK("%s\n",__FUNCTION__);
+
+	btf_rc = btf_ring->req_cons;
+	btf_rp = btf_ring->sring->req_prod;
+
+	while ((btf_rc != btf_rp) &&
+			!RING_REQUEST_CONS_OVERFLOW(btf_ring, btf_rc)) {
+
+		rmb();
+		btf_req = RING_GET_REQUEST(btf_ring, btf_rc);
+		btf_ring->req_cons = ++btf_rc;
+
+		if (info->shadow[btf_req->rqid].cmnd == CMND_SCSI) {
+			scsi_trace(2, (unsigned char *)btf_req,
+				   sizeof(struct vscsiif_btf_request));
+			     
+			if (scsifront_cmd_done(info, btf_req)) {
+				BUG();
+			}
+
+		} else {
+			__sync_cmd_done(info, btf_req);
+		}
+
+		btf_ring->rsp_prod_pvt++;
+		RING_PUSH_RESPONSES(btf_ring);
+	}
+
+	if (btf_ring->rsp_prod_pvt == btf_rc) {
+		RING_FINAL_CHECK_FOR_REQUESTS(btf_ring, more_to_do);
+		
+	} else if (RING_HAS_UNCONSUMED_REQUESTS(btf_ring)) {
+		more_to_do = 1;
+	}
+
+	return more_to_do;
+}
+
+int comfront_schedule(void *data)
+{
+	struct comfront_info *info = (struct comfront_info *)data;
+
+	while (!kthread_should_stop()) {
+		wait_event_interruptible(
+			info->wq,
+			info->waiting_resp || kthread_should_stop());
+
+		info->waiting_resp = 0;
+		smp_mb();
+
+		if (do_comfront_cmd_done(info))
+			info->waiting_resp = 1;
+
+		read_ftb_ring_resp_cons(info);
+
+	}
+
+	info->kthread = NULL;
+
+	return 0;
+}
+
+struct vscsiif_btf_request *comfront_do_request_and_wait_response(
+					struct comfront_info *info,
+					struct vscsiif_ftb_request *ring_req)
+{
+	struct vscsiif_btf_request *ring_res;
+	uint32_t rqid = ring_req->rqid;
+
+	info->shadow[rqid].cmnd = ring_req->cmnd;
+
+	scsi_trace(1, (unsigned char *)ring_req,
+		   sizeof(struct vscsiif_ftb_request));
+
+	comfront_do_request(info);
+	wait_event_interruptible(info->shadow[rqid].wq,
+				 info->shadow[rqid].cond);
+	info->shadow[rqid].cond--;
+
+	ADD_ID_TO_FREELIST(info, rqid);
+
+	ring_res = &(info->btf_req);
+
+	scsi_trace(2, (unsigned char *)ring_res,
+		   sizeof(struct vscsiif_btf_request));
+
+	return ring_res;
+}
diff -r 709db80c03c3 -r 24e0cb9fe9df drivers/xen/scsifront/comfront.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/comfront.h	Tue Oct 30 16:41:36 2007 +0900
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+#ifndef __XEN_DRIVERS_SCSIFRONT_H__
+#define __XEN_DRIVERS_SCSIFRONT_H__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#ifdef CONFIG_XEN_FC
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_fc.h>
+#endif
+#include <xen/xenbus.h>
+#include <xen/gnttab.h>
+#include <xen/evtchn.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/io/vscsiif.h>
+#include <asm/delay.h>
+
+
+#define GRANT_INVALID_REF 0
+
+struct comfront_shadow {
+	uint32_t rqid;
+	unsigned int cmnd;
+	wait_queue_head_t wq;
+	int cond;
+	union {
+		struct {
+			unsigned int sc_data_direction;
+			unsigned int use_sg;
+			unsigned int request_bufflen;
+			unsigned long req_scsi_cmnd;
+			int gref[SG_TABLESIZE];
+		} scsi;
+#ifdef CONFIG_XEN_FC
+		struct {
+		} fc;
+#endif
+	} u;
+};
+
+struct comfront_info {
+	struct xenbus_device *dev;
+	struct Scsi_Host *host;
+	spinlock_t io_lock;
+	spinlock_t shadow_lock;
+	unsigned int evtchn;
+	unsigned int irq;
+	int ftb_ring_ref;
+	int btf_ring_ref;
+	struct vscsiif_ftb_front_ring ftb_ring;
+	struct vscsiif_btf_back_ring btf_ring;
+	struct comfront_shadow shadow[DEFAULT_CAN_QUEUE];
+	uint32_t shadow_free;
+	struct vscsiif_btf_request	btf_req;
+
+	struct task_struct *kthread;
+	wait_queue_head_t wq;
+	unsigned int waiting_resp;
+
+	void *fcinfo;
+};
+
+#define DPRINTK(_f, _a...)				\
+	pr_debug("(file=%s, line=%d) " _f,	\
+		 __FILE__ , __LINE__ , ## _a )
+
+
+void ADD_ID_TO_FREELIST(struct comfront_info *info, uint32_t id);
+
+#ifdef CONFIG_XEN_FC
+extern int fcfront_get_initial_attribute(struct comfront_info *cominfo);
+extern int fcfront_get_function_template(struct comfront_info *cominfo);
+extern int fcfront_connection_setup(struct comfront_info *cominfo);
+extern void fcfront_connection_unsetup(struct comfront_info *cominfo);
+#endif
+
+
+struct vscsiif_ftb_request * comfront_pre_request(struct comfront_info *);
+struct vscsiif_btf_request *comfront_do_request_and_wait_response(
+					struct comfront_info *info,
+					struct vscsiif_ftb_request *ring_req);
+void comfront_do_request(struct comfront_info *);
+irqreturn_t comfront_intr(int, void *, struct pt_regs *);
+int comfront_schedule(void *);
+
+#endif /* __XEN_DRIVERS_SCSIFRONT_H__  */
diff -r 709db80c03c3 -r 24e0cb9fe9df drivers/xen/scsifront/fcfront.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/fcfront.c	Tue Oct 30 16:41:36 2007 +0900
@@ -0,0 +1,777 @@
+/*
+ * Xen SCSI FC 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 "comfront.h"
+#include "fcfront.h"
+
+
+extern void notify_remote_via_irq(int);
+extern int irq_to_evtchn_port(int);
+extern int bind_listening_port_to_irqhandler(unsigned int,
+		irqreturn_t (*handler)(int, void *, struct pt_regs *),
+		unsigned long, const char *, void *);
+extern void unbind_from_irqhandler(unsigned int, void *);
+extern int gnttab_grant_foreign_access(domid_t, unsigned long, int);
+extern int gnttab_end_foreign_access_ref(grant_ref_t, int);
+extern void gnttab_end_foreign_access(grant_ref_t, int, unsigned long);
+
+extern struct vscsiif_ftb_request *comfront_pre_request(struct comfront_info *);
+extern void comfront_do_request(struct comfront_info *);
+
+extern struct vscsiif_btf_request *comfront_do_request_and_wait_response(
+					struct comfront_info *,
+					struct vscsiif_ftb_request *);
+
+
+
+/* ---------------------------------------------------------------------- */
+
+static void fc_get_host_port_id(struct Scsi_Host *shost)
+{
+	struct comfront_info *cominfo = (struct comfront_info *)
+						(shost->hostdata);
+ 	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+
+	ring_req = comfront_pre_request(cominfo);
+	
+	ring_req->cmnd = CMND_GET_HOST_PORT_ID;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt == 0) {
+		fc_host_port_id(shost) = ring_res->u.ghpi.port_id;
+	} else {
+		fc_host_port_id(shost) = (u32)0xffffffff;
+	}
+
+}
+
+static void fc_get_host_port_type(struct Scsi_Host *shost)
+{
+	struct comfront_info *cominfo = (struct comfront_info *)
+						(shost->hostdata);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd = CMND_GET_HOST_PORT_TYPE;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt == 0) {
+		fc_host_port_type(shost) = ring_res->u.ghpt.port_type;
+	} else {
+		fc_host_port_type(shost) = (u32)0xffffffff;
+	}
+
+}
+
+static void fc_get_host_port_state(struct Scsi_Host *shost)
+{
+	struct comfront_info *cominfo = (struct comfront_info *)
+						(shost->hostdata);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd = CMND_GET_HOST_PORT_STATE;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt == 0) {
+		fc_host_port_state(shost) = ring_res->u.ghps.port_state;
+	} else {
+		fc_host_port_state(shost) = (u32)0xffffffff;
+	}
+
+}
+
+static void fc_get_host_active_fc4s(struct Scsi_Host *shost)
+{
+	struct comfront_info *cominfo = (struct comfront_info *)
+						(shost->hostdata);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd = CMND_GET_HOST_ACTIVE_FC4S;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt == 0) {
+		memcpy(fc_host_active_fc4s(shost),
+		       ring_res->u.ghaf.active_fc4s,
+		       sizeof(fc_host_active_fc4s(shost)));
+	} else {
+		memset(fc_host_active_fc4s(shost), 0,
+		       sizeof(fc_host_active_fc4s(shost)));
+	}
+
+}
+
+static void fc_get_host_speed(struct Scsi_Host *shost)
+{
+	struct comfront_info *cominfo = (struct comfront_info *)
+						(shost->hostdata);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd = CMND_GET_HOST_SPEED;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt == 0) {
+		fc_host_speed(shost) = ring_res->u.ghsp.speed;
+	} else {
+		fc_host_speed(shost) = (u32)0xffffffff;
+	}
+
+}
+
+static void fc_get_host_fabric_name(struct Scsi_Host *shost)
+{
+	struct comfront_info *cominfo = (struct comfront_info *)
+						(shost->hostdata);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd = CMND_GET_HOST_FABRIC_NAME;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt == 0) {
+		fc_host_fabric_name(shost) = ring_res->u.ghfn.fabric_name;
+	} else {
+		fc_host_fabric_name(shost) = (u32)0xffffffff;
+	}
+
+}
+
+static struct fc_host_statistics * fc_get_stats(struct Scsi_Host *shost)
+{
+	struct comfront_info *cominfo = (struct comfront_info *)
+						(shost->hostdata);
+	struct fcfront_info *fcinfo = (struct fcfront_info *)
+						(cominfo->fcinfo);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+	struct fc_host_statistics *ret;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd = CMND_GET_HOST_STATS;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt == 0) {
+		/* "info->hs" is appropriate position ? */
+		memcpy(&(fcinfo->hs), &(ring_res->u.ghst.stats),
+		       sizeof(fcinfo->hs));
+		ret = &(ring_res->u.ghst.stats);
+	} else {
+		ret = NULL;
+	}
+
+	return ret;
+}
+
+static void fc_reset_stats(struct Scsi_Host *shost)
+{
+	struct comfront_info *cominfo = (struct comfront_info *)
+						(shost->hostdata);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd = CMND_RESET_HOST_STATS;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+}
+
+static int fc_issue_lip(struct Scsi_Host *shost)
+{
+	struct comfront_info *cominfo = (struct comfront_info *)
+						(shost->hostdata);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd = CMND_ISSUE_HOST_LIP;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+	
+	return ring_res->rslt;
+}
+
+static void fc_get_starget_port_id(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct comfront_info *cominfo  = (struct comfront_info *)
+						(shost->hostdata);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd           = CMND_GET_STARGET_PORT_ID;
+	ring_req->u.gtpi.channel = starget->channel;
+	ring_req->u.gtpi.id      = starget->id;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt == 0) {
+		fc_starget_port_id(starget) = ring_res->u.gtpi.port_id;
+	} else {
+		fc_starget_port_id(starget) = (u32)0xffffffff;
+	}
+
+}
+
+static void fc_get_starget_node_name(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct comfront_info *cominfo  = (struct comfront_info *)
+						(shost->hostdata);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd           = CMND_GET_STARGET_NODE_NAME;
+	ring_req->u.gtnn.channel = starget->channel;
+	ring_req->u.gtnn.id      = starget->id;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt == 0) {
+		fc_starget_node_name(starget) = ring_res->u.gtnn.node_name;
+	} else {
+		fc_starget_node_name(starget) = (u32)0xffffffff;
+	}
+
+}
+
+static void fc_get_starget_port_name(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct comfront_info *cominfo  = (struct comfront_info *)
+						(shost->hostdata);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd           = CMND_GET_STARGET_PORT_NAME;
+	ring_req->u.gtpn.channel = starget->channel;
+	ring_req->u.gtpn.id      = starget->id;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt == 0) {
+		fc_starget_port_name(starget) = ring_res->u.gtpn.port_name;
+	} else {
+		fc_starget_port_name(starget) = (u32)0xffffffff;
+	}
+
+}
+
+static void fc_get_rport_loss_tmo(struct fc_rport *rport)
+{
+	struct Scsi_Host *shost = rport_to_shost(rport);
+	struct comfront_info *cominfo  = (struct comfront_info *)
+						(shost->hostdata);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd             = CMND_GET_RPORT_LOSS_TMO;
+	ring_req->u.gplt.node_name = rport->node_name;
+	ring_req->u.gplt.port_name = rport->port_name;
+	ring_req->u.gplt.port_id   = rport->port_id;
+	ring_req->u.gplt.roles     = rport->roles;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt == 0) {
+		rport->dev_loss_tmo = ring_res->u.gplt.timeout;
+	} else {
+		rport->dev_loss_tmo = (u32)0xffffffff;
+	}
+
+}
+
+static void fc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+{
+	struct Scsi_Host *shost = rport_to_shost(rport);
+	struct comfront_info *cominfo  = (struct comfront_info *)
+						(shost->hostdata);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd             = CMND_SET_RPORT_LOSS_TMO;
+	ring_req->u.splt.node_name = rport->node_name;
+	ring_req->u.splt.port_name = rport->port_name;
+	ring_req->u.splt.port_id   = rport->port_id;
+	ring_req->u.splt.roles     = rport->roles;
+	ring_req->u.splt.timeout   = timeout;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt == 0) {
+		rport->dev_loss_tmo = ring_res->u.splt.timeout;
+	} else {
+		rport->dev_loss_tmo = (u32)0xffffffff;
+	}
+
+}
+
+struct fc_function_template fc_transport_functions = {
+	.get_rport_dev_loss_tmo = fc_get_rport_loss_tmo,
+	.set_rport_dev_loss_tmo = fc_set_rport_loss_tmo,
+	.get_starget_node_name  = fc_get_starget_node_name,
+	.get_starget_port_name  = fc_get_starget_port_name,
+	.get_starget_port_id    = fc_get_starget_port_id,
+	.get_host_port_id       = fc_get_host_port_id,
+	.get_host_port_type     = fc_get_host_port_type,
+	.get_host_port_state    = fc_get_host_port_state,
+	.get_host_active_fc4s   = fc_get_host_active_fc4s,
+						/* lpfc does not support */
+	.get_host_speed         = fc_get_host_speed,
+	.get_host_fabric_name   = fc_get_host_fabric_name,
+	.get_fc_host_stats      = fc_get_stats,
+	.reset_fc_host_stats    = fc_reset_stats,
+	.issue_fc_host_lip      = fc_issue_lip,
+
+	/* remote port fixed attributes */
+	.show_rport_maxframe_size     = 1,
+	.show_rport_supported_classes = 1,
+	.show_rport_dev_loss_tmo      = 1,
+
+	/* target dynamic attributes */
+	.show_starget_node_name = 1,
+	.show_starget_port_name = 1,
+	.show_starget_port_id   = 1,
+
+	/* host fixed attributes */
+	.show_host_node_name           = 1,
+	.show_host_port_name           = 1,
+	.show_host_permanent_port_name = 1,	/* lpfc does not support */
+	.show_host_supported_classes   = 1,
+	.show_host_supported_fc4s      = 1,
+	.show_host_symbolic_name       = 1,
+	.show_host_supported_speeds    = 1,
+	.show_host_maxframe_size       = 1,
+	.show_host_serial_number       = 1,	/* lpfc does not support */
+
+	/* host dynamic attribute */
+	.show_host_port_id     = 1,
+	.show_host_port_type   = 1,
+	.show_host_port_state  = 1,
+	.show_host_active_fc4s = 1,
+	.show_host_speed       = 1,
+	.show_host_fabric_name = 1,
+};
+
+
+/* ---------------------------------------------------------------------- */
+
+static int __setup_grant_table(struct fcfront_info *info)
+{
+	void *addr;
+	int gntref;
+
+	if ((addr = kmalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) {
+		return -ENOMEM;
+	}
+	  
+	gntref = gnttab_grant_foreign_access(info->cominfo->dev->otherend_id,
+					     virt_to_mfn(addr), 0);
+	if (gntref < 0) {
+		printk(KERN_ERR
+		       "fcfront: %s: gnttab_grant_foreign_access() error\n",
+		       __FUNCTION__);
+		return gntref;
+	}
+
+	info->addr   = addr;
+	info->gntref = gntref;
+	
+	return 0;
+}
+
+static void __unsetup_grant_table(struct fcfront_info *info)
+{
+	/* currently, nothing to do */
+}
+
+static int __setup_xenstore(struct fcfront_info *info)
+{
+	struct xenbus_device *dev = info->cominfo->dev;
+	struct xenbus_transaction xbt;
+	int ret = 0;
+
+again:
+	if ((ret = xenbus_transaction_start(&xbt)) != 0) {
+		printk(KERN_ERR
+		       "fcfront: %s: xenbus_transaction_start() error\n",
+		       __FUNCTION__);
+		goto out0;
+	}
+
+	if ((ret = xenbus_printf(xbt, dev->nodename,
+			"fc_gntref", "%d", info->gntref)) != 0) {
+		printk(KERN_ERR "fcfront: %s: xenbus_printf() error\n",
+			   __FUNCTION__);
+		goto out1;
+	}
+	
+	if ((ret = xenbus_transaction_end(xbt, 0)) != 0) {
+		if (ret == -EAGAIN) {
+			goto again;
+		} else {
+			printk(KERN_ERR
+			       "fcfront: %s: xenbus_transaction_end() error\n",
+			       __FUNCTION__);
+			goto out0;
+		}
+	}
+
+	return 0;
+
+out1:
+	(void)xenbus_transaction_end(xbt, 0);
+	
+out0:
+	return ret;
+}
+
+static void __unsetup_xenstore(struct fcfront_info *info)
+{
+	/* currently, nothing to do */
+}
+
+int fcfront_connection_setup(struct comfront_info *cominfo)
+{
+	struct fcfront_info *info;
+	int ret;
+	
+#if 0	/* for DEBUG */
+	printk(KERN_ERR "%s: giha=%ld\n", sizeof(struct giha), __FUNCTION__);
+	printk(KERN_ERR "%s: gita=%ld\n", sizeof(struct gita), __FUNCTION__);
+	printk(KERN_ERR "%s: gipa=%ld\n", sizeof(struct gipa), __FUNCTION__);
+	printk(KERN_ERR "%s: gftp=%ld\n", sizeof(struct gftp), __FUNCTION__);
+#endif
+
+	{
+		cominfo->fcinfo = kmalloc(sizeof(struct fcfront_info),
+					  GFP_KERNEL);
+		if (cominfo->fcinfo == NULL) {
+			ret = -ENOMEM;
+			goto out0;
+		}
+		memset(cominfo->fcinfo, 0, sizeof(struct fcfront_info));
+		info = (struct fcfront_info *)(cominfo->fcinfo);
+		info->cominfo = cominfo;
+	}
+
+	/* prepare for grant table */
+	if ((ret = __setup_grant_table(info)) != 0) {
+		printk(KERN_ERR "fcfront: %s: __setup_grant_table() error\n",
+		       __FUNCTION__);
+		goto out1;
+	}
+
+	/* exchange various parameters through xenstore */
+	if ((ret = __setup_xenstore(info)) != 0) {
+		printk(KERN_ERR "fcfront: %s: "
+		       "__setup_xenstore() error\n", __FUNCTION__);
+		goto out2;
+	}
+
+	return 0;
+
+out2:
+	__unsetup_grant_table(info);
+
+out1:
+	kfree(cominfo->fcinfo);
+	
+out0:
+	return ret;
+}
+
+void fcfront_connection_unsetup(struct comfront_info *cominfo)
+{
+	struct fcfront_info *info = (struct fcfront_info *)(cominfo->fcinfo);
+
+	__unsetup_xenstore(info);
+	__unsetup_grant_table(info);
+
+	kfree(cominfo->fcinfo);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+static int __get_host_attrib(struct comfront_info *cominfo)
+{
+	struct fcfront_info *fcinfo = (struct fcfront_info *)(cominfo->fcinfo);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+	struct fc_host_attrs *host_attrs =
+			(struct fc_host_attrs *)(cominfo->host->shost_data);
+	struct giha *giha = (struct giha *)(fcinfo->addr);
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd = CMND_GET_INITIAL_SHOST_ATTRIB;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt != 0) {
+		return 0;
+	}
+	
+	memcpy(host_attrs->active_fc4s, giha->active_fc4s,
+	       sizeof(host_attrs->active_fc4s));
+	host_attrs->fabric_name         = giha->fabric_name;
+	host_attrs->maxframe_size       = giha->maxframe_size;
+	host_attrs->node_name           = giha->node_name;
+	host_attrs->permanent_port_name = giha->permanent_port_name;
+	host_attrs->port_id             = giha->port_id;
+	host_attrs->port_name           = giha->port_name;
+	host_attrs->port_state          = giha->port_state;
+	host_attrs->port_type           = giha->port_type;
+	memcpy(host_attrs->serial_number, giha->serial_number,
+	       sizeof(host_attrs->serial_number));
+	host_attrs->speed               = giha->speed;
+	/* "fcinfo->hs" is appropriate position ? */
+	memcpy(&(fcinfo->hs), &(giha->stats), sizeof(fcinfo->hs));
+	host_attrs->supported_classes   = giha->supported_classes;
+	memcpy(host_attrs->supported_fc4s, giha->supported_fc4s,
+	       sizeof(host_attrs->supported_fc4s));
+	host_attrs->supported_speeds    = giha->supported_speeds;
+	memcpy(host_attrs->symbolic_name, giha->symbolic_name,
+	       sizeof(host_attrs->symbolic_name));
+	host_attrs->tgtid_bind_type     = giha->tgtid_bind_type;
+
+	return 0;
+}
+
+static int __get_target_attrib(struct comfront_info *cominfo)
+{
+	struct fcfront_info *fcinfo = (struct fcfront_info *)(cominfo->fcinfo);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+	struct scsi_target *starget;
+	struct fc_starget_attrs *starget_attrs;
+	struct gita *gita = (struct gita *)(fcinfo->addr);
+	unsigned int i;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd = CMND_GET_INITIAL_STARGET_ATTRIB;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt != 0) {
+		return 0;
+	}
+	
+	for (i = 0; i < gita->num; i++) {
+		list_for_each_entry(starget, &(cominfo->host->__targets),
+				    siblings) {
+			starget_attrs = (struct fc_starget_attrs *)
+					(&(starget->starget_data));
+			if ((starget->channel == gita->e[i].channel) &&
+			    (starget->id      == gita->e[i].id)) {
+				starget_attrs->node_name =
+					gita->e[i].node_name;
+				starget_attrs->port_id   =
+					gita->e[i].port_id;
+				starget_attrs->port_name =
+					gita->e[i].port_name;
+				break;
+			} else {
+			/*	printk(KERN_ERR
+				       "fcfront: %s: SCSI target not added\n",
+				       __FUNCTION__);*/
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int __get_port_attrib(struct comfront_info *cominfo)
+{
+	struct fcfront_info *fcinfo = (struct fcfront_info *)(cominfo->fcinfo);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+	int channel;
+	struct fc_rport_identifiers ids;
+	struct fc_rport *rport;
+	struct gipa *gipa = (struct gipa *)(fcinfo->addr);
+	unsigned int i;
+	int ret = 0;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd = CMND_GET_INITIAL_RPORT_ATTRIB;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt != 0) {
+		return ret;
+	}
+	
+	for (i = 0; i < gipa->num; i++) {
+		channel       = gipa->e[i].channel;
+		ids.node_name = gipa->e[i].node_name;
+		ids.port_id   = gipa->e[i].port_id;
+		ids.port_name = gipa->e[i].port_name;
+		ids.roles     = gipa->e[i].roles;
+
+		rport = fc_remote_port_add(cominfo->host, channel, &ids);
+		if (rport == NULL) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		rport->dev_loss_tmo      = gipa->e[i].dev_loss_tmo;
+		rport->maxframe_size     = gipa->e[i].maxframe_size;
+		rport->port_state        = gipa->e[i].port_state;
+		rport->scsi_target_id    = gipa->e[i].scsi_target_id;
+		rport->supported_classes = gipa->e[i].supported_classes;
+	}
+
+	return ret;
+}
+
+int fcfront_get_initial_attribute(struct comfront_info *cominfo)
+{
+	int ret = 0;
+
+	/* get SCSI host attributes */
+	(void)__get_host_attrib(cominfo);
+	
+	/* get SCSI target attributes */
+	(void)__get_target_attrib(cominfo);
+
+	/* get remote port attibutes */
+	ret = __get_port_attrib(cominfo);
+
+	return ret;
+}
+
+#define CORRECT_FT(s, f, v, d)		\
+		if (((s)->f) == (v)) {	\
+			(d)->f = (v);	\
+		}
+
+int fcfront_get_function_template(struct comfront_info *cominfo)
+{
+	struct fcfront_info *fcinfo = (struct fcfront_info *)(cominfo->fcinfo);
+	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+	struct gftp *gftp = (struct gftp *)(fcinfo->addr);
+	struct fc_function_template_shared *ft = &(gftp->ft);
+	struct fc_function_template *pvfcft = &fc_transport_functions;
+
+	ring_req = comfront_pre_request(cominfo);
+
+	ring_req->cmnd = CMND_GET_FUNCTION_TEMPLATE;
+
+	ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+	if (ring_res->rslt == 0) {
+
+		CORRECT_FT(ft, get_rport_dev_loss_tmo,        0, pvfcft);
+		CORRECT_FT(ft, set_rport_dev_loss_tmo,        0, pvfcft);
+		CORRECT_FT(ft, get_starget_node_name,         0, pvfcft);
+		CORRECT_FT(ft, get_starget_port_name,         0, pvfcft);
+		CORRECT_FT(ft, get_starget_port_id,           0, pvfcft);
+		CORRECT_FT(ft, get_host_port_id,              0, pvfcft);
+		CORRECT_FT(ft, get_host_port_type,            0, pvfcft);
+		CORRECT_FT(ft, get_host_port_state,           0, pvfcft);
+		CORRECT_FT(ft, get_host_active_fc4s,          0, pvfcft);
+		CORRECT_FT(ft, get_host_speed,                0, pvfcft);
+		CORRECT_FT(ft, get_host_fabric_name,          0, pvfcft);
+		CORRECT_FT(ft, get_fc_host_stats,             0, pvfcft);
+		CORRECT_FT(ft, reset_fc_host_stats,           0, pvfcft);
+		CORRECT_FT(ft, issue_fc_host_lip,             0, pvfcft);
+
+		pvfcft->dd_fcrport_size = ft->dd_fcrport_size;
+
+		CORRECT_FT(ft, show_rport_maxframe_size,      0,    pvfcft);
+		CORRECT_FT(ft, show_rport_supported_classes,  0,    pvfcft);
+		CORRECT_FT(ft, show_rport_dev_loss_tmo,       0,    pvfcft);
+		CORRECT_FT(ft, show_starget_node_name,        0,    pvfcft);
+		CORRECT_FT(ft, show_starget_port_name,        0,    pvfcft);
+		CORRECT_FT(ft, show_starget_port_id,          0,    pvfcft);
+		CORRECT_FT(ft, show_host_node_name,           0,    pvfcft);
+		CORRECT_FT(ft, show_host_port_name,           0,    pvfcft);
+		CORRECT_FT(ft, show_host_permanent_port_name, 0,    pvfcft);
+		CORRECT_FT(ft, show_host_supported_classes,   0,    pvfcft);
+		CORRECT_FT(ft, show_host_supported_fc4s,      0,    pvfcft);
+		CORRECT_FT(ft, show_host_symbolic_name,       0,    pvfcft);
+		CORRECT_FT(ft, show_host_supported_speeds,    0,    pvfcft);
+		CORRECT_FT(ft, show_host_maxframe_size,       0,    pvfcft);
+		CORRECT_FT(ft, show_host_serial_number,       0,    pvfcft);
+		CORRECT_FT(ft, show_host_port_id,             0,    pvfcft);
+		CORRECT_FT(ft, show_host_port_type,           0,    pvfcft);
+		CORRECT_FT(ft, show_host_port_state,          0,    pvfcft);
+		CORRECT_FT(ft, show_host_active_fc4s,         0,    pvfcft);
+		CORRECT_FT(ft, show_host_speed,               0,    pvfcft);
+		CORRECT_FT(ft, show_host_fabric_name,         0,    pvfcft);
+	}
+
+	return 0;
+}
+
+MODULE_DESCRIPTION("Xen Para-Virtual SCSI Fibre Channel Frontend Driver");
+MODULE_LICENSE("GPL");
diff -r 709db80c03c3 -r 24e0cb9fe9df drivers/xen/scsifront/fcfront.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/fcfront.h	Tue Oct 30 16:41:36 2007 +0900
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+
+#ifndef __XEN_DRIVERS_FCFRONT_H__
+#define __XEN_DRIVERS_FCFRONT_H__
+
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_fc.h>
+
+/* ----------------------------------------------------------------------
+	Definition of Grant Table Structures
+   ---------------------------------------------------------------------- */
+
+#define SCSI_FC_MAX_STARGET	32	/* limited by PAGE_SIZE */
+#define SCSI_FC_MAX_RPORT	32	/* limited by PAGE_SIZE */
+
+struct giha {
+	u8	active_fc4s[FC_FC4_LIST_SIZE];
+	u64	fabric_name;
+	u64	node_name;
+	u64	permanent_port_name;
+	u32     maxframe_size;
+	u32	port_id;
+	u64	port_name;
+	enum fc_port_state	port_state;
+	enum fc_port_type	port_type;
+	char	serial_number[FC_SERIAL_NUMBER_SIZE];
+	struct fc_host_statistics	stats;
+	u32     speed;
+	u32	supported_classes;
+	u8	supported_fc4s[FC_FC4_LIST_SIZE];
+	char	symbolic_name[FC_SYMBOLIC_NAME_SIZE];
+	u32     supported_speeds;
+	enum fc_tgtid_binding_type	tgtid_bind_type;
+};
+
+struct gita {
+	u32	num;
+	u32	padding1;
+	struct {
+		u64	node_name;
+		u64     port_name;
+		u32	port_id;
+		u32	channel;
+		u32	id;
+		u32	padding2;
+	} e[SCSI_FC_MAX_STARGET];
+};
+
+struct gipa {
+	u32	num;
+	u32	padding1;
+	struct {
+		u32	dev_loss_tmo;
+		u32	maxframe_size;
+		u64	node_name;
+		u64	port_name;
+		u32     port_id;
+		enum fc_port_state	port_state;
+		u32	roles;
+		u32	scsi_target_id;
+		u32	supported_classes;
+		u32	channel;
+	} e[SCSI_FC_MAX_RPORT];
+};
+
+struct fc_function_template_shared {
+	u64	get_rport_dev_loss_tmo:1;
+	u64	set_rport_dev_loss_tmo:1;
+	u64	get_starget_node_name:1;
+	u64	get_starget_port_name:1;
+	u64 	get_starget_port_id:1;
+	u64 	get_host_port_id:1;
+	u64	get_host_port_type:1;
+	u64	get_host_port_state:1;
+	u64	get_host_active_fc4s:1;
+	u64	get_host_speed:1;
+	u64	get_host_fabric_name:1;
+	u64	get_fc_host_stats:1;
+	u64	reset_fc_host_stats:1;
+	u64	issue_fc_host_lip:1;
+	u64	padding1:50;
+
+	u64	show_rport_maxframe_size:1;
+	u64	show_rport_supported_classes:1;
+	u64	show_rport_dev_loss_tmo:1;
+	u64	show_starget_node_name:1;
+	u64	show_starget_port_name:1;
+	u64	show_starget_port_id:1;
+	u64	show_host_node_name:1;
+	u64	show_host_port_name:1;
+	u64	show_host_permanent_port_name:1;
+	u64	show_host_supported_classes:1;
+	u64	show_host_supported_fc4s:1;
+	u64	show_host_symbolic_name:1;
+	u64	show_host_supported_speeds:1;
+	u64	show_host_maxframe_size:1;
+	u64	show_host_serial_number:1;
+	u64	show_host_port_id:1;
+	u64	show_host_port_type:1;
+	u64	show_host_port_state:1;
+	u64	show_host_active_fc4s:1;
+	u64	show_host_speed:1;
+	u64	show_host_fabric_name:1;
+	u64	padding2:43;
+
+	u32	dd_fcrport_size;
+	u32	padding3;
+};
+
+struct gftp {
+	struct fc_function_template_shared	ft;
+};
+
+
+/* ----------------------------------------------------------------------
+	Definition of Internal Information Structures
+   ---------------------------------------------------------------------- */
+
+struct fcfront_info {
+	struct comfront_info	*cominfo;
+
+	int	gntref;
+	void	*addr;
+
+				/* On backend, "hs" is stored in ***_hba */
+	struct fc_host_statistics	hs;
+};
+
+struct fcback_info {
+	struct comback_info	*cominfo;
+
+	int	gntref;
+	struct vm_struct	*gnt_area;
+
+	struct vscsiif_ftb_request	ftb_req;
+};
+
+
+/* ----------------------------------------------------------------------
+	Definition of Front/Back common functions
+   ---------------------------------------------------------------------- */
+
+struct fc_internal_head {
+	struct scsi_transport_template t;
+	struct fc_function_template *f;
+};
+  
+#endif /*__XEN_DRIVERS_FCFRONT_H__*/
diff -r 709db80c03c3 -r 24e0cb9fe9df drivers/xen/scsifront/scsifront.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/scsifront.c	Tue Oct 30 16:41:36 2007 +0900
@@ -0,0 +1,739 @@
+/*
+ * 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 "comfront.h"
+
+
+#define DEFAULT_CMD_PER_LUN	10
+#define DEFAULT_TASK_COMM_LEN	16
+
+extern int scsi_trace_init(void);
+extern void scsi_trace(unsigned long, unsigned char *, unsigned int);
+
+static int req_per_lun = DEFAULT_CMD_PER_LUN;
+module_param_named(cmds_lun, req_per_lun, int, 0);
+MODULE_PARM_DESC(reqs, "Number of lun requests to allocate");
+
+#ifdef CONFIG_XEN_FC
+extern struct fc_function_template fc_transport_functions;
+static struct scsi_transport_template * fc_transport_template = NULL;
+#endif
+extern int read_ftb_ring_resp_cons(struct comfront_info *info);
+
+static void scsifront_free(struct comfront_info *info)
+{
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+	if (info->host->shost_state != SHOST_DEL) {
+#else
+	if (!test_bit(SHOST_DEL, &info->host->shost_state)) {
+#endif
+
+#ifdef CONFIG_XEN_FC
+		fc_remove_host(info->host);
+#endif
+		scsi_remove_host(info->host);
+		scsi_host_put(info->host);
+	}
+
+	flush_scheduled_work();
+
+	if (info->ftb_ring_ref != GRANT_INVALID_REF) {
+		gnttab_end_foreign_access(info->ftb_ring_ref, 0,
+					(unsigned long)info->ftb_ring.sring);
+		info->ftb_ring_ref = GRANT_INVALID_REF;
+		info->ftb_ring.sring = NULL;
+	}
+
+	if (info->btf_ring_ref != GRANT_INVALID_REF) {
+		gnttab_end_foreign_access(info->btf_ring_ref, 0,
+					(unsigned long)info->btf_ring.sring);
+		info->btf_ring_ref = GRANT_INVALID_REF;
+		info->btf_ring.sring = NULL;
+	}
+
+	if (info->irq)
+		unbind_from_irqhandler(info->irq, info);
+	info->irq = 0;
+}
+
+
+static int map_data_for_request(struct comfront_info *info,
+		struct scsi_cmnd *sc, struct vscsiif_ftb_request *ftb_req, uint32_t id)
+{
+	grant_ref_t gref_head;
+	struct page *page;
+	int err, i, ref, ref_cnt = 0;
+	int write = (sc->sc_data_direction == DMA_TO_DEVICE);
+	int nr_pages, off, len, bytes;
+	unsigned long buffer_pfn;
+
+	if (sc->sc_data_direction == DMA_NONE)
+		return 0;
+
+	err = gnttab_alloc_grant_references(SG_TABLESIZE, &gref_head);
+	if (err) {
+		printk(KERN_ERR "scsifront: gnttab_alloc_grant_references() error\n");
+		return -ENOMEM;
+	}
+
+	if (sc->use_sg) {
+		/* quoted scsi_lib.c/scsi_req_map_sg . */
+		struct scatterlist *sg = (struct scatterlist *)sc->request_buffer;
+		unsigned int data_len = 0;
+		nr_pages = (sc->request_bufflen + sg[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+		if (nr_pages > SG_TABLESIZE) {
+			ref_cnt = (-ENOMEM);
+			goto big_to_sg;
+		}
+
+		for (i = 0; i < sc->use_sg; i++) {
+			page = sg[i].page;
+			off = sg[i].offset;
+			len = sg[i].length;
+			data_len += len;
+
+			buffer_pfn = page_to_phys(page) >> PAGE_SHIFT;
+
+			while (len > 0) {
+				bytes = min_t(unsigned int, len, PAGE_SIZE - off);
+				
+				ref = gnttab_claim_grant_reference(&gref_head);
+				BUG_ON(ref == -ENOSPC);  /*FIXME*/
+
+				gnttab_grant_foreign_access_ref(ref, info->dev->otherend_id,
+					buffer_pfn, write);
+
+				info->shadow[id].u.scsi.gref[ref_cnt] = ref;
+				ftb_req->u.scsi.seg[ref_cnt].gref     = ref;
+				ftb_req->u.scsi.seg[ref_cnt].offset   = off;
+				ftb_req->u.scsi.seg[ref_cnt].length   = bytes;
+
+				buffer_pfn++;
+				len -= bytes;
+				off = 0;
+				ref_cnt++;
+			}
+		}
+	} else if (sc->request_bufflen) {
+		unsigned long end   = ((unsigned long)sc->request_buffer
+					+ sc->request_bufflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
+		unsigned long start = (unsigned long)sc->request_buffer >> PAGE_SHIFT;
+
+		page = virt_to_page(sc->request_buffer);
+		nr_pages = end - start;
+		len = sc->request_bufflen;
+
+		if (nr_pages > SG_TABLESIZE) {
+			ref_cnt = (-ENOMEM);
+			goto big_to_sg;
+		}
+
+		buffer_pfn = page_to_phys(page) >> PAGE_SHIFT;
+
+		off = offset_in_page((unsigned long)sc->request_buffer);
+		for (i = 0; i < nr_pages; i++) {
+			bytes = PAGE_SIZE - off;
+
+			if (bytes > len)
+				bytes = len;
+
+			ref = gnttab_claim_grant_reference(&gref_head);
+			BUG_ON(ref == -ENOSPC);  /*FIXME*/
+
+			gnttab_grant_foreign_access_ref(ref, info->dev->otherend_id,
+				buffer_pfn, write);
+
+			info->shadow[id].u.scsi.gref[i] = ref;
+			ftb_req->u.scsi.seg[i].gref     = ref;
+			ftb_req->u.scsi.seg[i].offset   = off;
+			ftb_req->u.scsi.seg[i].length   = bytes;
+			
+/*			page = pfn_to_page(++buffer_mfn);*/
+			buffer_pfn++;
+			len -= bytes;
+			off = 0;
+			ref_cnt++;
+		}
+	}
+
+big_to_sg:
+
+	gnttab_free_grant_references(gref_head);
+
+	return ref_cnt;
+}
+
+static int scsifront_queuecommand(struct scsi_cmnd *sc,
+					void (*done)(struct scsi_cmnd *))
+{
+	struct Scsi_Host *host = sc->device->host;
+	struct comfront_info *info = (struct comfront_info *) host->hostdata;
+	struct vscsiif_ftb_request *ftb_req;
+	int ref_cnt;
+
+	if (info->dev->state != XenbusStateConnected) {
+		printk(KERN_ERR "scsifront: XenbusState not connected %u!\n",
+				info->dev->state);
+		sc->result = DID_NO_CONNECT << 16;
+		done(sc);
+		return 0;
+	}
+
+	if (RING_FULL(&info->ftb_ring)) {
+		/*printk(KERN_INFO "scsifront: FTB Ring Full busy\n");*/
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+
+	if (read_ftb_ring_resp_cons(info)) {
+		/*printk("scsifront: BTF Ring Full busy\n");*/
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+	
+	sc->scsi_done = done;
+	sc->result    = 0;
+
+	ftb_req                 = comfront_pre_request(info);
+	ftb_req->cmnd           = CMND_SCSI;
+
+	ftb_req->u.scsi.id      = sc->device->id;
+	ftb_req->u.scsi.lun     = sc->device->lun;
+	ftb_req->u.scsi.channel = sc->device->channel;
+	ftb_req->u.scsi.cmd_len = sc->cmd_len;
+
+	BUG_ON(sc->cmd_len > VSCSI_MAX_COMMAND_SIZE);
+	BUG_ON(sc == NULL);
+
+	if ( sc->cmd_len )
+		memcpy(ftb_req->u.scsi.cmnd, sc->cmnd, sc->cmd_len);
+	else
+		memset(ftb_req->u.scsi.cmnd, 0, VSCSI_MAX_COMMAND_SIZE);
+
+	ftb_req->u.scsi.sc_data_direction   = sc->sc_data_direction;
+	ftb_req->u.scsi.request_bufflen     = sc->request_bufflen;
+	ftb_req->u.scsi.timeout_per_command = sc->timeout_per_command;
+
+	info->shadow[ftb_req->rqid].u.scsi.req_scsi_cmnd = (unsigned long)sc;
+	info->shadow[ftb_req->rqid].u.scsi.sc_data_direction
+							 = sc->sc_data_direction;
+	info->shadow[ftb_req->rqid].u.scsi.request_bufflen
+					 = sc->request_bufflen;
+	info->shadow[ftb_req->rqid].cmnd = ftb_req->cmnd;
+
+	ref_cnt = map_data_for_request(info, sc, ftb_req, ftb_req->rqid);
+	if (unlikely(ref_cnt < 0)) {
+		ADD_ID_TO_FREELIST(info, ftb_req->rqid);
+		notify_remote_via_irq(info->irq);
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+
+	ftb_req->u.scsi.use_sg                    = ref_cnt;
+	info->shadow[ftb_req->rqid].u.scsi.use_sg = ref_cnt;
+
+	scsi_trace(1, (unsigned char *)ftb_req,
+		   sizeof(struct vscsiif_ftb_request));
+
+	comfront_do_request(info);
+
+	return 0;
+}
+
+
+static int scsifront_eh_abort_handler(struct scsi_cmnd *sc)
+{
+	/* not implemented */
+	printk(KERN_ERR "scsifront: abort! 0 return.\n");
+	return (FAILED);
+}
+
+
+static int scsifront_eh_host_reset_handler(struct scsi_cmnd *sc)
+{
+	struct Scsi_Host *host = sc->device->host;
+	struct comfront_info *info = (struct comfront_info *) host->hostdata;
+ 	struct vscsiif_ftb_request *ring_req;
+	struct vscsiif_btf_request *ring_res;
+	int err = FAILED;
+	
+	printk(KERN_INFO "scsifront: reset.\n");
+
+	scsi_block_requests(host);
+
+	ring_req = comfront_pre_request(info);
+
+	ring_req->cmnd          = CMND_SCSI_RESET;
+	ring_req->u.scsi.id      = sc->device->id;
+	ring_req->u.scsi.lun     = sc->device->lun;
+	ring_req->u.scsi.channel = sc->device->channel;
+
+	spin_unlock_irq(info->host->host_lock);
+
+	ring_res = comfront_do_request_and_wait_response(info, ring_req);
+
+	err = (ring_res->rslt ? SUCCESS : FAILED);
+
+	scsi_unblock_requests(host);
+
+	return (err);
+}
+
+
+static void scsifront_gnttab_done(struct comfront_shadow *s, uint32_t id)
+{
+	int i;
+
+	if (s->u.scsi.sc_data_direction == DMA_NONE)
+		return;
+
+	if (s->u.scsi.use_sg) {
+		for (i = 0; i < s->u.scsi.use_sg; i++) {
+			if (unlikely(gnttab_query_foreign_access(
+				s->u.scsi.gref[i]) != 0)) {
+				printk(KERN_ALERT "scsifront: "
+					"grant still in use by backend.\n");
+				BUG();
+			}
+			gnttab_end_foreign_access(s->u.scsi.gref[i], 0, 0UL);
+		}
+	} else if (s->u.scsi.request_bufflen) {
+		gnttab_end_foreign_access(s->u.scsi.gref[0], 0, 0UL);
+	} else {
+		return;
+	}
+}
+
+
+int scsifront_cmd_done(struct comfront_info *info,
+				   struct vscsiif_btf_request *btf_req)
+{
+	struct scsi_cmnd	*sc;
+	uint32_t id;
+
+	id = btf_req->rqid;
+	sc = (struct scsi_cmnd *)info->shadow[id].u.scsi.req_scsi_cmnd;
+
+	if (sc == NULL)
+		return 1;
+
+	scsifront_gnttab_done(&info->shadow[id], id);
+	ADD_ID_TO_FREELIST(info, id);
+
+	sc->result = btf_req->rslt;
+	sc->resid  = 0;
+
+	BUG_ON(btf_req->u.scsi.sense_len > SCSI_SENSE_BUFFERSIZE);
+	
+	if( btf_req->rslt != 0 ) {
+		if (btf_req->u.scsi.sense_len)
+			memcpy(sc->sense_buffer, btf_req->u.scsi.sense_buffer,
+				btf_req->u.scsi.sense_len);
+	}
+
+	sc->scsi_done(sc);
+
+	return 0;
+}
+
+
+static int scsifront_alloc_ring(struct comfront_info *info)
+{
+	struct xenbus_device *dev = info->dev;
+	struct vscsiif_ftb_sring *ftb;
+	struct vscsiif_btf_sring *btf;
+	int err = -ENOMEM;
+
+	info->ftb_ring_ref = GRANT_INVALID_REF;
+	info->btf_ring_ref = GRANT_INVALID_REF;
+
+	/***** Frontend to Backend ring start *****/
+	ftb = (struct vscsiif_ftb_sring *) __get_free_page(GFP_KERNEL);
+	if (!ftb) {
+		xenbus_dev_fatal(dev, err, "fail to allocate shared ring (Front to Back)");
+		return err;
+	}
+	SHARED_RING_INIT(ftb);
+	FRONT_RING_INIT(&info->ftb_ring, ftb, PAGE_SIZE);
+
+	err = xenbus_grant_ring(dev, virt_to_mfn(ftb));
+	if (err < 0) {
+		free_page((unsigned long) ftb);
+		info->ftb_ring.sring = NULL;
+		xenbus_dev_fatal(dev, err, "fail to grant shared ring (Front to Back)");
+		goto free_sring;
+	}
+	info->ftb_ring_ref = err;
+
+	/***** Backend to Frontend ring start *****/
+	btf = (struct vscsiif_btf_sring *) __get_free_page(GFP_KERNEL);
+	if (!btf) {
+		xenbus_dev_fatal(dev, err, "fail to allocate shared ring (Back to Front)");
+		return err;
+	}
+	SHARED_RING_INIT(btf);
+	BACK_RING_INIT(&info->btf_ring, btf, PAGE_SIZE);
+
+	err = xenbus_grant_ring(dev, virt_to_mfn(btf));
+	if (err < 0) {
+		free_page((unsigned long) btf);
+		info->btf_ring.sring = NULL;
+		xenbus_dev_fatal(dev, err, "fail to grant shared ring (Back to Front)");
+		goto free_sring;
+	}
+	info->btf_ring_ref = err;
+	
+	err = bind_listening_port_to_irqhandler(
+			dev->otherend_id, comfront_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:
+	scsifront_free(info);
+
+	return err;
+}
+
+static int scsifront_init_ring(struct comfront_info *info)
+{
+	struct xenbus_device *dev = info->dev;
+	struct xenbus_transaction xbt;
+	int err;
+
+	DPRINTK("%s\n",__FUNCTION__);
+
+	err = scsifront_alloc_ring(info);
+	if (err)
+		return err;
+	DPRINTK("%u %u %u\n", info->ftb_ring_ref, info->ftb_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, "ftb-ring-ref", "%u",
+				info->ftb_ring_ref);
+	if (err) {
+		xenbus_dev_fatal(dev, err, "%s", "writing ftb-ring-ref");
+		goto fail;
+	}
+	err = xenbus_printf(xbt, dev->nodename, "btf-ring-ref", "%u",
+				info->btf_ring_ref);
+	if (err) {
+		xenbus_dev_fatal(dev, err, "%s", "writing btf-ring-ref");
+		goto fail;
+	}
+
+	err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+				irq_to_evtchn_port(info->irq));
+
+	if (err) {
+		xenbus_dev_fatal(dev, err, "%s", "writing event-channel");
+		goto fail;
+	}
+
+	err = xenbus_printf(xbt, dev->nodename, "vhostno", "%d",
+				info->host->host_no);
+
+	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,
+	.eh_host_reset_handler	= scsifront_eh_host_reset_handler,
+	.cmd_per_lun		= DEFAULT_CMD_PER_LUN,
+	.can_queue		= 16,
+	.this_id 		= -1,
+	.sg_tablesize		= SG_TABLESIZE,
+	.use_clustering		= DISABLE_CLUSTERING,
+	.proc_name		= "scsifront",
+};
+
+static int scsifront_connect(struct comfront_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);
+
+#ifdef CONFIG_XEN_FC
+	(void)fcfront_get_function_template(info);
+
+	fc_transport_template = fc_attach_transport(&fc_transport_functions);
+	host->transportt = fc_transport_template;
+#endif
+	/* FIXME */
+	host->max_id      = 64;
+	host->max_channel = 0;
+	host->max_lun     = 128;
+	host->max_sectors = (SG_TABLESIZE * PAGE_SIZE / 512);
+	host->cmd_per_lun = req_per_lun;
+
+	err = scsi_add_host(host, &dev->dev);
+	if (err) {
+		printk(KERN_ERR "scsifront: fail to add scsi host %d\n", err);
+		return err;
+	}
+
+	scsi_scan_host(host);
+
+#ifdef CONFIG_XEN_FC
+	(void)fcfront_get_initial_attribute(info);
+#endif
+
+	return 0;
+}
+
+static int scsifront_disconnect(struct comfront_info *info)
+{
+	struct xenbus_device *dev = info->dev;
+
+	DPRINTK("%s: %s remove\n",__FUNCTION__ ,dev->nodename);
+
+#ifdef CONFIG_XEN_FC
+	fc_remove_host(info->host);
+#endif
+	scsi_remove_host(info->host);
+	scsi_host_put(info->host);
+
+	xenbus_frontend_closed(dev);
+
+	return 0;
+}
+
+static int scsifront_probe(struct xenbus_device *dev,
+				const struct xenbus_device_id *id)
+{
+	struct Scsi_Host *host;
+	struct comfront_info *info;
+	int i, err = -ENOMEM;
+	char name[DEFAULT_TASK_COMM_LEN];
+
+	host = scsi_host_alloc(&scsifront_sht, sizeof(*info));
+	if (!host) {
+		xenbus_dev_fatal(dev, err, "fail to allocate scsi host");
+		return err;
+	}
+	info = (struct comfront_info *) host->hostdata;
+	dev->dev.driver_data = info;
+	info->dev  = dev;
+	info->host = host;
+
+	for (i = 0; i < DEFAULT_CAN_QUEUE; i++) {
+		info->shadow[i].rqid = i + 1;
+		init_waitqueue_head(&(info->shadow[i].wq));
+		info->shadow[i].cond = 0;
+	}
+	info->shadow[DEFAULT_CAN_QUEUE - 1].rqid = 0x0fffffff;
+
+#ifdef CONFIG_XEN_FC
+	if ((err = fcfront_connection_setup(info)) != 0) {
+		printk(KERN_ERR
+		       "scsifront: %s: fcfront_connection_setup() error\n",
+		       __FUNCTION__);
+		return err;
+	}
+#endif
+	
+	err = scsifront_init_ring(info);
+	if (err) {
+		scsi_host_put(host);
+		return err;
+	}
+
+	init_waitqueue_head(&info->wq);
+	spin_lock_init(&info->io_lock);
+	spin_lock_init(&info->shadow_lock);
+
+	snprintf(name, DEFAULT_TASK_COMM_LEN, "scsiif.%d", info->host->host_no);
+
+	info->kthread = kthread_run(comfront_schedule, info, name);
+	if (IS_ERR(info->kthread)) {
+		err = PTR_ERR(info->kthread);
+		info->kthread = NULL;
+	}
+
+	return 0;
+}
+
+
+static int scsifront_remove(struct xenbus_device *dev)
+{
+	struct comfront_info *info = dev->dev.driver_data;
+
+	DPRINTK("%s: %s removed\n",__FUNCTION__ ,dev->nodename);
+
+	if (info->kthread) {
+		kthread_stop(info->kthread);
+		info->kthread = NULL;
+	}
+
+#ifdef CONFIG_XEN_FC
+	fcfront_connection_unsetup(info);
+#endif
+	scsifront_free(info);
+	
+	/*kfree(info);*/
+	return 0;
+}
+
+static void scsifront_backend_changed(struct xenbus_device *dev,
+					XenbusState backend_state)
+{
+	struct comfront_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:
+		scsifront_disconnect(info);
+		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 0 /* for DEBUG */
+	printk(KERN_ERR "%s: ftb_req=%d\n", __FUNCTION__,
+	       sizeof(struct vscsiif_ftb_request));
+	printk(KERN_ERR "%s: ftb_res=%d\n", __FUNCTION__,
+	       sizeof(struct vscsiif_ftb_response));
+	printk(KERN_ERR "%s: btf_req=%d\n", __FUNCTION__,
+	       sizeof(struct vscsiif_btf_request));
+	printk(KERN_ERR "%s: btf_res=%d\n", __FUNCTION__,
+	       sizeof(struct vscsiif_btf_response));
+
+	printk("%s SCSI_RING_SIZE_ftb=%ld\n", __FUNCTION__,
+		__RING_SIZE((struct vscsiif_ftb_sring *)0, PAGE_SIZE));
+	printk("%s SCSI_RING_SIZE_btf=%ld\n", __FUNCTION__,
+		__RING_SIZE((struct vscsiif_btf_sring *)0, PAGE_SIZE));
+
+#endif  /* for DEBUG */
+
+	if (!is_running_on_xen())
+		return -ENODEV;
+
+#ifdef CONFIG_XEN_FC
+	if (is_initial_xendomain()) {
+		return 0;
+	}
+#endif
+
+	err = xenbus_register_frontend(&scsifront_driver);
+
+	(void)scsi_trace_init();
+	
+	return err;
+}
+
+static void scsifront_exit(void)
+{
+	xenbus_unregister_driver(&scsifront_driver);
+
+#ifdef CONFIG_XEN_FC
+	fc_release_transport(fc_transport_template);
+#endif
+}
+
+module_init(scsifront_init);
+module_exit(scsifront_exit);
+
+MODULE_DESCRIPTION("Xen SCSI frontend driver");
+MODULE_LICENSE("GPL");
diff -r 709db80c03c3 -r 24e0cb9fe9df drivers/xen/scsifront/tracefront.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/tracefront.c	Tue Oct 30 16:41:36 2007 +0900
@@ -0,0 +1,107 @@
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+
+#include <linux/time.h>
+//#include <asm/delay.h>
+
+
+#define MAX_DATA_SIZE		472		/* should be modified	*/
+						/*   according to data	*/
+						/*   to be recorded	*/
+#define ENTRY_NUM		(16 * 1024)
+
+struct scsi_trace_entry {
+	unsigned long	dir;			/* direction		*/
+						/* 0: pending(BE)	*/
+						/* 1: request(FE)	*/
+						/* 2: response(FE)	*/
+	unsigned long	serial;			/* incremental counter	*/
+						/*   starts at 0 	*/
+	struct timeval	tv;			/* timeofday		*/
+//	unsigned long	itc;			/* itc			*/
+	unsigned int	size;			/* data size		*/
+	unsigned char	data[MAX_DATA_SIZE];	/* data body		*/
+};
+
+static struct scsi_trace_entry	*scsi_trace_buf;
+EXPORT_SYMBOL(scsi_trace_buf);			/* for DUMP		*/
+
+static DEFINE_SPINLOCK(scsi_trace_lock);
+
+void
+scsi_trace(unsigned long dir, unsigned char *data, unsigned int size)
+{
+	static unsigned long	index  = 0;
+	static unsigned long	serial = 0;
+	unsigned long		flags;
+
+	if (size > MAX_DATA_SIZE) {
+		printk(KERN_ERR "%s: data given is too big.\n"
+		       "must be smaller than %d bytes.\n",
+		       __FUNCTION__, MAX_DATA_SIZE);
+		return;
+	}
+
+	spin_lock_irqsave(&scsi_trace_lock, flags);
+
+	scsi_trace_buf[index].dir    = dir;
+	do_gettimeofday(&(scsi_trace_buf[index].tv));
+//	scsi_trace_buf[index].itc    = ia64_get_itc();
+	scsi_trace_buf[index].size   = size;
+//	memset(scsi_trace_buf[index].data, 0, MAX_DATA_SIZE);
+	memcpy(scsi_trace_buf[index].data, data, size);
+
+	/* This indicates that the record is successfully recorded */
+	scsi_trace_buf[index].serial = serial++;
+
+	index = (index + 1) % ENTRY_NUM;
+	
+	spin_unlock_irqrestore(&scsi_trace_lock, flags);
+
+}
+
+static int
+scsi_trace_read_proc(char *page, char **start, off_t off,
+		     int count, int *eof, void *data)
+{
+	int		len = sizeof(struct scsi_trace_entry) * ENTRY_NUM;
+        unsigned long	flags;
+
+        spin_lock_irqsave(&scsi_trace_lock, flags);
+
+        if (len <= off + count) {
+		*eof = 1;
+	}
+        *start = page;
+        len -= off;
+        if (len > count) {
+		len = count;
+	}
+        if (len < 0) {
+                len = 0;
+        } else {
+                memcpy(page, ((unsigned char *)scsi_trace_buf) + off, len);
+	}
+
+        spin_unlock_irqrestore(&scsi_trace_lock, flags);
+
+        return len;
+}
+
+int
+scsi_trace_init(void)
+{
+	unsigned int	scsi_trace_buf_size;
+
+	scsi_trace_buf_size = sizeof(struct scsi_trace_entry) * ENTRY_NUM;
+	if ((scsi_trace_buf = vmalloc(scsi_trace_buf_size)) == NULL) {
+		return -1;
+	}
+	memset(scsi_trace_buf, 0, scsi_trace_buf_size);
+
+	create_proc_read_entry("scsi_trace", 0, NULL,
+			       scsi_trace_read_proc, NULL);
+
+	return 0;
+}

[-- 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-10-30 10:39 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-10-19  5:15 [PATCH 0/5] pvSCSI (SCSI pass through) driver Jun Kamada
2007-10-19  8:38 ` Keir Fraser
2007-10-19 10:20   ` Ian Pratt
2007-10-22  2:39     ` Jun Kamada
2007-10-22  0:07 ` James Harper
2007-10-23  7:41   ` Jun Kamada
2007-10-22  8:58 ` Keir Fraser
2007-10-23  7:09   ` Jun Kamada
2007-10-23  8:50     ` Keir Fraser
2007-10-23 11:35       ` Jun Kamada
2007-10-23 12:39         ` Keir Fraser
2007-10-24  6:22           ` Jun Kamada
2007-10-24  7:42             ` Keir Fraser
2007-10-25  1:59               ` Jun Kamada
2007-10-30 10:39                 ` [PATCH 0/6] " Jun Kamada
2007-10-30 10:56                   ` Keir Fraser
2007-10-31  8:37                     ` Jun Kamada
2007-10-31  9:10                       ` Keir Fraser
2007-10-31 10:56                         ` Jun Kamada
2007-10-31 11:15                           ` Keir Fraser
2007-11-01 12:14                   ` Stephen C. Tweedie
2007-11-02  0:23                     ` James Harper
2007-11-05  3:30                       ` Jun Kamada
2007-11-05  2:05                     ` Jun Kamada
2007-11-08 21:33                       ` Stephen C. Tweedie
2007-11-12  8:27                         ` Jun Kamada
2007-11-05  3:34                     ` Aaron Dailey
2007-10-30 10:39                 ` Jun Kamada [this message]
2007-10-30 10:39                 ` [PATCH 2/6] " Jun Kamada
2007-10-30 10:39                 ` [PATCH 3/6] " Jun Kamada
2007-10-30 10:39                 ` [PATCH 4/6] " Jun Kamada
2007-10-30 10:39                 ` [PATCH 5/6] " Jun Kamada
2007-10-30 10:39                 ` [PATCH 6/6] " Jun Kamada

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=20071030193911.4419.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.