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
next prev 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.