# 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;
+}
