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] [4/4] PV driver for FC transport layer (FC transport layer driver)
Date: Fri, 29 Jun 2007 20:08:16 +0900	[thread overview]
Message-ID: <20070629200737.69F2.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: fcdriver.patch --]
[-- Type: application/octet-stream, Size: 60950 bytes --]

# HG changeset patch
# User Jun Kamada <kama@jp.fujitsu.com>
# Date 1183114138 -32400
# Node ID 99d47e3f5430faa0014f95ef9810a34cf775befc
# Parent  0f169b36be81293df09f1c66b6284dc00270854f
FC transport layer extension for pv-scsi driver

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

diff -r 0f169b36be81 -r 99d47e3f5430 drivers/scsi/scsi_transport_fc.c
--- a/drivers/scsi/scsi_transport_fc.c	Fri Jun 29 18:09:19 2007 +0900
+++ b/drivers/scsi/scsi_transport_fc.c	Fri Jun 29 19:48:58 2007 +0900
@@ -253,6 +253,24 @@ struct fc_internal {
 };
 
 #define to_fc_internal(tmpl)	container_of(tmpl, struct fc_internal, t)
+
+#ifdef CONFIG_XEN_SCSI_FC
+struct fc_function_template *
+fc_shost2ft(struct Scsi_Host *shost)
+{
+	struct fc_internal	*i = to_fc_internal(shost->transportt);
+
+	return i->f;
+}
+
+void
+fc_update_ft(struct Scsi_Host *shost, struct fc_function_template *ft)
+{
+	struct fc_internal	*i = to_fc_internal(shost->transportt);
+
+	i->f = ft;
+}
+#endif
 
 static int fc_target_setup(struct transport_container *tc, struct device *dev,
 			   struct class_device *cdev)
diff -r 0f169b36be81 -r 99d47e3f5430 drivers/xen/Kconfig
--- a/drivers/xen/Kconfig	Fri Jun 29 18:09:19 2007 +0900
+++ b/drivers/xen/Kconfig	Fri Jun 29 19:48:58 2007 +0900
@@ -194,6 +194,11 @@ config XEN_SCSI_FRONTEND
 	  The SCSI frontend driver allows the kernel to access SCSI HBAs
 	  within another guest OS.
 
+config XEN_SCSI_FC
+	tristate "SCSI Fibre Channel Support"
+	depends on XEN_SCSI_BACKEND || XEN_SCSI_FRONTEND
+	default y
+
 config XEN_NETDEV_FRONTEND
 	tristate "Network-device frontend driver"
 	depends on XEN && NET
diff -r 0f169b36be81 -r 99d47e3f5430 drivers/xen/scsiback/Makefile
--- a/drivers/xen/scsiback/Makefile	Fri Jun 29 18:09:19 2007 +0900
+++ b/drivers/xen/scsiback/Makefile	Fri Jun 29 19:48:58 2007 +0900
@@ -1,2 +1,3 @@ obj-$(CONFIG_XEN_SCSI_BACKEND)	+= scsibk
 obj-$(CONFIG_XEN_SCSI_BACKEND)	+= scsibk.o
+obj-$(CONFIG_XEN_SCSI_FC)	+= fcback.o
 scsibk-y			+= interface.o scsiback.o
diff -r 0f169b36be81 -r 99d47e3f5430 drivers/xen/scsiback/common.h
--- a/drivers/xen/scsiback/common.h	Fri Jun 29 18:09:19 2007 +0900
+++ b/drivers/xen/scsiback/common.h	Fri Jun 29 19:48:58 2007 +0900
@@ -79,6 +79,10 @@ struct scsiback_info {
 	wait_queue_head_t wq;
 	unsigned int waiting_reqs;
 
+#ifdef CONFIG_XEN_SCSI_FC
+	void	*fcinfo;
+#endif
+
 	struct page **mmap_pages;
 };
 
diff -r 0f169b36be81 -r 99d47e3f5430 drivers/xen/scsiback/fcback.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/fcback.c	Fri Jun 29 19:48:58 2007 +0900
@@ -0,0 +1,724 @@
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <xen/xenbus.h>
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/ring.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include "fc.h"
+#include "common.h"
+
+extern void	unbind_from_irqhandler(unsigned int, void *);
+extern struct fc_function_template	*fc_shost2ft(struct Scsi_Host *);
+
+static struct mutex	lock;
+
+
+/* ---------------------------------------------------------------------- */
+
+static struct scsi_target *
+shost_to_starget(struct Scsi_Host *shost,
+		 unsigned int channel, unsigned int id)
+{
+	struct scsi_target	*starget, *found_starget = NULL;
+
+	list_for_each_entry(starget, &(shost->__targets), siblings) {
+		if ((starget->channel == channel) && (starget->id == id)) {
+			found_starget = starget;
+			break;
+		}
+	}
+
+	return found_starget;
+}
+
+static struct fc_rport *
+shost_to_rport(struct Scsi_Host *shost, u64 node_name,
+	       u64 port_name, u32 port_id, u32 roles)
+{
+	struct fc_rport		*rport, *found_rport = NULL;
+
+	list_for_each_entry(rport, &fc_host_rports(shost), peers) {
+		if ((rport->node_name == node_name) &&
+			(rport->port_name == port_name) &&
+			(rport->port_id   == port_id)   &&
+			(rport->roles     == roles)) {
+			found_rport = rport;
+			break;
+		}
+	}
+
+	return found_rport;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+static int
+fcback_main(struct fcback_info *info)
+{
+	struct fcif_back_ring	*ring = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+
+	/* Must check by class or something ... */
+	if ((strcmp(info->scsiinfo->host->hostt->name, "qla2xxx") != 0) &&
+		(strcmp(info->scsiinfo->host->hostt->name, "lpfc") != 0)) {
+		printk(KERN_ERR
+		       "<<<%s: not a supported fibre channel card>>>\n",
+		       __FUNCTION__);
+		return -1;
+	}
+
+	mutex_lock(&lock);
+	
+	/*
+	  Receive request from DomU
+	*/
+	{
+		ring_req = RING_GET_REQUEST(ring, 0);
+	}
+
+	/*
+	  Perform specified function and send response to DomU
+	*/
+	{
+		struct fc_function_template
+				*ft = fc_shost2ft(info->scsiinfo->host);
+		struct scsi_target	*starget;
+		struct fc_rport		*rport;
+		
+		ring_res = RING_GET_RESPONSE(ring, 1);
+
+		ring_res->rslt = -1;
+
+		switch (ring_req->cmnd) {
+		case CMND_GET_HOST_PORT_ID:
+			if ((ft->show_host_port_id != 0) &&
+				(ft->get_host_port_id != NULL)) {
+				ft->get_host_port_id(info->scsiinfo->host);
+				ring_res->u.ghpi.port_id =
+					((struct fc_host_attrs *)
+					 (info->scsiinfo->host->shost_data))->port_id;
+				ring_res->rqid = ring_req->rqid;
+				ring_res->rslt = 0;
+			}
+			break;
+			
+		case CMND_GET_HOST_PORT_TYPE:
+			if ((ft->show_host_port_type != 0) &&
+				(ft->get_host_port_type != NULL)) {
+				ft->get_host_port_type(info->scsiinfo->host);
+				ring_res->u.ghpt.port_type =
+					((struct fc_host_attrs *)
+					 (info->scsiinfo->host->shost_data))->port_type;
+				ring_res->rqid = ring_req->rqid;
+				ring_res->rslt = 0;
+			}
+			break;
+			
+		case CMND_GET_HOST_PORT_STATE:
+			if ((ft->show_host_port_state != 0) &&
+				(ft->get_host_port_state != NULL)) {
+				ft->get_host_port_state(info->scsiinfo->host);
+				ring_res->u.ghps.port_state =
+					((struct fc_host_attrs *)
+					 (info->scsiinfo->host->shost_data))->port_state;
+				ring_res->rqid = ring_req->rqid;
+				ring_res->rslt = 0;
+			}
+			break;
+			
+		case CMND_GET_HOST_ACTIVE_FC4S:
+			if ((ft->show_host_active_fc4s != 0) &&
+				(ft->get_host_active_fc4s != NULL)) {
+				ft->get_host_active_fc4s(info->scsiinfo->host);
+				memcpy(ring_res->u.ghaf.active_fc4s,
+				       ((struct fc_host_attrs *)
+					(info->scsiinfo->host->shost_data))->active_fc4s,
+				       sizeof(ring_res->u.ghaf.active_fc4s));
+				ring_res->rqid = ring_req->rqid;
+				ring_res->rslt = 0;
+			}
+			break;
+			
+		case CMND_GET_HOST_SPEED:
+			if ((ft->show_host_speed != 0) &&
+				(ft->get_host_speed != NULL)) {
+				ft->get_host_speed(info->scsiinfo->host);
+				ring_res->u.ghsp.speed =
+					((struct fc_host_attrs *)
+					 (info->scsiinfo->host->shost_data))->speed;
+				ring_res->rqid = ring_req->rqid;
+				ring_res->rslt = 0;
+			}
+			break;
+			
+		case CMND_GET_HOST_FABRIC_NAME:
+			if ((ft->show_host_fabric_name != 0) &&
+				(ft->get_host_fabric_name != NULL)) {
+				ft->get_host_fabric_name(info->scsiinfo->host);
+				ring_res->u.ghfn.fabric_name =
+					((struct fc_host_attrs *)
+					 (info->scsiinfo->host->shost_data))->fabric_name;
+				ring_res->rqid = ring_req->rqid;
+				ring_res->rslt = 0;
+			}
+			break;
+			
+		case CMND_GET_HOST_STATS: {
+			struct fc_host_statistics		*hs;
+
+			if (ft->get_fc_host_stats != NULL) {
+				if ((hs = ft->get_fc_host_stats(
+					info->scsiinfo->host)) == NULL) {
+					break;
+				}
+				ring_res->u.ghst.stats = *hs;
+				ring_res->rqid         = ring_req->rqid;
+				ring_res->rslt         = 0;
+			}
+			break; }
+		  
+		case CMND_RESET_HOST_STATS:
+			if (ft->reset_fc_host_stats != NULL) {
+				ft->reset_fc_host_stats(info->scsiinfo->host);
+				ring_res->rqid = ring_req->rqid;
+				ring_res->rslt = 0;
+			}
+			break;
+			
+		case CMND_ISSUE_HOST_LIP:
+			if (ft->issue_fc_host_lip != NULL) {
+				ring_res->rslt = ft->issue_fc_host_lip(
+							info->scsiinfo->host);
+				ring_res->rqid = ring_req->rqid;
+			}
+			break;
+			
+		case CMND_GET_STARGET_PORT_ID:
+			if ((ft->show_starget_port_id != 0) &&
+				(ft->get_starget_port_id != NULL)) {
+				if ((starget = shost_to_starget(
+					info->scsiinfo->host,
+					ring_req->u.gtpi.channel,
+					ring_req->u.gtpi.id)) == NULL) {
+					break;
+				}
+				ft->get_starget_port_id(starget);
+				ring_res->u.gtpi.port_id =
+					((struct fc_starget_attrs *)
+					 (&(starget->starget_data)))->port_id;
+				ring_res->rqid = ring_req->rqid;
+				ring_res->rslt = 0;
+			}
+			break;
+			
+		case CMND_GET_STARGET_NODE_NAME:
+			if ((ft->show_starget_node_name != 0) &&
+				(ft->get_starget_node_name != NULL)) {
+				if ((starget = shost_to_starget(
+					info->scsiinfo->host,
+					ring_req->u.gtnn.channel,
+					ring_req->u.gtnn.id)) == NULL) {
+					break;
+				}
+				ft->get_starget_node_name(starget);
+				ring_res->u.gtnn.node_name =
+					((struct fc_starget_attrs *)
+					(&(starget->starget_data)))->node_name;
+				ring_res->rqid = ring_req->rqid;
+				ring_res->rslt = 0;
+			}
+			break;
+			
+		case CMND_GET_STARGET_PORT_NAME:
+			if ((ft->show_starget_port_name != 0) &&
+				(ft->get_starget_port_name != NULL)) {
+				if ((starget = shost_to_starget(
+					info->scsiinfo->host,
+					ring_req->u.gtpn.channel,
+					ring_req->u.gtpn.id)) == NULL) {
+					break;
+				}
+				ft->get_starget_port_name(starget);
+				ring_res->u.gtpn.port_name =
+					((struct fc_starget_attrs *)
+					(&(starget->starget_data)))->port_name;
+				ring_res->rqid = ring_req->rqid;
+				ring_res->rslt = 0;
+			}
+			break;
+			
+		case CMND_GET_RPORT_LOSS_TMO:
+			if ((ft->show_rport_dev_loss_tmo != 0) &&
+				(ft->get_rport_dev_loss_tmo != NULL)) {
+				if ((rport = shost_to_rport(
+					info->scsiinfo->host,
+					ring_req->u.gplt.node_name,
+					ring_req->u.gplt.port_name,
+					ring_req->u.gplt.port_id,
+					ring_req->u.gplt.roles)) == NULL) {
+					break;
+				}
+				ft->get_rport_dev_loss_tmo(rport);
+				ring_res->u.gplt.timeout = rport->dev_loss_tmo;
+				ring_res->rqid           = ring_req->rqid;
+				ring_res->rslt           = 0;
+			}
+			break;
+			
+		case CMND_SET_RPORT_LOSS_TMO:
+			if (ft->set_rport_dev_loss_tmo != NULL) {
+				if ((rport = shost_to_rport(
+					info->scsiinfo->host,
+					ring_req->u.splt.node_name,
+					ring_req->u.splt.port_name,
+					ring_req->u.splt.port_id,
+					ring_req->u.splt.roles)) == NULL) {
+					break;
+				}
+				ft->set_rport_dev_loss_tmo(rport,
+						ring_req->u.splt.timeout);
+				ring_res->u.splt.timeout = rport->dev_loss_tmo;
+				ring_res->rqid           = ring_req->rqid;
+				ring_res->rslt           = 0;
+			}
+			break;
+			
+		case CMND_GET_INITIAL_SHOST_ATTRIB: {
+			struct fc_host_attrs	*host_attrs =
+					(struct fc_host_attrs *)
+					(info->scsiinfo->host->shost_data);
+			struct giha		*giha = (struct giha *)
+							(info->gnt_area->addr);
+
+			memcpy(giha->active_fc4s, host_attrs->active_fc4s,
+				   sizeof(giha->active_fc4s));
+			giha->fabric_name       = host_attrs->fabric_name;
+			giha->maxframe_size     = host_attrs->maxframe_size;
+			giha->node_name         = host_attrs->node_name;
+			giha->permanent_port_name =
+				host_attrs->permanent_port_name;
+			giha->port_id           = host_attrs->port_id;
+			giha->port_name         = host_attrs->port_name;
+			giha->port_state        = host_attrs->port_state;
+			giha->port_type         = host_attrs->port_type;
+			memcpy(giha->serial_number, host_attrs->serial_number,
+			       sizeof(giha->serial_number));
+			giha->speed             = host_attrs->speed;
+			{
+				struct fc_host_statistics	*hs;
+
+				if (ft->get_fc_host_stats != NULL) {
+					if ((hs = ft->get_fc_host_stats(
+						info->scsiinfo->host)) != NULL) {
+						giha->stats = *hs;
+					} else {
+						memset(&(giha->stats), 0,
+						       sizeof(giha->stats));
+					}
+				}
+			}
+			giha->supported_classes =
+				host_attrs->supported_classes;
+			memcpy(giha->supported_fc4s,
+			       host_attrs->supported_fc4s,
+			       sizeof(giha->supported_fc4s));
+			giha->supported_speeds  = host_attrs->supported_speeds;
+			memcpy(giha->symbolic_name, host_attrs->symbolic_name,
+				   sizeof(giha->symbolic_name));
+			giha->tgtid_bind_type   = host_attrs->tgtid_bind_type;
+			
+			ring_res->rqid          = ring_req->rqid;
+			ring_res->rslt          = 0;
+			
+			break; }
+		  
+		case CMND_GET_INITIAL_STARGET_ATTRIB: {
+			struct scsi_target	*starget;
+			struct fc_starget_attrs	*starget_attrs;
+			unsigned int		i = 0;
+			struct gita		*gita = (struct gita *)
+						(info->gnt_area->addr);
+
+			list_for_each_entry(starget,
+					    &(info->scsiinfo->host->__targets),
+					    siblings) {
+				starget_attrs = (struct fc_starget_attrs *)
+						(&(starget->starget_data));
+				gita->e[i].channel   = starget->channel;
+				gita->e[i].id        = starget->id;
+				gita->e[i].node_name = starget_attrs->node_name;
+				gita->e[i].port_id   = starget_attrs->port_id;
+				gita->e[i].port_name = starget_attrs->port_name;
+				i++;
+				if (i > SCSI_FC_MAX_STARGET) {
+					ring_res->rslt = -1;
+					goto out_gita;
+				}
+			}
+			gita->num = i;
+
+			ring_res->rqid = ring_req->rqid;
+			ring_res->rslt = 0;
+
+out_gita:
+			break; }
+		  
+		case CMND_GET_INITIAL_RPORT_ATTRIB: {
+			struct fc_rport		*found_rport;
+			unsigned int		i = 0;
+			struct gipa		*gipa = (struct gipa *)
+						(info->gnt_area->addr);
+
+			list_for_each_entry(found_rport,
+				&fc_host_rports(info->scsiinfo->host), peers) {
+				gipa->e[i].dev_loss_tmo   =
+					found_rport->dev_loss_tmo;
+				gipa->e[i].maxframe_size  =
+					found_rport->maxframe_size;
+				gipa->e[i].node_name      =
+					found_rport->node_name;
+				gipa->e[i].port_id        =
+					found_rport->port_id;
+				gipa->e[i].port_name      =
+					found_rport->port_name;
+				gipa->e[i].port_state     =
+					found_rport->port_state;
+				gipa->e[i].roles          =
+					found_rport->roles;
+				gipa->e[i].scsi_target_id =
+					found_rport->scsi_target_id;
+				gipa->e[i].supported_classes =
+					found_rport->supported_classes;
+				gipa->e[i].channel       =
+					found_rport->channel;
+				i++;
+				if (i > SCSI_FC_MAX_RPORT) {
+					ring_res->rslt = -1;
+					goto out_gipa;
+				}
+			}
+			gipa->num = i;
+
+			ring_res->rqid = ring_req->rqid;
+			ring_res->rslt = 0;
+
+out_gipa:
+			break; }
+		  
+		case CMND_GET_FUNCTION_TEMPLATE: {
+			struct fc_function_template	*ft;
+			struct gftp		*gftp = (struct gftp *)
+						(info->gnt_area->addr);
+
+			ft = fc_shost2ft(info->scsiinfo->host);
+			memcpy(&(gftp->ft), ft, sizeof(gftp->ft));
+
+			ring_res->rqid = ring_req->rqid;
+			ring_res->rslt = 0;
+			
+			break; }
+		  
+		default:
+			printk(KERN_ERR "<<<%s: unknown command>>>\n",
+			       __FUNCTION__);
+			ring_res->rslt = -1;
+			break;
+		}
+
+		RING_PUSH_RESPONSES(ring);
+		notify_remote_via_irq(info->irq);
+	}
+
+	mutex_unlock(&lock);
+	
+	return 0;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+static int
+fcback_schedule(void *data)
+{
+	struct fcback_info	*info = (struct fcback_info *)data;
+
+	while (!kthread_should_stop()) {
+		info->cond = 0;
+		wait_event_interruptible(info->wq,
+					 info->cond || kthread_should_stop());
+
+		smp_mb();
+
+		/* do main processing */
+		(void)fcback_main(info);
+	}
+
+	info->kthread = NULL;
+	
+	return 0;
+}
+
+static irqreturn_t
+fcback_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct fcback_info	*info;
+
+	info = (struct fcback_info *)dev_id;
+
+	info->cond = 1;
+	wake_up(&(info->wq));
+
+	return IRQ_HANDLED;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * This function resides on opposite side of __setup_xenstore()
+ * 		in scsifront/fcfront.c
+ */
+static int
+__setup_xenstore(struct fcback_info *info)
+{
+	struct xenbus_device	*dev = info->scsiinfo->dev;
+	unsigned long		rngref;
+	unsigned int		evtchn;
+	int			gntref;
+	int			ret = 0;
+
+	if ((ret = xenbus_gather(XBT_NIL, dev->otherend,
+				 "fc_rngref", "%lu", &rngref,
+				 "fc_evtchn", "%u",  &evtchn,
+				 "fc_gntref", "%d",  &gntref, NULL)) != 0) {
+		printk(KERN_ERR "<<<%s: xenbus_gather() error>>>\n",
+		       __FUNCTION__);
+		return ret;
+	}
+
+	info->rngref = rngref;
+	info->evtchn = evtchn;
+	info->gntref = gntref;
+
+	return 0;
+}
+
+static void
+__unsetup_xenstore(struct fcback_info *info)
+{
+	/* currently, nothing to do */
+}
+
+/*
+ * This function resides on opposite side of __setup_shared_ring()
+ *		in scsifront/fcfront.c
+ */
+static int
+__setup_shared_ring(struct fcback_info *info)
+{
+	unsigned long			rngref = info->rngref;
+	struct gnttab_map_grant_ref	op;
+	struct fcif_sring		*sring;
+	int				ret = 0;
+	
+	/* map shared ring to Dom0's VA */
+	info->ring_area = alloc_vm_area(PAGE_SIZE);
+	if (info->ring_area == NULL) {
+		printk(KERN_ERR "<<<%s: alloc_vm_area() error>>>\n",
+		       __FUNCTION__);
+		ret = -ENOMEM;
+		goto out0;
+	}
+
+	gnttab_set_map_op(&op, (unsigned long)(info->ring_area->addr),
+					  GNTMAP_host_map, rngref,
+					  info->scsiinfo->dev->otherend_id);
+	ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
+	BUG_ON(ret);
+	if (op.status != 0) {
+		printk(KERN_ERR
+		       "<<<%s: HYPERVISOR_grant_table_op() error>>>\n",
+		       __FUNCTION__);
+		ret = op.status;
+		goto out1;
+	}
+
+	sring = (struct fcif_sring *)(info->ring_area->addr);
+	BACK_RING_INIT(&(info->ring), sring, PAGE_SIZE);
+
+	/* at this point, you can access shared ring by info->fcinfo.sring */
+
+	return 0;
+
+out1:
+	free_vm_area(info->ring_area);
+	
+out0:
+	return ret;
+}
+
+static void
+__unsetup_shared_ring(struct fcback_info *info)
+{
+	free_vm_area(info->ring_area);
+
+	/* must perform something about "grant table" */
+
+	info->rngref     = GRANT_INVALID_REF;
+	info->ring.sring = NULL;
+}
+
+static int
+__setup_event_channel(struct fcback_info *info)
+{
+	int		ret = 0;
+	
+	/* for frontend driven communication */
+	/* (frontend -> backend -> frontend) */
+	{
+		int		irq;
+
+		init_waitqueue_head(&(info->wq));
+		
+		if ((irq = bind_interdomain_evtchn_to_irqhandler(
+				info->scsiinfo->dev->otherend_id, info->evtchn,
+				fcback_intr, 0, "fcif-backend", info)) < 0) {
+			printk(KERN_ERR
+			       "<<<%s: bind_interdomain_evtchn_to_irqhandler() error>>>\n",
+			       __FUNCTION__);
+			ret = irq;
+			goto out;
+		}
+		info->irq = irq;
+
+		info->kthread = kthread_run(fcback_schedule, info, "fcif");
+		if (IS_ERR(info->kthread)) {
+			printk(KERN_ERR "<<<%s: kthread_run() error>>>\n",
+			       __FUNCTION__);
+		}
+	}
+
+out:
+	return ret;
+}
+
+static void
+__unsetup_event_channel(struct fcback_info *info)
+{
+	kthread_stop(info->kthread);
+	unbind_from_irqhandler(info->irq, info);
+}
+
+static int
+__setup_grant_table(struct fcback_info *info)
+{
+	struct gnttab_map_grant_ref 	op;
+	struct vm_struct		*gnt_area;
+	int				err;
+
+	if ((gnt_area = alloc_vm_area(PAGE_SIZE)) == NULL) {
+		printk(KERN_ERR "<<<%s: alloc_vm_area() error>>>\n",
+		       __FUNCTION__);
+		return -ENOMEM;
+	}
+
+	gnttab_set_map_op(&op, (unsigned long)(gnt_area->addr),
+			  GNTMAP_host_map,
+			  info->gntref, info->scsiinfo->dev->otherend_id);
+
+	err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
+	if (op.status) {
+		printk(KERN_ERR
+		       "<<<%s: HYPERVISOR_grant_table_op() error>>>\n",
+		       __FUNCTION__);
+		return op.status;
+	}
+
+	info->gnt_area = gnt_area;
+	
+	return 0;
+}
+
+int
+fcback_connection_setup(struct scsiback_info *scsiinfo)
+{
+	struct fcback_info	*info;
+	int			ret = 0;
+
+	{
+		scsiinfo->fcinfo = kmalloc(sizeof(struct fcback_info),
+					   GFP_KERNEL);
+		if (scsiinfo->fcinfo == NULL) {
+			ret = -ENOMEM;
+			goto out0;
+		}
+		memset(scsiinfo->fcinfo, 0, sizeof(struct fcback_info));
+		info = (struct fcback_info *)(scsiinfo->fcinfo);
+		info->scsiinfo = scsiinfo;
+	}
+	
+	/* exchange various parameters through xenstore */
+	if ((ret = __setup_xenstore(info)) != 0) {
+		printk(KERN_ERR "<<<%s: __setup_xenstore() error>>>\n",
+		       __FUNCTION__);
+		goto out1;
+	}
+
+	/* prepare for shared ring */
+	if ((ret = __setup_shared_ring(info)) != 0) {
+		printk(KERN_ERR "<<<%s: __setup_shared_ring() error>>>\n",
+			   __FUNCTION__);
+		goto out1;
+	}
+
+	/* prepare for event channel */
+	if ((ret = __setup_event_channel(info)) != 0) {
+		printk(KERN_ERR "<<<%s: __setup_event_channel() error>>>\n",
+			   __FUNCTION__);
+		goto out2;
+	}
+
+	/* prepare for grant table */
+	if ((ret = __setup_grant_table(info)) != 0) {
+		printk(KERN_ERR "<<<%s: __setup_grant_table() error>>>\n",
+			   __FUNCTION__);
+		goto out2;
+	}
+
+	mutex_init(&lock);
+
+	return 0;
+
+out2:
+	__unsetup_shared_ring(info);
+
+out1:
+	kfree(scsiinfo->fcinfo);
+
+out0:
+	return ret;
+}
+
+void
+fcback_connection_unsetup(struct scsiback_info *scsiinfo)
+{
+	struct fcback_info	*info = (struct fcback_info *)
+						(scsiinfo->fcinfo);
+
+	__unsetup_event_channel(info);
+	__unsetup_shared_ring(info);
+	__unsetup_xenstore(info);
+
+	kfree(scsiinfo->fcinfo);
+}
+
+
+MODULE_DESCRIPTION("Xen Para-Virtual SCSI Fibre Channel Backend Driver");
+MODULE_LICENSE("GPL");
diff -r 0f169b36be81 -r 99d47e3f5430 drivers/xen/scsiback/interface.c
--- a/drivers/xen/scsiback/interface.c	Fri Jun 29 18:09:19 2007 +0900
+++ b/drivers/xen/scsiback/interface.c	Fri Jun 29 19:48:58 2007 +0900
@@ -33,6 +33,10 @@
 #include "common.h"
 #include <xen/evtchn.h>
 #include <linux/kthread.h>
+
+#ifdef CONFIG_XEN_SCSI_FC
+extern void		fcback_connection_unsetup(struct scsiback_info *);
+#endif
 
 static kmem_cache_t *scsiback_cachep;
 
@@ -130,6 +134,10 @@ free_vm:
 
 void scsiback_disconnect(struct scsiback_info *info)
 {
+#ifdef CONFIG_XEN_SCSI_FC
+	fcback_connection_unsetup(info);
+#endif
+	
 	if (info->kthread) {
 		kthread_stop(info->kthread);
 		info->kthread = NULL;
diff -r 0f169b36be81 -r 99d47e3f5430 drivers/xen/scsiback/scsiback.c
--- a/drivers/xen/scsiback/scsiback.c	Fri Jun 29 18:09:19 2007 +0900
+++ b/drivers/xen/scsiback/scsiback.c	Fri Jun 29 19:48:58 2007 +0900
@@ -45,6 +45,10 @@
 
 #define INVALID_GRANT_HANDLE	0xFFFF
 
+#ifdef CONFIG_XEN_SCSI_FC
+extern int	fcback_connection_setup(struct scsiback_info *);
+#endif
+
 typedef struct {
 	struct scsiback_info *info;
 	unsigned long rqid;
@@ -536,6 +540,18 @@ static int scsiback_connect(struct scsib
 		xenbus_dev_error(info->dev, err, "start scsiif");
 	}
 
+#ifdef CONFIG_XEN_SCSI_FC
+	{
+		int	ret;
+
+		if ((ret = fcback_connection_setup(info)) != 0) {
+			printk(KERN_ERR "<<<%s: fcback_setup() error>>>\n",
+			       __FUNCTION__);
+			return ret;
+		}
+	}
+#endif	
+	
 	return 0;
 }
 
@@ -674,6 +690,13 @@ static int __init scsiback_init(void)
 	if (!is_running_on_xen())
 		return -ENODEV;
 
+#ifdef CONFIG_XEN_SCSI_FC
+	if (!is_initial_xendomain()) {
+		printk(KERN_ERR "<<<%s: Not on a Dom0>>>\n", __FUNCTION__);
+		return -1;
+	}
+#endif
+
 	mmap_pages = CAN_QUEUE * SG_TABLESIZE;
 
 	pending_reqs          = kmalloc(sizeof(pending_reqs[0]) *
diff -r 0f169b36be81 -r 99d47e3f5430 drivers/xen/scsifront/Makefile
--- a/drivers/xen/scsifront/Makefile	Fri Jun 29 18:09:19 2007 +0900
+++ b/drivers/xen/scsifront/Makefile	Fri Jun 29 19:48:58 2007 +0900
@@ -1,4 +1,5 @@ obj-$(CONFIG_XEN_SCSI_FRONTEND)	:= xensc
 obj-$(CONFIG_XEN_SCSI_FRONTEND)	:= xenscsi.o
+obj-$(CONFIG_XEN_SCSI_FC)	+= fcfront.o
 
 xenscsi-objs := scsifront.o
 
diff -r 0f169b36be81 -r 99d47e3f5430 drivers/xen/scsifront/fc.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/fc.h	Fri Jun 29 19:48:58 2007 +0900
@@ -0,0 +1,229 @@
+#define CMND_GET_HOST_PORT_ID			  1	/* ghpi */
+#define CMND_GET_HOST_PORT_TYPE			  2	/* ghpt */
+#define CMND_GET_HOST_PORT_STATE		  3	/* ghps */
+#define CMND_GET_HOST_ACTIVE_FC4S		  4	/* ghaf */
+#define CMND_GET_HOST_SPEED			  5	/* ghsp */
+#define CMND_GET_HOST_FABRIC_NAME		  6	/* ghfn */
+#define CMND_GET_HOST_STATS			  7	/* ghst */
+#define CMND_RESET_HOST_STATS			  8	/* rhst */
+#define CMND_ISSUE_HOST_LIP			  9	/* ihli */
+#define CMND_GET_STARGET_PORT_ID		 21	/* gtpi */
+#define CMND_GET_STARGET_NODE_NAME		 22	/* gtnn */
+#define CMND_GET_STARGET_PORT_NAME		 23	/* gtpn */
+#define CMND_GET_RPORT_LOSS_TMO			 41	/* gplt */
+#define CMND_SET_RPORT_LOSS_TMO			 42	/* splt */
+#define CMND_GET_INITIAL_SHOST_ATTRIB		101	/* giha */
+#define CMND_GET_INITIAL_STARGET_ATTRIB		102	/* gita */
+#define CMND_GET_INITIAL_RPORT_ATTRIB		103	/* gipa */
+#define CMND_GET_FUNCTION_TEMPLATE		121	/* gftp */
+
+#define GRANT_INVALID_REF			0
+
+
+/* ----------------------------------------------------------------------
+	Definition of Ring Structures
+   ---------------------------------------------------------------------- */
+/* Definition of
+ *	union  fcif_sring_entry,
+ *	struct fcif_sring,
+ *	struct fcif_front_ring,
+ *	struct fcif_back_ring,
+ *	fcif_sring_t,
+ *	fcif_front_ring_t,
+ *	fcif_back_ring_t
+*/
+struct fcif_request {
+	unsigned int	rqid;
+	unsigned int	cmnd;
+	union {
+		/* Get_sTarget_Port_Id */
+		/* Get_sTarget_Node_Name */
+		/* Get_sTarget_Port_Name */
+		struct {
+			u32	channel;
+			u32	id;
+		} gtpi, gtnn, gtpn;
+	  
+		/* Get_rPort_Loss_Tmo */
+		struct {
+			u64	node_name;
+			u64	port_name;
+			u32	port_id;
+			u32	roles;
+		} gplt;
+
+		/* Set_rPort_Loss_Tmo */
+		struct {
+			u64	node_name;
+			u64	port_name;
+			u32	port_id;
+			u32	roles;
+			u32	timeout;
+		} splt;
+	} u;
+};
+
+struct fcif_response {
+	unsigned int	rqid;
+	unsigned int	rslt;
+	union {
+		/* Get_Host_Port_Id */
+		struct {
+			u32	port_id;
+		} ghpi;
+
+		/* Get_Host_Port_Type */
+		struct {
+			enum fc_port_type	port_type;
+		} ghpt;
+	  
+		/* Get_Host_Port_State */
+		struct {
+			enum fc_port_state	port_state;
+		} ghps;
+	  
+		/* Get_Host_Active_Fc4s */
+		struct {
+			u8	active_fc4s[FC_FC4_LIST_SIZE];
+		} ghaf;
+	  
+		/* Get_Host_SPeed */
+		struct {
+			u32	speed;
+		} ghsp;
+	  
+		/* Get_Host_Fabric_Name */
+		struct {
+			u64	fabric_name;
+		} ghfn;
+	  
+		/* Get_Host_STats */
+		struct {
+			struct fc_host_statistics	stats;
+		} ghst;
+	  
+		/* Get_sTarget_Port_Id */
+		struct {
+			u32	port_id;
+		} gtpi;
+	  
+		/* Get_sTarget_Node_Name */
+		struct {
+			u64	node_name;
+		} gtnn;
+	  
+		/* Get_sTarget_Port_Name */
+		struct {
+			u64	port_name;
+		} gtpn;
+	  
+		/* Get_rPort_Loss_Tmo */
+		struct {
+			u32	timeout;
+		} gplt;
+	  
+		/* Set_rPort_Loss_Tmo */
+		struct {
+			u32	timeout;
+		} splt;
+	} u;
+};
+
+DEFINE_RING_TYPES(fcif, struct fcif_request, struct fcif_response);
+
+
+/* ----------------------------------------------------------------------
+	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;
+	u32			maxframe_size;
+	u64			node_name;
+	u64			permanent_port_name;
+	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];
+	u32			speed;
+	struct fc_host_statistics	stats;
+	u32			supported_classes;
+	u8			supported_fc4s[FC_FC4_LIST_SIZE];
+	u32			supported_speeds;
+	char			symbolic_name[FC_SYMBOLIC_NAME_SIZE];
+	enum fc_tgtid_binding_type	tgtid_bind_type;
+};
+
+struct gita {
+	u32			num;
+	struct {
+		u64		node_name;
+		u32		port_id;
+		u64		port_name;
+		u32		channel;
+		u32		id;
+	} e[SCSI_FC_MAX_STARGET];
+};
+
+struct gipa {
+	u32			num;
+	struct {
+		u32		dev_loss_tmo;
+		u32		maxframe_size;
+		u64		node_name;
+		u32		port_id;
+		u64		port_name;
+		enum fc_port_state	port_state;
+		u32		roles;
+		u32		scsi_target_id;
+		u32		supported_classes;
+		u32		channel;
+	} e[SCSI_FC_MAX_RPORT];
+};
+
+struct gftp {
+	struct fc_function_template	ft;
+};
+
+
+/* ----------------------------------------------------------------------
+	Definition of Internal Information Structures
+   ---------------------------------------------------------------------- */
+
+struct fcfront_info {
+	struct scsifront_info		*scsiinfo;
+	struct fc_host_statistics	hs;
+	unsigned long			rngref;
+	unsigned int			irq;
+
+	struct fcif_front_ring		ring;
+
+	void				*addr;
+	int				gntref;
+  
+	wait_queue_head_t		wq;
+	int				cond;
+};
+
+struct fcback_info {
+	struct scsiback_info		*scsiinfo;
+
+	unsigned long			rngref;
+	unsigned int			evtchn;
+	unsigned int			irq;
+
+	struct vm_struct		*ring_area;
+	struct fcif_back_ring		ring;
+
+	struct vm_struct		*gnt_area;
+	int				gntref;
+
+	struct task_struct		*kthread;
+	wait_queue_head_t		wq;
+	int				cond;
+};
diff -r 0f169b36be81 -r 99d47e3f5430 drivers/xen/scsifront/fcfront.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/fcfront.c	Fri Jun 29 19:48:58 2007 +0900
@@ -0,0 +1,1027 @@
+#include <asm/page.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/irqreturn.h>
+#include <linux/mutex.h>
+#include <xen/xenbus.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_fc.h>
+#include <xen/interface/io/ring.h>
+
+#include "fc.h"
+
+/* must be merged into one instance */
+#if 1
+#include <xen/interface/io/scsiif.h>
+#include <xen/interface/io/ring.h>
+
+/* tentative. Must be moved to *.h file */
+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;
+#ifdef CONFIG_XEN_SCSI_FC
+	void	*fcinfo;
+#endif
+};
+#endif /* 1 */
+
+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 int	gnttab_end_foreign_access_ref(grant_ref_t, int);
+extern void	unbind_from_irqhandler(unsigned int, void *);
+extern void	gnttab_end_foreign_access(grant_ref_t, int, unsigned long);
+
+extern struct fc_function_template	*fc_shost2ft(struct Scsi_Host *);
+extern void	fc_update_ft(struct Scsi_Host *,
+			     struct fc_function_template *);
+
+/* copied "ft", which is corrected by Dom0's "ft" */
+static struct fc_function_template	pvfc_transport_functions;
+static struct mutex			lock;
+static unsigned int			rqid_seed = 0;
+
+
+/* ---------------------------------------------------------------------- */
+static struct fcif_response *
+__do_request_and_wait_response(struct fcfront_info *info)
+{
+	struct fcif_front_ring		*ring = &(info->ring);
+	struct fcif_response		*ring_res;
+	
+	RING_PUSH_REQUESTS(ring);
+	notify_remote_via_irq(info->irq);
+
+	info->cond = 0;
+	wait_event_interruptible(info->wq, info->cond);
+	
+	ring_res = RING_GET_RESPONSE(ring, 1);
+
+#if 1
+	printk(KERN_ERR "<<<%s: rqid=%u>>>\n", __FUNCTION__, ring_res->rqid);
+#endif
+
+	return ring_res;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+static void
+fc_get_host_port_id(struct Scsi_Host *shost)
+{
+	struct fcfront_info	*info = ((struct scsifront_info *)
+					 (shost->hostdata))->fcinfo;
+	struct fcif_front_ring	*ring = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+
+	mutex_lock(&lock);
+	
+	ring_req       = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+	ring_req->rqid = rqid_seed++;
+	ring_req->cmnd = CMND_GET_HOST_PORT_ID;
+	
+	ring_res = __do_request_and_wait_response(info);
+	if (ring_res->rslt == 0) {
+		fc_host_port_id(shost) = ring_res->u.ghpi.port_id;
+	} else {
+		fc_host_port_id(shost) = (u32)0xffffffff;
+	}
+
+	mutex_unlock(&lock);
+}
+
+static void
+fc_get_host_port_type(struct Scsi_Host *shost)
+{
+	struct fcfront_info	*info = ((struct scsifront_info *)
+					 (shost->hostdata))->fcinfo;
+	struct fcif_front_ring	*ring = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+
+	mutex_lock(&lock);
+	
+	ring_req       = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+	ring_req->rqid = rqid_seed++;
+	ring_req->cmnd = CMND_GET_HOST_PORT_TYPE;
+	
+	ring_res = __do_request_and_wait_response(info);
+	if (ring_res->rslt == 0) {
+		fc_host_port_type(shost) = ring_res->u.ghpt.port_type;
+	} else {
+		fc_host_port_type(shost) = (u32)0xffffffff;
+	}
+
+	mutex_unlock(&lock);
+}
+
+static void
+fc_get_host_port_state(struct Scsi_Host *shost)
+{
+	struct fcfront_info	*info = ((struct scsifront_info *)
+					 (shost->hostdata))->fcinfo;
+	struct fcif_front_ring	*ring = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+
+	mutex_lock(&lock);
+
+	ring_req       = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+	ring_req->rqid = rqid_seed++;
+	ring_req->cmnd = CMND_GET_HOST_PORT_STATE;
+	
+	ring_res = __do_request_and_wait_response(info);
+	if (ring_res->rslt == 0) {
+		fc_host_port_state(shost) = ring_res->u.ghps.port_state;
+	} else {
+		fc_host_port_state(shost) = (u32)0xffffffff;
+	}
+
+	mutex_unlock(&lock);
+}
+
+static void
+fc_get_host_active_fc4s(struct Scsi_Host *shost)
+{
+	struct fcfront_info	*info = ((struct scsifront_info *)
+					 (shost->hostdata))->fcinfo;
+	struct fcif_front_ring	*ring = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+
+	mutex_lock(&lock);
+
+	ring_req       = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+	ring_req->rqid = rqid_seed++;
+	ring_req->cmnd = CMND_GET_HOST_ACTIVE_FC4S;
+	
+	ring_res = __do_request_and_wait_response(info);
+	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)));
+	}
+
+	mutex_unlock(&lock);
+}
+
+static void
+fc_get_host_speed(struct Scsi_Host *shost)
+{
+	struct fcfront_info	*info = ((struct scsifront_info *)
+					 (shost->hostdata))->fcinfo;
+	struct fcif_front_ring	*ring = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+
+	mutex_lock(&lock);
+
+	ring_req       = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+	ring_req->rqid = rqid_seed++;
+	ring_req->cmnd = CMND_GET_HOST_SPEED;
+	
+	ring_res = __do_request_and_wait_response(info);
+	if (ring_res->rslt == 0) {
+		fc_host_speed(shost) = ring_res->u.ghsp.speed;
+	} else {
+		fc_host_speed(shost) = (u32)0xffffffff;
+	}
+
+	mutex_unlock(&lock);
+}
+
+static void
+fc_get_host_fabric_name(struct Scsi_Host *shost)
+{
+	struct fcfront_info	*info = ((struct scsifront_info *)
+					 (shost->hostdata))->fcinfo;
+	struct fcif_front_ring	*ring = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+
+	mutex_lock(&lock);
+
+	ring_req       = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+	ring_req->rqid = rqid_seed++;
+	ring_req->cmnd = CMND_GET_HOST_FABRIC_NAME;
+	
+	ring_res = __do_request_and_wait_response(info);
+	if (ring_res->rslt == 0) {
+		fc_host_fabric_name(shost) = ring_res->u.ghfn.fabric_name;
+	} else {
+		fc_host_fabric_name(shost) = (u64)0xffffffffffffffff;
+	}
+
+	mutex_unlock(&lock);
+}
+
+static struct fc_host_statistics *
+fc_get_stats(struct Scsi_Host *shost)
+{
+	struct fcfront_info		*info = ((struct scsifront_info *)
+						 (shost->hostdata))->fcinfo;
+	struct fcif_front_ring		*ring = &(info->ring);
+	struct fcif_request		*ring_req;
+	struct fcif_response		*ring_res;
+	struct fc_host_statistics	*ret;
+
+	mutex_lock(&lock);
+
+	ring_req       = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+	ring_req->rqid = rqid_seed++;
+	ring_req->cmnd = CMND_GET_HOST_STATS;
+	
+	ring_res = __do_request_and_wait_response(info);
+	if (ring_res->rslt == 0) {
+		/* "info->hs" is appropriate position ? */
+		memcpy(&(info->hs), &(ring_res->u.ghst.stats),
+		       sizeof(info->hs));
+		ret = &(ring_res->u.ghst.stats);
+	} else {
+		ret = NULL;
+	}
+
+	mutex_unlock(&lock);
+
+	return ret;
+}
+
+static void
+fc_reset_stats(struct Scsi_Host *shost)
+{
+	struct fcfront_info	*info = ((struct scsifront_info *)
+					 (shost->hostdata))->fcinfo;
+	struct fcif_front_ring	*ring = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+
+	mutex_lock(&lock);
+
+	ring_req       = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+	ring_req->rqid = rqid_seed++;
+	ring_req->cmnd = CMND_RESET_HOST_STATS;
+	
+	ring_res = __do_request_and_wait_response(info);
+
+	mutex_unlock(&lock);
+}
+
+static int
+fc_issue_lip(struct Scsi_Host *shost)
+{
+	struct fcfront_info	*info = ((struct scsifront_info *)
+					 (shost->hostdata))->fcinfo;
+	struct fcif_front_ring	*ring = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+
+	mutex_lock(&lock);
+
+	ring_req       = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+	ring_req->rqid = rqid_seed++;
+	ring_req->cmnd = CMND_ISSUE_HOST_LIP;
+	
+	ring_res = __do_request_and_wait_response(info);
+	
+	mutex_unlock(&lock);
+
+	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 fcfront_info	*info  = ((struct scsifront_info *)
+					  (shost->hostdata))->fcinfo;
+	struct fcif_front_ring	*ring  = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+
+	mutex_lock(&lock);
+
+	ring_req = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+	ring_req->rqid           = rqid_seed++;
+	ring_req->cmnd           = CMND_GET_STARGET_PORT_ID;
+	ring_req->u.gtpi.channel = starget->channel;
+	ring_req->u.gtpi.id      = starget->id;
+	
+	ring_res = __do_request_and_wait_response(info);
+	if (ring_res->rslt == 0) {
+		fc_starget_port_id(starget) = ring_res->u.gtpi.port_id;
+	} else {
+		fc_starget_port_id(starget) = (u32)0xffffffff;
+	}
+
+	mutex_unlock(&lock);
+}
+
+static void
+fc_get_starget_node_name(struct scsi_target *starget)
+{
+	struct Scsi_Host	*shost = dev_to_shost(starget->dev.parent);
+	struct fcfront_info	*info  = ((struct scsifront_info *)
+					  (shost->hostdata))->fcinfo;
+	struct fcif_front_ring	*ring  = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+
+	mutex_lock(&lock);
+
+	ring_req = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+	ring_req->rqid           = rqid_seed++;
+	ring_req->cmnd           = CMND_GET_STARGET_NODE_NAME;
+	ring_req->u.gtnn.channel = starget->channel;
+	ring_req->u.gtnn.id      = starget->id;
+	
+	ring_res = __do_request_and_wait_response(info);
+	if (ring_res->rslt == 0) {
+		fc_starget_node_name(starget) = ring_res->u.gtnn.node_name;
+	} else {
+		fc_starget_node_name(starget) = (u64)0xffffffffffffffff;
+	}
+
+	mutex_unlock(&lock);
+}
+
+static void
+fc_get_starget_port_name(struct scsi_target *starget)
+{
+	struct Scsi_Host	*shost = dev_to_shost(starget->dev.parent);
+	struct fcfront_info	*info  = ((struct scsifront_info *)
+					  (shost->hostdata))->fcinfo;
+	struct fcif_front_ring	*ring  = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+
+	mutex_lock(&lock);
+
+	ring_req = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+	ring_req->rqid           = rqid_seed++;
+	ring_req->cmnd           = CMND_GET_STARGET_PORT_NAME;
+	ring_req->u.gtpn.channel = starget->channel;
+	ring_req->u.gtpn.id      = starget->id;
+	
+	ring_res = __do_request_and_wait_response(info);
+	if (ring_res->rslt == 0) {
+		fc_starget_port_name(starget) = ring_res->u.gtpn.port_name;
+	} else {
+		fc_starget_port_name(starget) = (u64)0xffffffffffffffff;
+	}
+
+	mutex_unlock(&lock);
+}
+
+static void
+fc_get_rport_loss_tmo(struct fc_rport *rport)
+{
+	struct Scsi_Host	*shost = rport_to_shost(rport);
+	struct fcfront_info	*info  = ((struct scsifront_info *)
+					  (shost->hostdata))->fcinfo;
+	struct fcif_front_ring	*ring  = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+
+	mutex_lock(&lock);
+
+	ring_req = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+	ring_req->rqid             = rqid_seed++;
+	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 = __do_request_and_wait_response(info);
+	if (ring_res->rslt == 0) {
+		rport->dev_loss_tmo = ring_res->u.gplt.timeout;
+	} else {
+		rport->dev_loss_tmo = (u32)0xffffffff;
+	}
+
+	mutex_unlock(&lock);
+}
+
+static void
+fc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+{
+	struct Scsi_Host	*shost = rport_to_shost(rport);
+	struct fcfront_info	*info  = ((struct scsifront_info *)
+					  (shost->hostdata))->fcinfo;
+	struct fcif_front_ring	*ring  = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+
+	mutex_lock(&lock);
+
+	ring_req = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+	ring_req->rqid             = rqid_seed++;
+	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 = __do_request_and_wait_response(info);
+	if (ring_res->rslt == 0) {
+		rport->dev_loss_tmo = ring_res->u.splt.timeout;
+	} else {
+		rport->dev_loss_tmo = (u32)0xffffffff;
+	}
+
+	mutex_unlock(&lock);
+}
+
+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,
+	.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,
+
+//	.dd_fcrport_size		= sizeof(struct fc_rport_data),
+
+	/* 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,
+	.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,
+
+	/* 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 irqreturn_t
+fcfront_intr(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+	struct fcfront_info	*info = (struct fcfront_info *)dev_id;
+	struct fcif_front_ring	*ring = &(info->ring);
+	struct fcif_response	*ring_res;
+	
+	ring_res = RING_GET_RESPONSE(ring, 1);
+
+	info->cond = 1;
+	wake_up(&(info->wq));
+	
+	return IRQ_HANDLED;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+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->scsiinfo->dev->otherend_id,
+					     virt_to_mfn(addr), 0);
+	if (gntref < 0) {
+		printk(KERN_ERR
+		       "<<<%s: gnttab_grant_foreign_access() error>>>\n",
+		       __FUNCTION__);
+		return gntref;
+	}
+
+	info->addr   = addr;
+	info->gntref = gntref;
+	
+	return 0;
+}
+
+/*
+ * This function resides on opposite side of __setup_shared_ring()
+ * 		in scsiback/fcback.c
+ */
+static int
+__setup_shared_ring(struct fcfront_info *info)
+{
+	struct xenbus_device	*dev = info->scsiinfo->dev;
+	struct fcif_sring	*sring;
+	unsigned long		rngref = GRANT_INVALID_REF;
+	int			ret = 0;
+
+	if ((sring = (struct fcif_sring *)__get_free_page(GFP_KERNEL))
+	    == NULL) {
+		printk(KERN_ERR "<<<%s: __get_free_page() error>>>\n",
+		       __FUNCTION__);
+		ret = -ENOMEM;
+		goto out0;
+	}
+	
+	SHARED_RING_INIT(sring);
+
+	/*
+	 * Do following
+	 *		info->ring.sring = sring;
+	 *		...
+	 */
+	FRONT_RING_INIT(&(info->ring), sring, PAGE_SIZE);
+
+	rngref = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
+	if (rngref < 0) {
+		printk(KERN_ERR "<<<%s: xenbus_grant_ring() error>>>\n",
+			   __FUNCTION__);
+		ret = -ENOMEM;
+		goto out1;
+	}
+	info->rngref = rngref;
+
+	return 0;
+
+out1:
+	free_page((unsigned long)sring);
+
+out0:
+	return ret;
+}
+
+static void
+__unsetup_shared_ring(struct fcfront_info *info)
+{
+	if (info->rngref != GRANT_INVALID_REF) {
+		gnttab_end_foreign_access(info->rngref, 0,
+					  (unsigned long)(info->ring.sring));
+		info->rngref = GRANT_INVALID_REF;
+
+		free_page((unsigned long)(info->ring.sring));
+		info->ring.sring = NULL;
+	}
+}
+
+/*
+ * This function resides on opposite side of __setup_event_channel()
+ * 		in scsiback/fcback.c
+ */
+static int
+__setup_event_channel(struct fcfront_info *info)
+{
+	struct xenbus_device	*dev = info->scsiinfo->dev;
+	int			ret = 0;
+
+	/* for frontend driven communication */
+	/* (frontend -> backend -> frontend) */
+	{
+		int	irq = 0;
+
+		init_waitqueue_head(&(info->wq));
+	
+		irq = bind_listening_port_to_irqhandler(dev->otherend_id,
+			fcfront_intr, SA_SAMPLE_RANDOM, "fcfront", info);
+		if (irq <= 0) {
+			printk(KERN_ERR
+			       "<<<%s: bind_listening_port_to_irqhandler() error>>>\n",
+			       __FUNCTION__);
+			ret = -ENOMEM;
+			goto out;
+		}
+		info->irq = irq;
+	}
+
+out:
+	return ret;
+}
+
+static void
+__unsetup_event_channel(struct fcfront_info *info)
+{
+	if (info->irq) {
+		unbind_from_irqhandler(info->irq, info);
+		info->irq = 0;
+	}
+}
+
+/*
+ * This function resides on opposite side of __setup_xenstore()
+ * 		in scsiback/fcback.c
+ */
+static int
+__setup_xenstore(struct fcfront_info *info)
+{
+	struct xenbus_device		*dev = info->scsiinfo->dev;
+	struct xenbus_transaction	xbt;
+	int				ret = 0;
+
+again:
+	if ((ret = xenbus_transaction_start(&xbt)) != 0) {
+		printk(KERN_ERR "<<<%s: xenbus_transaction_start() error>>>\n",
+			   __FUNCTION__);
+		goto out0;
+	}
+
+	if ((ret = xenbus_printf(xbt, dev->nodename,
+				 "fc_rngref", "%lu", info->rngref)) != 0) {
+		printk(KERN_ERR "<<<%s: xenbus_printf() error>>>\n",
+		       __FUNCTION__);
+		goto out1;
+	}
+
+	if ((ret = xenbus_printf(xbt, dev->nodename,
+				 "fc_evtchn", "%u",
+				 irq_to_evtchn_port(info->irq))) != 0) {
+		printk(KERN_ERR "<<<%s: xenbus_printf() error>>>\n",
+		       __FUNCTION__);
+		goto out1;
+	}
+
+	if ((ret = xenbus_printf(xbt, dev->nodename,
+				 "fc_gntref", "%d", info->gntref)) != 0) {
+		printk(KERN_ERR "<<<%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
+			       "<<<%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 scsifront_info *scsiinfo)
+{
+	struct fcfront_info	*info;
+	int			ret;
+	
+	{
+		scsiinfo->fcinfo = kmalloc(sizeof(struct fcfront_info),
+					   GFP_KERNEL);
+		if (scsiinfo->fcinfo == NULL) {
+			ret = -ENOMEM;
+			goto out0;
+		}
+		memset(scsiinfo->fcinfo, 0, sizeof(struct fcfront_info));
+		info = (struct fcfront_info *)(scsiinfo->fcinfo);
+		info->scsiinfo = scsiinfo;
+	}
+
+	/* prepare for grant table */
+	if ((ret = __setup_grant_table(info)) != 0) {
+		printk(KERN_ERR "<<<%s: __setup_grant_table() error>>>\n",
+		       __FUNCTION__);
+		goto out1;
+	}
+	
+	/* prepare for shared ring */
+	if ((ret = __setup_shared_ring(info)) != 0) {
+		printk(KERN_ERR "<<<%s: __setup_shared_ring() error>>>\n",
+		       __FUNCTION__);
+		goto out1;
+	}
+
+	/* prepare for event channel */
+	if ((ret = __setup_event_channel(info)) != 0) {
+		printk(KERN_ERR "<<<%s: __setup_event_channel() error>>>\n",
+		       __FUNCTION__);
+		goto out2;
+	}
+
+	/* exchange various parameters through xenstore */
+	if ((ret = __setup_xenstore(info)) != 0) {
+		printk(KERN_ERR "<<<%s: __setup_xenstore() error>>>\n",
+		       __FUNCTION__);
+		goto out3;
+	}
+
+	mutex_init(&lock);
+	
+	return 0;
+
+out3:
+	__unsetup_event_channel(info);
+	
+out2:
+	__unsetup_shared_ring(info);
+	
+out1:
+	kfree(scsiinfo->fcinfo);
+	
+out0:
+	return ret;
+}
+
+void
+fcfront_connection_unsetup(struct scsifront_info *scsiinfo)
+{
+	struct fcfront_info	*info = (struct fcfront_info *)
+						(scsiinfo->fcinfo);
+
+	__unsetup_xenstore(info);
+	__unsetup_event_channel(info);
+	__unsetup_shared_ring(info);
+
+	kfree(scsiinfo->fcinfo);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+int
+fcfront_get_initial_attribute(struct scsifront_info *scsiinfo)
+{
+	struct fcfront_info	*info = (struct fcfront_info *)
+						(scsiinfo->fcinfo);
+	struct fcif_front_ring	*ring = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+	int			ret = 0;
+
+	/* get SCSI host attributes */
+	{
+		struct fc_host_attrs	*host_attrs = (struct fc_host_attrs *)
+						(scsiinfo->host->shost_data);
+		struct giha		*giha = (struct giha *)(info->addr);
+		  
+		mutex_lock(&lock);
+
+		ring_req = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+		ring_req->rqid = rqid_seed++;
+		ring_req->cmnd = CMND_GET_INITIAL_SHOST_ATTRIB;
+	
+		ring_res = __do_request_and_wait_response(info);
+
+		if (ring_res->rslt == 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;
+			/* "info->hs" is appropriate position ? */
+			memcpy(&(info->hs), &(giha->stats), sizeof(info->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;
+		}
+
+		mutex_unlock(&lock);
+	}
+	
+	/* get SCSI target attributes */
+	{
+		struct scsi_target	*starget;
+		struct fc_starget_attrs	*starget_attrs;
+		struct gita		*gita = (struct gita *)(info->addr);
+		unsigned int		i;
+
+		mutex_lock(&lock);
+
+		ring_req = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+		ring_req->rqid = rqid_seed++;
+		ring_req->cmnd = CMND_GET_INITIAL_STARGET_ATTRIB;
+	
+		ring_res = __do_request_and_wait_response(info);
+
+		if (ring_res->rslt == 0) {
+			for (i = 0; i < gita->num; i++) {
+				list_for_each_entry(starget,
+						&(scsiinfo->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 "<<<%s: SCSI target not added>>>\n",
+						       __FUNCTION__);
+					}
+				}
+			}
+		}
+
+		mutex_unlock(&lock);
+	}
+
+	/* get remote port attibutes */
+	{
+		int				channel;
+		struct fc_rport_identifiers	ids;
+		struct fc_rport			*rport;
+		struct gipa			*gipa = (struct gipa *)
+								(info->addr);
+		unsigned int			i;
+
+		mutex_lock(&lock);
+
+		ring_req = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+		ring_req->rqid = rqid_seed++;
+		ring_req->cmnd = CMND_GET_INITIAL_RPORT_ATTRIB;
+	
+		ring_res = __do_request_and_wait_response(info);
+
+		if (ring_res->rslt == 0) {
+			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(scsiinfo->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;
+			}
+		}
+
+		mutex_unlock(&lock);
+	}
+
+	return ret;
+}
+
+#define CORRECT_FT(s, f, v, d)	\
+	if (((s)->f) == (v)) {	\
+		(d)->f = (v);	\
+	}
+
+int
+fcfront_get_function_template(struct scsifront_info *scsiinfo)
+{
+	struct fcfront_info	*info = (struct fcfront_info *)
+											(scsiinfo->fcinfo);
+	struct fcif_front_ring	*ring = &(info->ring);
+	struct fcif_request	*ring_req;
+	struct fcif_response	*ring_res;
+	struct gftp		*gftp = (struct gftp *)(info->addr);
+
+	struct fc_function_template	*origft = fc_shost2ft(scsiinfo->host);
+	struct fc_function_template	*pvfcft = &pvfc_transport_functions;
+	
+	memcpy(pvfcft, origft, sizeof(*pvfcft));
+
+	mutex_lock(&lock);
+
+	ring_req       = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+	ring_req->rqid = rqid_seed++;
+	ring_req->cmnd = CMND_GET_FUNCTION_TEMPLATE;
+	
+	ring_res = __do_request_and_wait_response(info);
+
+	if (ring_res->rslt == 0) {
+		struct fc_function_template	*ft = &(gftp->ft);
+
+		CORRECT_FT(ft, get_rport_dev_loss_tmo,        NULL, pvfcft);
+		CORRECT_FT(ft, set_rport_dev_loss_tmo,        NULL, pvfcft);
+		CORRECT_FT(ft, get_starget_node_name,         NULL, pvfcft);
+		CORRECT_FT(ft, get_starget_port_name,         NULL, pvfcft);
+		CORRECT_FT(ft, get_starget_port_id,           NULL, pvfcft);
+		CORRECT_FT(ft, get_host_port_id,              NULL, pvfcft);
+		CORRECT_FT(ft, get_host_port_type,            NULL, pvfcft);
+		CORRECT_FT(ft, get_host_port_state,           NULL, pvfcft);
+		CORRECT_FT(ft, get_host_active_fc4s,          NULL, pvfcft);
+		CORRECT_FT(ft, get_host_speed,                NULL, pvfcft);
+		CORRECT_FT(ft, get_host_fabric_name,          NULL, pvfcft);
+		CORRECT_FT(ft, get_fc_host_stats,             NULL, pvfcft);
+		CORRECT_FT(ft, reset_fc_host_stats,           NULL, pvfcft);
+		CORRECT_FT(ft, issue_fc_host_lip,             NULL, pvfcft);
+
+		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);
+	}
+
+	/* replace registered "ft" by new "pvfcft". Is this allowed ? */
+	fc_update_ft(scsiinfo->host, pvfcft);
+	
+	mutex_unlock(&lock);
+
+	return 0;
+}
+
+MODULE_DESCRIPTION("Xen Para-Virtual SCSI Fibre Channel Frontend Driver");
+MODULE_LICENSE("GPL");
diff -r 0f169b36be81 -r 99d47e3f5430 drivers/xen/scsifront/scsifront.c
--- a/drivers/xen/scsifront/scsifront.c	Fri Jun 29 18:09:19 2007 +0900
+++ b/drivers/xen/scsifront/scsifront.c	Fri Jun 29 19:48:58 2007 +0900
@@ -51,6 +51,10 @@
 #include <xen/platform-compat.h>
 #endif
 
+#ifdef CONFIG_XEN_SCSI_FC
+#include <scsi/scsi_transport_fc.h>
+#endif
+
 #define GRANT_INVALID_REF 0
 
 
@@ -58,6 +62,11 @@
 	pr_debug("(file=%s, line=%d) " _f,	\
 		 __FILE__ , __LINE__ , ## _a )
 
+#ifdef CONFIG_XEN_SCSI_FC
+extern int	fcfront_connection_setup(struct scsifront_info *);
+extern int	fcfront_get_initial_attribute(struct scsifront_info *);
+extern int	fcfront_get_function_template(struct scsifront_info *);
+#endif
 
 struct scsi_shadow {
 	struct scsiif_request ring_req;
@@ -75,8 +84,15 @@ struct scsifront_info {
 	struct scsiif_front_ring ring;
 	struct scsi_shadow shadow[SCSI_RING_SIZE];
 	unsigned long shadow_free;
+#ifdef CONFIG_XEN_SCSI_FC
+	void	*fcinfo;
+#endif
 };
 
+#ifdef CONFIG_XEN_SCSI_FC
+extern struct fc_function_template	fc_transport_functions;
+static struct scsi_transport_template	*fc_transport_template = NULL;
+#endif
 
 static inline int GET_ID_FROM_FREELIST(
 	struct scsifront_info *info)
@@ -417,6 +433,11 @@ static int scsifront_connect(struct scsi
 
 	scsi_scan_host(host);
 
+#ifdef CONFIG_XEN_SCSI_FC
+	(void)fcfront_get_initial_attribute(info);
+	(void)fcfront_get_function_template(info);
+#endif
+
 	return 0;
 }
 
@@ -441,6 +462,20 @@ static int scsifront_probe(struct xenbus
 		info->shadow[i].ring_req.rqid = i + 1;
 	info->shadow[SCSI_RING_SIZE - 1].ring_req.rqid = 0x0fffffff;
 
+#ifdef CONFIG_XEN_SCSI_FC
+	host->transportt = fc_transport_template;
+	{
+		int	ret;
+
+		if ((ret = fcfront_connection_setup(info)) != 0) {
+			printk(KERN_ERR
+			       "<<<%s: fcfront_connection_setup() error>>>\n",
+			       __FUNCTION__);
+			return ret;
+		}
+	}
+#endif
+
 	err = scsifront_init_ring(info);
 	if (err) {
 		scsi_host_put(host);
@@ -455,6 +490,10 @@ static int scsifront_remove(struct xenbu
 {
 	struct scsifront_info *info = dev->dev.driver_data;
 
+#ifdef CONFIG_XEN_SCSI_FC
+	fcfront_connection_unsetup(info);
+#endif
+	
 	scsifront_free(info);
 	
 	return 0;
@@ -507,6 +546,20 @@ static int __init scsifront_init(void)
 	if (!is_running_on_xen())
 		return -ENODEV;
 
+#ifdef CONFIG_XEN_SCSI_FC
+	if (is_initial_xendomain()) {
+		printk(KERN_ERR "<<<%s: Not on a DomU>>>\n", __FUNCTION__);
+		return 0;
+	}
+
+	fc_transport_template = fc_attach_transport(&fc_transport_functions);
+	if (fc_transport_template == NULL) {
+		printk(KERN_ERR "<<<%s: fc_attach_transport() error>>>\n",
+		       __FUNCTION__);
+		return -ENOMEM;
+	}
+#endif
+
 	err = xenbus_register_frontend(&scsifront_driver);
 
 	return err;
@@ -515,6 +568,10 @@ static void scsifront_exit(void)
 static void scsifront_exit(void)
 {
 	xenbus_unregister_driver(&scsifront_driver);
+
+#ifdef CONFIG_XEN_SCSI_FC
+	fc_release_transport(fc_transport_template);
+#endif
 }
 
 module_init(scsifront_init);

[-- 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:08 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 ` [RFC] [3/4] PV driver for FC transport layer (pv-scsi frontend driver) Jun Kamada
2007-06-29 11:08 ` Jun Kamada [this message]
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=20070629200737.69F2.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.