* [RFC] [0/4] PV driver for FC transport layer
@ 2007-06-29 11:04 Jun Kamada
2007-06-29 11:06 ` [RFC] [1/4] PV driver for FC transport layer (config files for pv-scsi) Jun Kamada
` (4 more replies)
0 siblings, 5 replies; 12+ messages in thread
From: Jun Kamada @ 2007-06-29 11:04 UTC (permalink / raw)
To: xen-devel; +Cc: kama
Hi all,
We developed a prototype of para-virtual FC(Fibre Channel) SCSI driver.
It's a extension of the "pv-scsi" driver, that Horikoshi-san posted on
16 May 2007 ([Xen-devel] [RFC] pv-scsi driver (scsiback/scsifront)),
in order to support FC transport layer.
The FC extension mainly performs following processes.
1. Copies FC attributes stored in Dom0 to DomU at the driver
initialization phase. The attributes are originally stored in
"Scsi_Host", "scsi_target" and "fc_rport" structures.
2. When /sys/class/fc_*/*/* on DomU is accessed from user land, performs
appropriate function on Dom0.
We expect your helpful comments especially at following point of view.
- What any other functions are required in order to behave as "complete"
FC driver? (We are not familiar with FC driver.)
- This is the sub-question of above. Current prototype supports only
"frontend driven" functions. What types of "backend driven" functions
we have to support?
Any other comments are welcomed.
Best regards
-----
Jun Kamada
Linux Technology Development Div.
Server Systems Unit
Fujitsu Ltd.
kama@jp.fujitsu.com
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC] [1/4] PV driver for FC transport layer (config files for pv-scsi)
2007-06-29 11:04 [RFC] [0/4] PV driver for FC transport layer Jun Kamada
@ 2007-06-29 11:06 ` Jun Kamada
2007-06-29 11:06 ` [RFC] [2/4] PV driver for FC transport layer (pv-scsi backend driver) Jun Kamada
` (3 subsequent siblings)
4 siblings, 0 replies; 12+ messages in thread
From: Jun Kamada @ 2007-06-29 11:06 UTC (permalink / raw)
Cc: kama, xen-devel
[-- 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: scsiconfig.patch --]
[-- Type: application/octet-stream, Size: 4733 bytes --]
# HG changeset patch
# User Jun Kamada <kama@jp.fujitsu.com>
# Date 1183107229 -32400
# Node ID 52f99cf7240f84e89740242828a3c09566139054
# Parent 3df04f34c4aa7679bf30a7fe6b46d8ccc0a004da
modiy config
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 3df04f34c4aa -r 52f99cf7240f buildconfigs/linux-defconfig_xen_ia64
--- a/buildconfigs/linux-defconfig_xen_ia64 Mon Jun 18 13:59:27 2007 -0600
+++ b/buildconfigs/linux-defconfig_xen_ia64 Fri Jun 29 17:53:49 2007 +0900
@@ -511,8 +511,8 @@ CONFIG_SCSI_SYM53C8XX_MMIO=y
CONFIG_SCSI_SYM53C8XX_MMIO=y
# CONFIG_SCSI_IPR is not set
CONFIG_SCSI_QLOGIC_1280=y
-# CONFIG_SCSI_QLA_FC is not set
-# CONFIG_SCSI_LPFC is not set
+CONFIG_SCSI_QLA_FC=y
+CONFIG_SCSI_LPFC=y
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
@@ -1659,6 +1659,7 @@ CONFIG_XEN_XENBUS_DEV=y
CONFIG_XEN_XENBUS_DEV=y
CONFIG_XEN_BACKEND=y
CONFIG_XEN_BLKDEV_BACKEND=y
+CONFIG_XEN_SCSI_BACKEND=y
CONFIG_XEN_BLKDEV_TAP=y
CONFIG_XEN_NETDEV_BACKEND=y
# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
@@ -1671,6 +1672,7 @@ CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER=y
# CONFIG_XEN_PCIDEV_BE_DEBUG is not set
CONFIG_XEN_TPMDEV_BACKEND=m
CONFIG_XEN_BLKDEV_FRONTEND=y
+CONFIG_XEN_SCSI_FRONTEND=m
CONFIG_XEN_NETDEV_FRONTEND=y
CONFIG_XEN_FRAMEBUFFER=y
CONFIG_XEN_KEYBOARD=y
diff -r 3df04f34c4aa -r 52f99cf7240f buildconfigs/linux-defconfig_xen_x86_32
--- a/buildconfigs/linux-defconfig_xen_x86_32 Mon Jun 18 13:59:27 2007 -0600
+++ b/buildconfigs/linux-defconfig_xen_x86_32 Fri Jun 29 17:53:49 2007 +0900
@@ -1083,13 +1083,13 @@ CONFIG_IDEDMA_AUTO=y
# SCSI device support
#
CONFIG_RAID_ATTRS=m
-CONFIG_SCSI=m
+CONFIG_SCSI=y
CONFIG_SCSI_PROC_FS=y
#
# SCSI support type (disk, tape, CD-ROM)
#
-CONFIG_BLK_DEV_SD=m
+CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=m
CONFIG_CHR_DEV_OSST=m
CONFIG_BLK_DEV_SR=m
@@ -1184,8 +1184,8 @@ CONFIG_SCSI_IPR_TRACE=y
CONFIG_SCSI_IPR_TRACE=y
CONFIG_SCSI_IPR_DUMP=y
CONFIG_SCSI_QLOGIC_1280=m
-CONFIG_SCSI_QLA_FC=m
-CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_QLA_FC=y
+CONFIG_SCSI_LPFC=y
CONFIG_SCSI_DC395x=m
CONFIG_SCSI_DC390T=m
CONFIG_SCSI_NSP32=m
@@ -3253,6 +3253,7 @@ CONFIG_XEN_XENBUS_DEV=y
CONFIG_XEN_XENBUS_DEV=y
CONFIG_XEN_BACKEND=y
CONFIG_XEN_BLKDEV_BACKEND=y
+CONFIG_XEN_SCSI_BACKEND=y
CONFIG_XEN_BLKDEV_TAP=y
CONFIG_XEN_NETDEV_BACKEND=y
# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
@@ -3264,6 +3265,7 @@ CONFIG_XEN_PCIDEV_BACKEND_VPCI=y
# CONFIG_XEN_PCIDEV_BE_DEBUG is not set
CONFIG_XEN_TPMDEV_BACKEND=m
CONFIG_XEN_BLKDEV_FRONTEND=y
+CONFIG_XEN_SCSI_FRONTEND=m
CONFIG_XEN_NETDEV_FRONTEND=y
CONFIG_XEN_FRAMEBUFFER=y
CONFIG_XEN_KEYBOARD=y
diff -r 3df04f34c4aa -r 52f99cf7240f drivers/xen/Kconfig
--- a/drivers/xen/Kconfig Mon Jun 18 13:59:27 2007 -0600
+++ b/drivers/xen/Kconfig Fri Jun 29 17:53:49 2007 +0900
@@ -53,6 +53,14 @@ config XEN_BLKDEV_BACKEND
The block-device backend driver allows the kernel to export its
block devices to other guests via a high-performance shared-memory
interface.
+
+config XEN_SCSI_BACKEND
+ tristate "SCSI backend driver"
+ depends on XEN_BACKEND
+ default y
+ help
+ The SCSI backend driver allows the kernel to export its SCSI HBAs
+ to other guests via a high-performance shared-memory interface.
config XEN_BLKDEV_TAP
tristate "Block-device tap backend driver"
@@ -178,6 +186,14 @@ config XEN_BLKDEV_FRONTEND
dedicated device-driver domain, or your master control domain
(domain 0), then you almost certainly want to say Y here.
+config XEN_SCSI_FRONTEND
+ tristate "SCSI frontend driver"
+ depends on XEN && SCSI
+ default y
+ help
+ The SCSI frontend driver allows the kernel to access SCSI HBAs
+ within another guest OS.
+
config XEN_NETDEV_FRONTEND
tristate "Network-device frontend driver"
depends on XEN && NET
diff -r 3df04f34c4aa -r 52f99cf7240f drivers/xen/Makefile
--- a/drivers/xen/Makefile Mon Jun 18 13:59:27 2007 -0600
+++ b/drivers/xen/Makefile Fri Jun 29 17:53:49 2007 +0900
@@ -9,10 +9,12 @@ obj-y += char/
obj-y += util.o
obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/
+obj-$(CONFIG_XEN_SCSI_BACKEND) += scsiback/
obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/
obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/
obj-$(CONFIG_XEN_TPMDEV_BACKEND) += tpmback/
obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blkfront/
+obj-$(CONFIG_XEN_SCSI_FRONTEND) += scsifront/
obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/
obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/
obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC] [2/4] PV driver for FC transport layer (pv-scsi backend driver)
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 ` Jun Kamada
2007-06-29 11:07 ` [RFC] [3/4] PV driver for FC transport layer (pv-scsi frontend driver) Jun Kamada
` (2 subsequent siblings)
4 siblings, 0 replies; 12+ messages in thread
From: Jun Kamada @ 2007-06-29 11:06 UTC (permalink / raw)
Cc: kama, xen-devel
[-- 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: scsiback.patch --]
[-- Type: application/octet-stream, Size: 27765 bytes --]
# HG changeset patch
# User Jun Kamada <kama@jp.fujitsu.com>
# Date 1183108100 -32400
# Node ID 06db0e13731c650c5b2ddf6d8048f9c89d89a012
# Parent 52f99cf7240f84e89740242828a3c09566139054
add scsiback 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 52f99cf7240f -r 06db0e13731c drivers/xen/scsiback/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/Makefile Fri Jun 29 18:08:20 2007 +0900
@@ -0,0 +1,2 @@
+obj-$(CONFIG_XEN_SCSI_BACKEND) += scsibk.o
+scsibk-y += interface.o scsiback.o
diff -r 52f99cf7240f -r 06db0e13731c drivers/xen/scsiback/common.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/common.h Fri Jun 29 18:08:20 2007 +0900
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2007, FUJITSU Limited
+ *
+ * Based on the blkback driver code.
+ *
+ * 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 __SCSIIF__BACKEND__COMMON_H__
+#define __SCSIIF__BACKEND__COMMON_H__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/pgalloc.h>
+#include <xen/evtchn.h>
+#include <asm/hypervisor.h>
+#include <xen/gnttab.h>
+#include <xen/driver_util.h>
+#include <xen/xenbus.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/scsiif.h>
+
+#define DPRINTK(_f, _a...) \
+ pr_debug("(file=%s, line=%d) " _f, \
+ __FILE__ , __LINE__ , ## _a )
+
+struct scsiback_info {
+ struct xenbus_device *dev;
+ struct Scsi_Host *host;
+ struct xenbus_watch backend_watch;
+
+ unsigned int evtchn;
+ unsigned int irq;
+
+ unsigned short host_no;
+
+ scsiif_back_ring_t ring;
+ struct vm_struct *ring_area;
+
+ grant_handle_t shmem_handle;
+ grant_ref_t shmem_ref;
+
+ struct work_struct scsiback_work;
+
+ spinlock_t ring_lock;
+ atomic_t refcnt;
+
+ struct task_struct *kthread;
+ wait_queue_head_t waiting_to_free;
+ wait_queue_head_t wq;
+ unsigned int waiting_reqs;
+
+ struct page **mmap_pages;
+};
+
+irqreturn_t scsiback_intr(int, void *, struct pt_regs *);
+int scsiback_init_sring(struct scsiback_info *,
+ unsigned long, unsigned int);
+int scsiback_schedule(void *data);
+
+
+#define scsiback_get(_b) (atomic_inc(&(_b)->refcnt))
+#define scsiback_put(_b) \
+ do { \
+ if (atomic_dec_and_test(&(_b)->refcnt)) \
+ wake_up(&(_b)->waiting_to_free);\
+ } while (0)
+
+struct scsiback_info *scsiinfo_alloc(domid_t domid);
+void scsiback_free(struct scsiback_info *info);
+void scsiback_disconnect(struct scsiback_info *info);
+void __init scsiback_interface_init(void);
+
+#endif /* __SCSIIF__BACKEND__COMMON_H__ */
diff -r 52f99cf7240f -r 06db0e13731c drivers/xen/scsiback/interface.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/interface.c Fri Jun 29 18:08:20 2007 +0900
@@ -0,0 +1,165 @@
+/*
+ * interface management.
+ *
+ * Copyright (c) 2007, FUJITSU Limited
+ *
+ * Based on the blkback driver code.
+ *
+ * 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 "common.h"
+#include <xen/evtchn.h>
+#include <linux/kthread.h>
+
+static kmem_cache_t *scsiback_cachep;
+
+struct scsiback_info *scsiinfo_alloc(domid_t domid)
+{
+ struct scsiback_info *info;
+
+ info = kmem_cache_alloc(scsiback_cachep, GFP_KERNEL);
+ if (!info)
+ return ERR_PTR(-ENOMEM);
+
+ memset(info, 0, sizeof(*info));
+ spin_lock_init(&info->ring_lock);
+ atomic_set(&info->refcnt, 1);
+ init_waitqueue_head(&info->wq);
+ init_waitqueue_head(&info->waiting_to_free);
+
+ return info;
+}
+
+static int map_frontend_page(
+ struct scsiback_info *info, unsigned long shared_page)
+{
+ struct gnttab_map_grant_ref op;
+ int err;
+
+ gnttab_set_map_op(&op, (unsigned long)info->ring_area->addr,
+ GNTMAP_host_map, shared_page,
+ info->dev->otherend_id);
+
+ err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
+ BUG_ON(err);
+
+ if (op.status) {
+ printk(" Grant table operation failure !\n");
+ return op.status;
+ }
+
+ info->shmem_ref = shared_page;
+ info->shmem_handle = op.handle;
+
+ return 0;
+}
+
+static void unmap_frontend_page(struct scsiback_info *info)
+{
+ struct gnttab_unmap_grant_ref op;
+ int err;
+
+ gnttab_set_unmap_op(&op, (unsigned long)info->ring_area->addr,
+ GNTMAP_host_map, info->shmem_handle);
+
+ err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
+ BUG_ON(err);
+}
+
+int scsiback_init_sring(struct scsiback_info *info,
+ unsigned long shared_page, unsigned int evtchn)
+{
+ struct scsiif_sring *sring;
+ int err;
+
+ if (info->irq) {
+ printk("Already connected through?\n");
+ return 0;
+ }
+
+ info->ring_area = alloc_vm_area(PAGE_SIZE);
+ if (!info)
+ return -ENOMEM;
+
+ err = map_frontend_page(info, shared_page);
+ if (err)
+ goto free_vm;
+
+ sring = (struct scsiif_sring *) info->ring_area->addr;
+ BACK_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+ err = bind_interdomain_evtchn_to_irqhandler(
+ info->dev->otherend_id, evtchn,
+ scsiback_intr, 0, "scsiif-backend", info);
+
+ if (err < 0)
+ goto unmap_page;
+
+ info->irq = err;
+ return 0;
+
+unmap_page:
+ unmap_frontend_page(info);
+free_vm:
+ free_vm_area(info->ring_area);
+ return err;
+}
+
+void scsiback_disconnect(struct scsiback_info *info)
+{
+ if (info->kthread) {
+ kthread_stop(info->kthread);
+ info->kthread = NULL;
+ }
+
+ atomic_dec(&info->refcnt);
+ wait_event(info->waiting_to_free, atomic_read(&info->refcnt) == 0);
+ atomic_inc(&info->refcnt);
+
+ if (info->irq) {
+ unbind_from_irqhandler(info->irq, info);
+ info->irq = 0;
+ }
+
+ if (info->ring.sring) {
+ unmap_frontend_page(info);
+ free_vm_area(info->ring_area);
+ info->ring.sring = NULL;
+ }
+}
+
+void scsiback_free(struct scsiback_info *info)
+{
+ if (!atomic_dec_and_test(&info->refcnt))
+ BUG();
+ kmem_cache_free(scsiback_cachep, info);
+}
+
+void __init scsiback_interface_init(void)
+{
+ scsiback_cachep = kmem_cache_create("scsiif_cache",
+ sizeof(struct scsiback_info), 0, 0, NULL, NULL);
+}
diff -r 52f99cf7240f -r 06db0e13731c drivers/xen/scsiback/scsiback.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/scsiback.c Fri Jun 29 18:08:20 2007 +0900
@@ -0,0 +1,716 @@
+/*
+ * Xen SCSI backend driver
+ *
+ * Copyright (c) 2007, FUJITSU Limited
+ *
+ * Based on the blkback driver code.
+ *
+ * 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/list.h>
+#include <linux/blkdev.h>
+#include <linux/kthread.h>
+#include <xen/balloon.h>
+#include <asm/hypervisor.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_dbg.h>
+#include "common.h"
+
+
+#define INVALID_GRANT_HANDLE 0xFFFF
+
+typedef struct {
+ struct scsiback_info *info;
+ unsigned long rqid;
+ int use_sg;
+ atomic_t pendcnt;
+ struct request *rq;
+ struct list_head free_list;
+} pending_req_t;
+
+static pending_req_t *pending_reqs;
+static struct list_head pending_free;
+static DEFINE_SPINLOCK(pending_free_lock);
+static DECLARE_WAIT_QUEUE_HEAD(pending_free_wq);
+
+#define SCSIBACK_INVALID_HANDLE (~0)
+
+static struct page **pending_pages;
+static grant_handle_t *pending_grant_handles;
+
+
+static inline int vaddr_pagenr(pending_req_t *req, int seg)
+{
+ return (req - pending_reqs) * SG_TABLESIZE + seg;
+}
+
+static inline unsigned long vaddr(pending_req_t *req, int seg)
+{
+ unsigned long pfn = page_to_pfn(pending_pages[vaddr_pagenr(req, seg)]);
+ return (unsigned long)pfn_to_kaddr(pfn);
+}
+
+#define pending_handle(_req, _seg) \
+ (pending_grant_handles[vaddr_pagenr(_req, _seg)])
+
+
+
+/******************************************************************
+ * misc small helpers
+ */
+static pending_req_t* alloc_req(void)
+{
+ pending_req_t *req = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pending_free_lock, flags);
+ if (!list_empty(&pending_free)) {
+ req = list_entry(pending_free.next, pending_req_t, free_list);
+ list_del(&req->free_list);
+ }
+ spin_unlock_irqrestore(&pending_free_lock, flags);
+ return req;
+}
+
+static void free_req(pending_req_t *req)
+{
+ unsigned long flags;
+ int was_empty;
+
+ spin_lock_irqsave(&pending_free_lock, flags);
+ was_empty = list_empty(&pending_free);
+ list_add(&req->free_list, &pending_free);
+ spin_unlock_irqrestore(&pending_free_lock, flags);
+ if (was_empty)
+ wake_up(&pending_free_wq);
+}
+
+
+static void fast_flush_area(pending_req_t *req)
+{
+ struct gnttab_unmap_grant_ref unmap[SG_TABLESIZE];
+ unsigned int i, invcount = 0;
+ grant_handle_t handle;
+ int err;
+
+ for (i = 0; i < req->use_sg; i++) {
+ handle = pending_handle(req, i);
+ if (handle == SCSIBACK_INVALID_HANDLE)
+ continue;
+ gnttab_set_unmap_op(&unmap[i], vaddr(req, i),
+ GNTMAP_host_map, handle);
+ pending_handle(req, i) = SCSIBACK_INVALID_HANDLE;
+ invcount++;
+ }
+
+ err = HYPERVISOR_grant_table_op(
+ GNTTABOP_unmap_grant_ref, unmap, invcount);
+ BUG_ON(err);
+}
+
+
+/******************************************************************************
+ * NOTIFICATION FROM GUEST OS.
+ */
+static void scsiback_notify_work(struct scsiback_info *info)
+{
+ info->waiting_reqs = 1;
+ wake_up(&info->wq);
+}
+
+irqreturn_t scsiback_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ scsiback_notify_work(dev_id);
+ return IRQ_HANDLED;
+}
+
+static void make_sense(struct scsiback_info *info, struct request *req,
+ int32_t result, uint64_t rqid)
+{
+ struct scsiif_response *resp;
+ unsigned long flags;
+ struct scsiif_back_ring *ring = &info->ring;
+ int more_to_do = 0;
+ int notify;
+
+ spin_lock_irqsave(&info->ring_lock, flags);
+
+ resp = RING_GET_RESPONSE(ring, ring->rsp_prod_pvt);
+ memset(resp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+
+ resp->result = result;
+ resp->rqid = rqid;
+
+ if (req) {
+ memcpy(resp->sense_buffer, req->sense, req->sense_len);
+ resp->sense_len = req->sense_len;
+ } else
+ resp->sense_len = 0;
+
+ ring->rsp_prod_pvt++;
+
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(ring, notify);
+
+ if (ring->rsp_prod_pvt == ring->req_cons) {
+ RING_FINAL_CHECK_FOR_REQUESTS(ring, more_to_do);
+
+ } else if (RING_HAS_UNCONSUMED_REQUESTS(ring)) {
+ more_to_do = 1;
+ }
+
+ spin_unlock_irqrestore(&info->ring_lock, flags);
+
+ if (more_to_do)
+ scsiback_notify_work(info);
+ if (notify)
+ notify_remote_via_irq(info->irq);
+}
+
+
+static void scsiback_end_cmd_fn(struct request *req, int error)
+{
+ unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
+ pending_req_t *pending_req = req->end_io_data;
+ pending_req->rq = req;
+
+ if (req->errors != 0) {
+ printk("Buffer not up-to-date at end of operation, "
+ "req->errors=0x%08x\n", req->errors);
+ memcpy(sense_buffer, req->sense, req->sense_len);
+ __scsi_print_sense("scsiback_end_cmd_fn", sense_buffer,
+ req->sense_len);
+ }
+
+ if (atomic_dec_and_test(&pending_req->pendcnt)) {
+ fast_flush_area(pending_req);
+ make_sense(pending_req->info, pending_req->rq,
+ req->errors, pending_req->rqid);
+ scsiback_put(pending_req->info);
+ free_req(pending_req);
+ }
+
+ __blk_put_request(req->q, req);
+}
+
+
+/* quoted scsi_lib.c/scsi_merge_bio */
+static int scsiback_merge_bio(struct request *rq, struct bio *bio)
+{
+ struct request_queue *q = rq->q;
+
+ bio->bi_flags &= ~(1 << BIO_SEG_VALID);
+ if (rq_data_dir(rq) == WRITE)
+ bio->bi_rw |= (1 << BIO_RW);
+
+ blk_queue_bounce(q, &bio);
+
+ if (!rq->bio)
+ blk_rq_bio_prep(q, rq, bio);
+ else if (!q->back_merge_fn(q, rq, bio))
+ return -EINVAL;
+ else {
+ rq->biotail->bi_next = bio;
+ rq->biotail = bio;
+ rq->hard_nr_sectors += bio_sectors(bio);
+ rq->nr_sectors = rq->hard_nr_sectors;
+ }
+
+ return 0;
+}
+
+
+/* quoted scsi_lib.c/scsi_bi_endio */
+static int scsiback_bi_endio(struct bio *bio, unsigned int bytes_done, int error)
+{
+ if (bio->bi_size)
+ return 1;
+
+ bio_put(bio);
+ return 0;
+}
+
+
+/* quoted scsi_lib.c/scsi_req_map_sg . */
+static int requset_map_sg(struct scsiif_request *ring_req,
+ pending_req_t *pending_req)
+{
+ struct request *rq = pending_req->rq;
+ struct request_queue *q = pending_req->rq->q;
+ int nr_pages;
+ int nsegs = pending_req->use_sg;
+ unsigned int data_len = 0, len, bytes, off;
+ struct page *page;
+ struct bio *bio = NULL;
+ int i, err, nr_vecs = 0;
+
+ for (i = 0; i < nsegs; i++) {
+ page = virt_to_page(vaddr(pending_req, i));
+ off = ring_req->seg[i].offset;
+ len = ring_req->seg[i].length;
+ data_len += len;
+
+ nr_pages = (len + off + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ while (len > 0) {
+ bytes = min_t(unsigned int, len, PAGE_SIZE - off);
+
+ if (!bio) {
+ nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages);
+ nr_pages -= nr_vecs;
+ bio = bio_alloc(GFP_KERNEL, nr_vecs);
+ if (!bio) {
+ err = -ENOMEM;
+ goto free_bios;
+ }
+ bio->bi_end_io = scsiback_bi_endio;
+ }
+
+ if (bio_add_pc_page(q, bio, page, bytes, off) !=
+ bytes) {
+ bio_put(bio);
+ err = -EINVAL;
+ goto free_bios;
+ }
+
+ if (bio->bi_vcnt >= nr_vecs) {
+ err = scsiback_merge_bio(rq, bio);
+ if (err) {
+ bio_endio(bio, bio->bi_size, 0);
+ goto free_bios;
+ }
+ bio = NULL;
+ }
+
+ page++;
+ len -= bytes;
+ off = 0;
+ }
+ }
+
+ rq->buffer = rq->data = NULL;
+ rq->data_len = data_len;
+ return 0;
+
+free_bios:
+ while ((bio = rq->bio) != NULL) {
+ rq->bio = bio->bi_next;
+ /*
+ * call endio instead of bio_put incase it was bounced
+ */
+ bio_endio(bio, bio->bi_size, 0);
+ }
+ return err;
+}
+
+
+static void scsiback_cmd_exec(struct scsiback_info *info,
+ struct scsiif_request *ring_req, pending_req_t *pending_req)
+{
+
+ struct gnttab_map_grant_ref map[SG_TABLESIZE];
+ struct scsi_device *sdev;
+ char sense[SCSI_SENSE_BUFFERSIZE];
+
+ int i, err = 0;
+ int write = (ring_req->sc_data_direction == DMA_TO_DEVICE);
+ u32 flags, use_sg;
+
+ use_sg = ring_req->use_sg;
+ sdev = scsi_device_lookup(info->host, ring_req->channel,
+ ring_req->id, ring_req->lun);
+
+ if (sdev == NULL) {
+ printk("Scsi Device Not Found\n");
+ goto fail_response;
+ }
+
+ pending_req->rq = blk_get_request(sdev->request_queue,
+ write, GFP_KERNEL);
+ pending_req->info = info;
+ pending_req->rqid = ring_req->rqid;
+ pending_req->use_sg = use_sg;
+
+
+ pending_req->rq->flags |= REQ_BLOCK_PC;
+ pending_req->rq->cmd_len = ring_req->cmd_len;
+ memcpy(pending_req->rq->cmd, ring_req->cmnd, ring_req->cmd_len);
+
+ memset(sense, 0, sizeof(sense)); /*FIXME*/
+ pending_req->rq->sense = sense;
+ pending_req->rq->sense_len = 0;
+
+ pending_req->rq->retries = ring_req->retries;
+ pending_req->rq->timeout = ring_req->timeout_per_command;
+
+ pending_req->rq->end_io_data = pending_req;
+
+ for (i = 0; i < use_sg; i++) {
+ flags = GNTMAP_host_map;
+ if (write)
+ flags |= GNTMAP_readonly;
+
+ gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags,
+ ring_req->seg[i].gref,
+ info->dev->otherend_id);
+ }
+
+ if (use_sg) {
+ err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
+ map, use_sg);
+ BUG_ON(err);
+ }
+
+ for (i = 0; i < use_sg; i++) {
+ if (unlikely(map[i].status != 0)) {
+ printk("invalid buffer -- could not remap it\n");
+ map[i].handle = SCSIBACK_INVALID_HANDLE;
+ err |= 1;
+ }
+
+ pending_handle(pending_req, i) = map[i].handle;
+
+ if (err)
+ continue;
+
+ set_phys_to_machine(__pa(vaddr(
+ pending_req, i)) >> PAGE_SHIFT,
+ FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT));
+ }
+
+ if (err)
+ goto fail_flush;
+
+ if (use_sg) {
+ if (requset_map_sg(ring_req, pending_req)) {
+ printk("SG Request Map Error\n");
+ goto fail_map;
+ }
+ }
+
+ atomic_set(&pending_req->pendcnt, 1);
+ scsiback_get(info);
+
+ blk_execute_rq_nowait(pending_req->rq->q, NULL, pending_req->rq,
+ 1, scsiback_end_cmd_fn);
+
+ return ;
+
+fail_map:
+fail_flush:
+ fast_flush_area(pending_req);
+fail_response:
+ make_sense(info, NULL, 1, ring_req->rqid);
+ free_req(pending_req);
+ printk("%s error\n",__FUNCTION__);
+}
+
+static int do_scsiback_cmd_fn(struct scsiback_info *info)
+{
+ struct scsiif_back_ring *ring = &info->ring;
+ struct scsiif_request *ring_req;
+
+ pending_req_t *pending_req;
+ RING_IDX rc, rp;
+ int more_to_do = 0;
+
+ rc = ring->req_cons;
+ rp = ring->sring->req_prod;
+ rmb();
+
+ while ((rc != rp) && !RING_REQUEST_CONS_OVERFLOW(ring, rc)) {
+
+ pending_req = alloc_req();
+ if (NULL == pending_req) {
+ more_to_do = 1;
+ break;
+ }
+
+ ring_req = RING_GET_REQUEST(ring, rc);
+ ring->req_cons = ++rc;
+
+ scsiback_cmd_exec(info, ring_req, pending_req);
+ }
+
+ return more_to_do;
+}
+
+int scsiback_schedule(void *data)
+{
+ struct scsiback_info *info = data;
+
+ scsiback_get(info);
+
+ while (!kthread_should_stop()) {
+ wait_event_interruptible(
+ info->wq,
+ info->waiting_reqs || kthread_should_stop());
+ wait_event_interruptible(
+ pending_free_wq,
+ !list_empty(&pending_free) || kthread_should_stop());
+
+ info->waiting_reqs = 0;
+ smp_mb();
+
+ if (do_scsiback_cmd_fn(info))
+ info->waiting_reqs = 1;
+ }
+
+ info->kthread = NULL;
+ scsiback_put(info);
+
+ return 0;
+}
+
+
+static int scsiback_remove(struct xenbus_device *dev)
+{
+ struct scsiback_info *info = dev->dev.driver_data;
+
+ if (info->backend_watch.node) {
+ unregister_xenbus_watch(&info->backend_watch);
+ kfree(info->backend_watch.node);
+ info->backend_watch.node = NULL;
+ }
+
+ if (info) {
+ scsiback_disconnect(info);
+ scsiback_free(info);
+ info = NULL;
+ }
+
+ kfree(info);
+
+ return 0;
+}
+
+
+static int scsiback_connect(struct scsiback_info *info)
+{
+ struct xenbus_device *dev = info->dev;
+ unsigned long ring_ref;
+ unsigned int evtchn;
+ int err;
+
+ err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu",
+ &ring_ref, "event-channel", "%u", &evtchn, NULL);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "reading %s ring", dev->otherend);
+ return err;
+ }
+
+ err = scsiback_init_sring(info, ring_ref, evtchn);
+ if (err) {
+ return err;
+ }
+
+ info->kthread = kthread_run(scsiback_schedule, info, "scsiif");
+ if (IS_ERR(info->kthread)) {
+ err = PTR_ERR(info->kthread);
+ info->kthread = NULL;
+ xenbus_dev_error(info->dev, err, "start scsiif");
+ }
+
+ return 0;
+}
+
+static void scsiback_frontend_changed(struct xenbus_device *dev,
+ enum xenbus_state frontend_state)
+{
+ struct scsiback_info *info = dev->dev.driver_data;
+ int err;
+
+ switch (frontend_state) {
+ case XenbusStateInitialising:
+ break;
+
+ case XenbusStateInitialised:
+ case XenbusStateConnected:
+ if (dev->state == XenbusStateConnected)
+ break;
+
+ err = scsiback_connect(info);
+ if (err)
+ break;
+
+ err = xenbus_switch_state(dev, XenbusStateConnected);
+ if (err)
+ xenbus_dev_fatal(dev, err, "switching to Connected state",
+ dev->nodename);
+ break;
+
+ case XenbusStateClosing:
+ scsiback_disconnect(info);
+ xenbus_switch_state(dev, XenbusStateClosing);
+ break;
+
+ case XenbusStateClosed:
+ xenbus_switch_state(dev, XenbusStateClosed);
+ if (xenbus_dev_is_online(dev))
+ break;
+
+ case XenbusStateUnknown:
+ /*
+ * workaround.
+ */
+ if (info->host->host_no)
+ device_unregister(&dev->dev);
+ break;
+ default:
+ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
+ frontend_state);
+ break;
+ }
+}
+
+
+static void scsiback_backend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ struct scsiback_info *info =
+ container_of(watch, struct scsiback_info, backend_watch);
+
+ printk("%s %p %u\n", __FUNCTION__, info->dev, info->dev->state);
+
+ /*FIXME*/
+}
+
+
+static int scsiback_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ int err, hostno;
+ struct scsiback_info *info;
+
+
+ DPRINTK("%p %d\n", dev, dev->otherend_id);
+
+ err = xenbus_scanf(XBT_NIL, dev->nodename, "hostno", "%d", &hostno);
+ if (err == -ENOENT ) {
+ printk("error xenbus_scanf hostno=%d\n",hostno);
+ goto fail;
+ }
+
+ info = scsiinfo_alloc(dev->otherend_id);
+ if (IS_ERR(info)) {
+ err = PTR_ERR(info);
+ info = NULL;
+ xenbus_dev_fatal(dev, err, "creating block interface");
+ goto fail;
+ }
+
+ info->host = scsi_host_lookup(hostno);
+
+ dev->dev.driver_data = info;
+
+ info->dev = dev;
+ info->irq = 0;
+
+ err = xenbus_watch_path2(dev, dev->nodename,
+ "scsi-host",
+ &info->backend_watch,
+ scsiback_backend_changed);
+ if (err)
+ goto fail;
+
+ err = xenbus_switch_state(dev, XenbusStateInitWait);
+ if (err)
+ goto fail;
+
+ return 0;
+
+fail:
+ printk("%s failed\n",__FUNCTION__);
+ scsiback_remove(dev);
+
+ return err;
+}
+
+
+static struct xenbus_device_id scsiback_ids[] = {
+ { "scsihost" },
+ { "" }
+};
+
+static struct xenbus_driver scsiback = {
+ .name = "scsihost",
+ .owner = THIS_MODULE,
+ .ids = scsiback_ids,
+ .probe = scsiback_probe,
+ .remove = scsiback_remove,
+ .otherend_changed = scsiback_frontend_changed
+};
+
+static int __init scsiback_init(void)
+{
+ int err = -ENOMEM;
+ int i, mmap_pages;
+
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ mmap_pages = CAN_QUEUE * SG_TABLESIZE;
+
+ pending_reqs = kmalloc(sizeof(pending_reqs[0]) *
+ CAN_QUEUE, GFP_KERNEL);
+ pending_grant_handles = kmalloc(sizeof(pending_grant_handles[0]) *
+ mmap_pages, GFP_KERNEL);
+ pending_pages = alloc_empty_pages_and_pagevec(mmap_pages);
+
+ if (!pending_reqs || !pending_grant_handles || !pending_pages)
+ goto out_of_memory;
+
+ for (i = 0; i < mmap_pages; i++)
+ pending_grant_handles[i] = SCSIBACK_INVALID_HANDLE;
+
+ scsiback_interface_init();
+
+ memset(pending_reqs, 0, sizeof(pending_reqs));
+ INIT_LIST_HEAD(&pending_free);
+
+ for (i = 0; i < CAN_QUEUE; i++)
+ list_add_tail(&pending_reqs[i].free_list, &pending_free);
+
+ err = xenbus_register_backend(&scsiback);
+ if (err)
+ goto out_of_memory;
+
+ return 0;
+
+ out_of_memory:
+ kfree(pending_reqs);
+ kfree(pending_grant_handles);
+ free_empty_pages_and_pagevec(pending_pages, mmap_pages);
+ printk("%s: out of memory\n", __FUNCTION__);
+ return -ENOMEM;
+}
+
+module_init(scsiback_init);
+
+MODULE_DESCRIPTION("Xen SCSI backend driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff -r 52f99cf7240f -r 06db0e13731c include/public/io/scsiif.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/include/public/io/scsiif.h Fri Jun 29 18:08:20 2007 +0900
@@ -0,0 +1,49 @@
+/*
+ * Copyright(c) FUJITSU Limited 2007.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Based on the blkback/blkfront driver code.
+ *
+ */
+#ifndef __XEN__PUBLIC_IO_SCSI_H__
+#define __XEN__PUBLIC_IO_SCSI_H__
+
+#include "ring.h"
+#include "../grant_table.h"
+
+#define CAN_QUEUE 8
+#define SG_TABLESIZE 11
+
+struct scsiif_request {
+#define MAX_COMMAND_SIZE 16
+ uint8_t cmnd[MAX_COMMAND_SIZE];
+ uint8_t cmd_len;
+ uint32_t id, lun, channel;
+ uint16_t sc_data_direction;
+ uint16_t use_sg;
+ uint16_t request_bufflen;
+ int32_t retries;
+ int32_t timeout_per_command;
+ uint64_t rqid;
+ struct scsiif_request_segment{
+ grant_ref_t gref;
+ uint32_t offset;
+ uint32_t length;
+ } seg[SG_TABLESIZE];
+};
+
+struct scsiif_response {
+ uint64_t rqid;
+ int32_t result;
+ uint64_t sense_len;
+#define SCSI_SENSE_BUFFERSIZE 96
+ uint8_t sense_buffer[SCSI_SENSE_BUFFERSIZE];
+};
+
+DEFINE_RING_TYPES(scsiif, struct scsiif_request, struct scsiif_response);
+
+#endif
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC] [3/4] PV driver for FC transport layer (pv-scsi frontend driver)
2007-06-29 11:04 [RFC] [0/4] PV driver for FC transport layer Jun Kamada
2007-06-29 11:06 ` [RFC] [1/4] PV driver for FC transport layer (config files for pv-scsi) Jun Kamada
2007-06-29 11:06 ` [RFC] [2/4] PV driver for FC transport layer (pv-scsi backend driver) Jun Kamada
@ 2007-06-29 11:07 ` Jun Kamada
2007-06-29 11:08 ` [RFC] [4/4] PV driver for FC transport layer (FC transport layer driver) Jun Kamada
2007-07-03 0:07 ` [RFC] [0/4] PV driver for FC transport layer Ian Pratt
4 siblings, 0 replies; 12+ messages in thread
From: Jun Kamada @ 2007-06-29 11:07 UTC (permalink / raw)
Cc: kama, xen-devel
[-- Attachment #1: Type: text/plain, Size: 100 bytes --]
Jun Kamada
Linux Technology Development Div.
Server Systems Unit
Fujitsu Ltd.
kama@jp.fujitsu.com
[-- Attachment #2: scsifront.patch --]
[-- Type: application/octet-stream, Size: 14169 bytes --]
# HG changeset patch
# User Jun Kamada <kama@jp.fujitsu.com>
# Date 1183108159 -32400
# Node ID 0f169b36be81293df09f1c66b6284dc00270854f
# Parent 06db0e13731c650c5b2ddf6d8048f9c89d89a012
add scsifront driver
Signed-off-by: Tomonari Horikoshi <t.horikoshi@jp.fujitsu.com>
Signed-off-by: Tsunehisa Doi <Doi.Tsunehisa@jp.fujitsu.com>
Signed-off-by: Jun Kamada <kama@jp.fujitsu.com>
Signed-off-by: Akira Hayakawa <hayakawa.akira@jp.fujitsu.com>
diff -r 06db0e13731c -r 0f169b36be81 drivers/xen/scsifront/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/Makefile Fri Jun 29 18:09:19 2007 +0900
@@ -0,0 +1,4 @@
+obj-$(CONFIG_XEN_SCSI_FRONTEND) := xenscsi.o
+
+xenscsi-objs := scsifront.o
+
diff -r 06db0e13731c -r 0f169b36be81 drivers/xen/scsifront/scsifront.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/scsifront.c Fri Jun 29 18:09:19 2007 +0900
@@ -0,0 +1,524 @@
+/*
+ * Xen SCSI frontend driver
+ *
+ * Copyright (c) 2007, FUJITSU Limited
+ *
+ * Based on the scsifront driver code by FUJITA Tomonori
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/scatterlist.h>
+#include <linux/uio.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <xen/evtchn.h>
+#include <xen/xenbus.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/io/scsiif.h>
+#include <xen/interface/io/ring.h>
+#include <xen/gnttab.h>
+#include <asm/hypervisor.h>
+
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
+#define GRANT_INVALID_REF 0
+
+
+#define DPRINTK(_f, _a...) \
+ pr_debug("(file=%s, line=%d) " _f, \
+ __FILE__ , __LINE__ , ## _a )
+
+
+struct scsi_shadow {
+ struct scsiif_request ring_req;
+ unsigned long req_scsi_cmnd;
+};
+
+#define SCSI_RING_SIZE __RING_SIZE((struct scsiif_sring *)0, PAGE_SIZE)
+
+struct scsifront_info {
+ struct xenbus_device *dev;
+ struct Scsi_Host *host;
+ unsigned int evtchn;
+ unsigned int irq;
+ unsigned long ring_ref;
+ struct scsiif_front_ring ring;
+ struct scsi_shadow shadow[SCSI_RING_SIZE];
+ unsigned long shadow_free;
+};
+
+
+static inline int GET_ID_FROM_FREELIST(
+ struct scsifront_info *info)
+{
+ unsigned long free = info->shadow_free;
+ BUG_ON(free > SCSI_RING_SIZE);
+ info->shadow_free = info->shadow[free].ring_req.rqid;
+ info->shadow[free].ring_req.rqid = 0x0fffffee; /* debug */
+ return free;
+}
+
+static inline void ADD_ID_TO_FREELIST(
+ struct scsifront_info *info, unsigned long id)
+{
+ info->shadow[id].ring_req.rqid = info->shadow_free;
+ info->shadow[id].req_scsi_cmnd = 0;
+ info->shadow_free = id;
+}
+
+static void scsifront_free(struct scsifront_info *info)
+{
+
+ scsi_remove_host(info->host);
+ scsi_host_put(info->host);
+
+ flush_scheduled_work();
+
+ if (info->ring_ref != GRANT_INVALID_REF) {
+ gnttab_end_foreign_access(info->ring_ref, 0,
+ (unsigned long)info->ring.sring);
+ info->ring_ref = GRANT_INVALID_REF;
+ info->ring.sring = NULL;
+ }
+
+ if (info->irq)
+ unbind_from_irqhandler(info->irq, info);
+ info->irq = 0;
+}
+
+static int map_data_for_request(struct scsifront_info *info,
+ struct scsi_cmnd *sc, struct scsiif_request *ring_req)
+{
+ struct scatterlist *sg = sc->request_buffer;
+
+ grant_ref_t gref_head;
+ int err, i, ref;
+ int write = (sc->sc_data_direction == DMA_TO_DEVICE);
+
+ if (!sg || sc->sc_data_direction == DMA_NONE)
+ return 0;
+
+ err = gnttab_alloc_grant_references(SG_TABLESIZE, &gref_head);
+ if (err)
+ return -ENOMEM;
+
+ for (i = 0; i < sc->use_sg; i++, sg++) {
+ ref = gnttab_claim_grant_reference(&gref_head);
+ BUG_ON(ref == -ENOSPC); /*FIXME*/
+
+ gnttab_grant_foreign_access_ref(ref, info->dev->otherend_id,
+ (page_to_phys(sg->page) >> PAGE_SHIFT), write);
+ ring_req->seg[i].gref = ref;
+ ring_req->seg[i].offset = sg->offset;
+ ring_req->seg[i].length = sg->length;
+ }
+
+ gnttab_free_grant_references(gref_head);
+
+ return 0;
+}
+
+static int scsifront_queuecommand(struct scsi_cmnd *sc,
+ void (*done)(struct scsi_cmnd *))
+{
+ struct Scsi_Host *host = sc->device->host;
+ struct scsifront_info *info = (struct scsifront_info *) host->hostdata;
+ struct scsiif_request *ring_req;
+ struct scsiif_front_ring *ring = &info->ring;
+ int err, notify;
+ unsigned long id;
+
+ if (info->dev->state != XenbusStateConnected || RING_FULL(ring)) {
+ printk("busy %u!\n", info->dev->state);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+ sc->scsi_done = done;
+ sc->result = 0;
+
+ ring_req = RING_GET_REQUEST(&info->ring, ring->req_prod_pvt);
+
+ ring_req->id = sc->device->id;
+ ring_req->lun = sc->device->lun;
+ ring_req->channel = sc->device->channel;
+ ring_req->cmd_len = sc->cmd_len;
+
+ BUG_ON(sc->cmd_len > MAX_COMMAND_SIZE);
+
+ if ( sc->cmd_len )
+ memcpy(ring_req->cmnd, sc->cmnd, sc->cmd_len);
+ else
+ memset(ring_req->cmnd, 0, MAX_COMMAND_SIZE);
+
+ ring_req->use_sg = sc->use_sg;
+ ring_req->sc_data_direction = sc->sc_data_direction;
+ ring_req->request_bufflen = sc->request_bufflen;
+ ring_req->retries = sc->retries;
+ ring_req->timeout_per_command = sc->timeout_per_command;
+
+ id = GET_ID_FROM_FREELIST(info); /* use id by response */
+ info->shadow[id].req_scsi_cmnd = (unsigned long)sc;
+ ring_req->rqid = id;
+ err = map_data_for_request(info, sc, ring_req);
+ if (err) {
+ printk("%s error\n",__FUNCTION__);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ ring->req_prod_pvt++;
+
+ info->shadow[id].ring_req = *ring_req;
+
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify);
+
+ if (notify)
+ notify_remote_via_irq(info->irq);
+
+ return 0;
+}
+
+static int scsifront_eh_abort_handler(struct scsi_cmnd *sc)
+{
+ /* not implemented */
+ BUG();
+ return 0;
+}
+
+static void scsifront_cmd_done(struct scsi_shadow *s)
+{
+ int i;
+
+ if (!s->ring_req.request_bufflen ||
+ (s->ring_req.sc_data_direction != DMA_TO_DEVICE &&
+ s->ring_req.sc_data_direction != DMA_FROM_DEVICE)) {
+ return;
+ }
+
+ if (!s->ring_req.use_sg)
+ return;
+
+ for (i = 0; i < s->ring_req.use_sg; i++ )
+ gnttab_end_foreign_access(s->ring_req.seg[i].gref, 0, 0UL);
+}
+
+static irqreturn_t scsifront_intr(int irq, void *dev_id,
+ struct pt_regs *ptregs)
+{
+ struct scsifront_info *info = (struct scsifront_info *) dev_id;
+ struct scsiif_front_ring *ring = &info->ring;
+ struct scsiif_response *ring_res;
+
+ struct scsi_cmnd *sc;
+ int i, rp;
+ unsigned long id;
+
+ if (info->dev->state != XenbusStateConnected)
+ return IRQ_HANDLED;
+
+again:
+ rp = info->ring.sring->rsp_prod;
+ rmb();
+
+ for (i = info->ring.rsp_cons; i != rp; i++) {
+ ring_res = RING_GET_RESPONSE(ring, i);
+
+ id = ring_res->rqid;
+ sc = (struct scsi_cmnd *)info->shadow[id].req_scsi_cmnd;
+ scsifront_cmd_done(&info->shadow[id]);
+
+ ADD_ID_TO_FREELIST(info, id);
+
+ sc->result = ring_res->result;
+ sc->resid = 0;
+
+ BUG_ON(ring_res->sense_len > SCSI_SENSE_BUFFERSIZE);
+
+ if (ring_res->sense_len)
+ memcpy(sc->sense_buffer, ring_res->sense_buffer,
+ ring_res->sense_len);
+
+ sc->scsi_done(sc);
+ }
+
+ info->ring.rsp_cons = i;
+ if (i != info->ring.req_prod_pvt) {
+ int more_to_do;
+ RING_FINAL_CHECK_FOR_RESPONSES(ring, more_to_do);
+ if (more_to_do)
+ goto again;
+ } else
+ ring->sring->rsp_event = i + 1;
+
+ return IRQ_HANDLED;
+}
+
+static int scsifront_alloc_ring(struct scsifront_info *info)
+{
+ struct xenbus_device *dev = info->dev;
+ struct scsiif_sring *sring;
+ int err = -ENOMEM;
+
+ info->ring_ref = GRANT_INVALID_REF;
+
+ sring = (struct scsiif_sring *) __get_free_page(GFP_KERNEL);
+ if (!sring) {
+ xenbus_dev_fatal(dev, err, "fail to allocate shared ring");
+ return err;
+ }
+
+ SHARED_RING_INIT(sring);
+ FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
+ DPRINTK("0x%x\n", RING_SIZE(&info->ring));
+
+ err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
+ if (err < 0) {
+ xenbus_dev_fatal(dev, err, "fail to grant shared ring");
+ goto free_sring;
+ }
+ info->ring_ref = err;
+ err = bind_listening_port_to_irqhandler(
+ dev->otherend_id, scsifront_intr,
+ SA_SAMPLE_RANDOM, "scsifront", info);
+
+ if (err <= 0) {
+ xenbus_dev_fatal(dev, err, "bind_listening_port_to_irqhandler");
+ goto fail;
+ }
+ info->irq = err;
+
+ return 0;
+fail:
+ /* free resource */
+free_sring:
+ free_page((unsigned long) sring);
+ scsifront_free(info);
+
+ return err;
+}
+
+static int scsifront_init_ring(struct scsifront_info *info)
+{
+ struct xenbus_device *dev = info->dev;
+ struct xenbus_transaction xbt;
+ int err;
+
+ DPRINTK("");
+
+ err = scsifront_alloc_ring(info);
+ if (err)
+ return err;
+ DPRINTK("%lu %u\n", info->ring_ref, info->evtchn);
+
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "starting transaction");
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%lu",
+ info->ring_ref);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "%s", "writing ring-ref");
+ goto fail;
+ }
+
+#ifdef XEN303 /*FJVMIO xen3.0.5*/
+ err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+ info->evtchn);
+#else
+ err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+ irq_to_evtchn_port(info->irq));
+#endif
+ if (err) {
+ xenbus_dev_fatal(dev, err, "%s", "writing event-channel");
+ goto fail;
+ }
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err) {
+ if (err == -EAGAIN)
+ goto again;
+ xenbus_dev_fatal(dev, err, "completing transaction");
+ } else
+ xenbus_switch_state(dev, XenbusStateInitialised);
+
+ return 0;
+fail:
+ xenbus_transaction_end(xbt, 1);
+ /* free resource */
+ scsifront_free(info);
+
+ return err;
+}
+
+static struct scsi_host_template scsifront_sht = {
+ .module = THIS_MODULE,
+ .name = "Xen SCSI frontend driver",
+ .queuecommand = scsifront_queuecommand,
+ .eh_abort_handler = scsifront_eh_abort_handler,
+ .cmd_per_lun = CAN_QUEUE,
+ .can_queue = CAN_QUEUE,
+ .this_id = -1,
+ .sg_tablesize = SG_TABLESIZE,
+ .use_clustering = DISABLE_CLUSTERING,
+ .proc_name = "scsifront",
+};
+
+static int scsifront_connect(struct scsifront_info *info)
+{
+ struct xenbus_device *dev = info->dev;
+ struct Scsi_Host *host = info->host;
+ int err = -ENOMEM;
+
+ DPRINTK("%u\n", dev->state);
+ if (dev->state == XenbusStateConnected)
+ return 0;
+
+ xenbus_switch_state(dev, XenbusStateConnected);
+
+ /* FIXME */
+ host->max_id = 1;
+ host->max_channel = 0;
+
+ err = scsi_add_host(host, &dev->dev);
+ if (err) {
+ printk("fail to add scsi host %d\n", err);
+ return err;
+ }
+
+ scsi_scan_host(host);
+
+ return 0;
+}
+
+static int scsifront_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ struct Scsi_Host *host;
+ struct scsifront_info *info;
+ int i, err = -ENOMEM;
+
+ host = scsi_host_alloc(&scsifront_sht, sizeof(*info));
+ if (!host) {
+ xenbus_dev_fatal(dev, err, "fail to allocate scsi host");
+ return err;
+ }
+ info = (struct scsifront_info *) host->hostdata;
+ dev->dev.driver_data = info;
+ info->dev = dev;
+ info->host = host;
+
+ for (i = 0; i < SCSI_RING_SIZE; i++)
+ info->shadow[i].ring_req.rqid = i + 1;
+ info->shadow[SCSI_RING_SIZE - 1].ring_req.rqid = 0x0fffffff;
+
+ err = scsifront_init_ring(info);
+ if (err) {
+ scsi_host_put(host);
+ return err;
+ }
+
+ return 0;
+}
+
+
+static int scsifront_remove(struct xenbus_device *dev)
+{
+ struct scsifront_info *info = dev->dev.driver_data;
+
+ scsifront_free(info);
+
+ return 0;
+}
+
+static void scsifront_backend_changed(struct xenbus_device *dev,
+ XenbusState backend_state)
+{
+ struct scsifront_info *info = dev->dev.driver_data;
+
+ DPRINTK("%p %u %u\n", dev, dev->state, backend_state);
+
+ switch (backend_state) {
+ case XenbusStateUnknown:
+ case XenbusStateInitialising:
+ case XenbusStateInitWait:
+ case XenbusStateInitialised:
+ case XenbusStateClosed:
+ break;
+
+ case XenbusStateConnected:
+ scsifront_connect(info);
+ break;
+
+ case XenbusStateClosing:
+ break;
+ }
+}
+
+static struct xenbus_device_id scsifront_ids[] = {
+ { "scsihost" },
+ { "" }
+};
+
+
+static struct xenbus_driver scsifront_driver = {
+ .name = "scsihost",
+ .owner = THIS_MODULE,
+ .ids = scsifront_ids,
+ .probe = scsifront_probe,
+ .remove = scsifront_remove,
+/* .resume = scsifront_resume, */
+ .otherend_changed = scsifront_backend_changed,
+};
+
+static int __init scsifront_init(void)
+{
+ int err;
+
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ err = xenbus_register_frontend(&scsifront_driver);
+
+ return err;
+}
+
+static void scsifront_exit(void)
+{
+ xenbus_unregister_driver(&scsifront_driver);
+}
+
+module_init(scsifront_init);
+module_exit(scsifront_exit);
+
+MODULE_DESCRIPTION("Xen SCSI frontend driver");
+MODULE_LICENSE("GPL");
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC] [4/4] PV driver for FC transport layer (FC transport layer driver)
2007-06-29 11:04 [RFC] [0/4] PV driver for FC transport layer Jun Kamada
` (2 preceding siblings ...)
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
2007-07-03 0:07 ` [RFC] [0/4] PV driver for FC transport layer Ian Pratt
4 siblings, 0 replies; 12+ messages in thread
From: Jun Kamada @ 2007-06-29 11:08 UTC (permalink / raw)
Cc: kama, xen-devel
[-- 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
^ permalink raw reply [flat|nested] 12+ messages in thread
* RE: [RFC] [0/4] PV driver for FC transport layer
2007-06-29 11:04 [RFC] [0/4] PV driver for FC transport layer Jun Kamada
` (3 preceding siblings ...)
2007-06-29 11:08 ` [RFC] [4/4] PV driver for FC transport layer (FC transport layer driver) Jun Kamada
@ 2007-07-03 0:07 ` Ian Pratt
2007-07-04 11:03 ` Jun Kamada
2007-07-06 0:22 ` FUJITA Tomonori
4 siblings, 2 replies; 12+ messages in thread
From: Ian Pratt @ 2007-07-03 0:07 UTC (permalink / raw)
To: Jun Kamada, xen-devel
> We developed a prototype of para-virtual FC(Fibre Channel) SCSI
driver.
> It's a extension of the "pv-scsi" driver, that Horikoshi-san posted on
> 16 May 2007 ([Xen-devel] [RFC] pv-scsi driver (scsiback/scsifront)),
> in order to support FC transport layer.
I'm struggling slightly to understand the usage scenario planned for
this stuff. Mapping a SCSI LUN through to a guest makes perfect sense
(e.g. for performing SCSI reservations, special SCSI commands like FUA,
controlling a tape robot etc), but mapping a whole HBA through to a
guest seems less useful -- usually it's the case you want to hide all
that nastiness from the guest, taking care of multipath etc in dom0
rather than exposing it to the guest.
Have you a particular scenario in mind?
Thanks,
Ian
> The FC extension mainly performs following processes.
>
> 1. Copies FC attributes stored in Dom0 to DomU at the driver
> initialization phase. The attributes are originally stored in
> "Scsi_Host", "scsi_target" and "fc_rport" structures.
> 2. When /sys/class/fc_*/*/* on DomU is accessed from user land,
performs
> appropriate function on Dom0.
>
> We expect your helpful comments especially at following point of view.
>
> - What any other functions are required in order to behave as
"complete"
> FC driver? (We are not familiar with FC driver.)
> - This is the sub-question of above. Current prototype supports only
> "frontend driven" functions. What types of "backend driven"
functions
> we have to support?
>
> Any other comments are welcomed.
>
> Best regards
>
> -----
> Jun Kamada
> Linux Technology Development Div.
> Server Systems Unit
> Fujitsu Ltd.
> kama@jp.fujitsu.com
>
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xensource.com
> http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC] [0/4] PV driver for FC transport layer
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 0:22 ` FUJITA Tomonori
1 sibling, 1 reply; 12+ messages in thread
From: Jun Kamada @ 2007-07-04 11:03 UTC (permalink / raw)
To: Ian Pratt; +Cc: kama, xen-devel
Hi Ian-san,
Thank you for your reply.
On Tue, 3 Jul 2007 01:07:04 +0100
"Ian Pratt" <Ian.Pratt@cl.cam.ac.uk> wrote:
> > We developed a prototype of para-virtual FC(Fibre Channel) SCSI
> driver.
> > It's a extension of the "pv-scsi" driver, that Horikoshi-san posted on
> > 16 May 2007 ([Xen-devel] [RFC] pv-scsi driver (scsiback/scsifront)),
> > in order to support FC transport layer.
>
> I'm struggling slightly to understand the usage scenario planned for
> this stuff. Mapping a SCSI LUN through to a guest makes perfect sense
> (e.g. for performing SCSI reservations, special SCSI commands like FUA,
> controlling a tape robot etc), but mapping a whole HBA through to a
> guest seems less useful -- usually it's the case you want to hide all
> that nastiness from the guest, taking care of multipath etc in dom0
> rather than exposing it to the guest.
>
> Have you a particular scenario in mind?
We are planning to run a storage management software, which controls
bindings storages on FC network to hosts, on group of guest domains.
The software expect that each guest domain has each HBA, and control the
HBA directly. (Ex. resetting SCSI bus and getting WWN, ...)
On the other hand, we consider that NPIV (N_Port ID Virtualization)
technology makes it possible to assign whole "logical/virtual" HBA to
each gueast domain.
That's our scenario in mind.
Best regards
-----
Jun Kamada
Linux Technology Development Div.
Server Systems Unit
Fujitsu Ltd.
kama@jp.fujitsu.com
^ permalink raw reply [flat|nested] 12+ messages in thread
* RE: [RFC] [0/4] PV driver for FC transport layer
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
1 sibling, 0 replies; 12+ messages in thread
From: FUJITA Tomonori @ 2007-07-06 0:22 UTC (permalink / raw)
To: Ian.Pratt; +Cc: kama, xen-devel
From: "Ian Pratt" <Ian.Pratt@cl.cam.ac.uk>
Subject: RE: [Xen-devel] [RFC] [0/4] PV driver for FC transport layer
Date: Tue, 3 Jul 2007 01:07:04 +0100
> > We developed a prototype of para-virtual FC(Fibre Channel) SCSI
> driver.
> > It's a extension of the "pv-scsi" driver, that Horikoshi-san posted on
> > 16 May 2007 ([Xen-devel] [RFC] pv-scsi driver (scsiback/scsifront)),
> > in order to support FC transport layer.
>
> I'm struggling slightly to understand the usage scenario planned for
> this stuff. Mapping a SCSI LUN through to a guest makes perfect sense
> (e.g. for performing SCSI reservations, special SCSI commands like FUA,
> controlling a tape robot etc), but mapping a whole HBA through to a
> guest seems less useful -- usually it's the case you want to hide all
> that nastiness from the guest, taking care of multipath etc in dom0
> rather than exposing it to the guest.
Mapping a SCSI LUN through to a guest is far complicated since it
needs the SCSI state machine.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC] [0/4] PV driver for FC transport layer
2007-07-04 11:03 ` Jun Kamada
@ 2007-07-06 0:22 ` FUJITA Tomonori
2007-07-06 6:44 ` Jun Kamada
0 siblings, 1 reply; 12+ messages in thread
From: FUJITA Tomonori @ 2007-07-06 0:22 UTC (permalink / raw)
To: kama; +Cc: Ian.Pratt, xen-devel
From: Jun Kamada <kama@jp.fujitsu.com>
Subject: Re: [Xen-devel] [RFC] [0/4] PV driver for FC transport layer
Date: Wed, 04 Jul 2007 20:03:32 +0900
> Hi Ian-san,
>
> Thank you for your reply.
>
> On Tue, 3 Jul 2007 01:07:04 +0100
> "Ian Pratt" <Ian.Pratt@cl.cam.ac.uk> wrote:
>
> > > We developed a prototype of para-virtual FC(Fibre Channel) SCSI
> > driver.
> > > It's a extension of the "pv-scsi" driver, that Horikoshi-san posted on
> > > 16 May 2007 ([Xen-devel] [RFC] pv-scsi driver (scsiback/scsifront)),
> > > in order to support FC transport layer.
> >
> > I'm struggling slightly to understand the usage scenario planned for
> > this stuff. Mapping a SCSI LUN through to a guest makes perfect sense
> > (e.g. for performing SCSI reservations, special SCSI commands like FUA,
> > controlling a tape robot etc), but mapping a whole HBA through to a
> > guest seems less useful -- usually it's the case you want to hide all
> > that nastiness from the guest, taking care of multipath etc in dom0
> > rather than exposing it to the guest.
> >
> > Have you a particular scenario in mind?
>
> We are planning to run a storage management software, which controls
> bindings storages on FC network to hosts, on group of guest domains.
> The software expect that each guest domain has each HBA, and control the
> HBA directly. (Ex. resetting SCSI bus and getting WWN, ...)
How do you support storage management software that uses non-scsi?
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC] [0/4] PV driver for FC transport layer
2007-07-06 0:22 ` FUJITA Tomonori
@ 2007-07-06 6:44 ` Jun Kamada
2007-07-06 7:26 ` FUJITA Tomonori
0 siblings, 1 reply; 12+ messages in thread
From: Jun Kamada @ 2007-07-06 6:44 UTC (permalink / raw)
To: FUJITA Tomonori; +Cc: kama, Ian.Pratt, xen-devel
Hi, Fujita-san,
On Fri, 06 Jul 2007 09:22:15 +0900
FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> wrote:
> > We are planning to run a storage management software, which controls
> > bindings storages on FC network to hosts, on group of guest domains.
> > The software expect that each guest domain has each HBA, and control the
> > HBA directly. (Ex. resetting SCSI bus and getting WWN, ...)
>
> How do you support storage management software that uses non-scsi?
Current our scope is only SCSI on FC.
What do you mean as the "non-scsi" ?
-----
Jun Kamada
Linux Technology Development Div.
Server Systems Unit
Fujitsu Ltd.
kama@jp.fujitsu.com
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC] [0/4] PV driver for FC transport layer
2007-07-06 6:44 ` Jun Kamada
@ 2007-07-06 7:26 ` FUJITA Tomonori
2007-07-06 8:54 ` Jun Kamada
0 siblings, 1 reply; 12+ messages in thread
From: FUJITA Tomonori @ 2007-07-06 7:26 UTC (permalink / raw)
To: kama; +Cc: fujita.tomonori, Ian.Pratt, xen-devel
From: Jun Kamada <kama@jp.fujitsu.com>
Subject: Re: [Xen-devel] [RFC] [0/4] PV driver for FC transport layer
Date: Fri, 06 Jul 2007 15:44:16 +0900
> Hi, Fujita-san,
>
> On Fri, 06 Jul 2007 09:22:15 +0900
> FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> wrote:
> > > We are planning to run a storage management software, which controls
> > > bindings storages on FC network to hosts, on group of guest domains.
> > > The software expect that each guest domain has each HBA, and control the
> > > HBA directly. (Ex. resetting SCSI bus and getting WWN, ...)
> >
> > How do you support storage management software that uses non-scsi?
>
> Current our scope is only SCSI on FC.
> What do you mean as the "non-scsi" ?
James Smart also asked you guys about this at the previous submission:
http://lists.xensource.com/archives/html/xen-devel/2007-05/msg00689.html
---
> We want to use SAN management software on guest OS. The software
> works on native(no VM) linux. So we think it is necesarry to
> have guest OS shown whether HBA card is FC or SCSI in the same
> way of native linux.
Well - depends on what/how your san mgmt works. If it's straight scsi,
then it would be fine - but you can't talk to anything non-scsi and
not enumerated by the hba. If it's layered on hbaapi, it does mean
you want to talk FC, not just scsi, and now things change significantly.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC] [0/4] PV driver for FC transport layer
2007-07-06 7:26 ` FUJITA Tomonori
@ 2007-07-06 8:54 ` Jun Kamada
0 siblings, 0 replies; 12+ messages in thread
From: Jun Kamada @ 2007-07-06 8:54 UTC (permalink / raw)
To: FUJITA Tomonori; +Cc: kama, Ian.Pratt, xen-devel
Fujita-san,
I'm sorry if following may not be a straight answer for your question.
Please imagine a large IDC. In general, some guest domain groups, which
have different storage managemnt policy, exist in the IDC. And, the each
domain group would like to have own storage management software within
the guest domain group.
We consider that the management software requires at least following
function to platform the software is running on.
- inform whether the currently focussed storage device or HBA is pure
SCSI or FC-SCSI.
- if FC-SCSI, inform FC attributes such as WWN to the software.
According to the information aquired, the storage managemant software
can control bindings of the storage and the HBA.
Thanks,
On Fri, 06 Jul 2007 16:26:11 +0900
FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> wrote:
> From: Jun Kamada <kama@jp.fujitsu.com>
> Subject: Re: [Xen-devel] [RFC] [0/4] PV driver for FC transport layer
> Date: Fri, 06 Jul 2007 15:44:16 +0900
>
> > Hi, Fujita-san,
> >
> > On Fri, 06 Jul 2007 09:22:15 +0900
> > FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> wrote:
> > > > We are planning to run a storage management software, which controls
> > > > bindings storages on FC network to hosts, on group of guest domains.
> > > > The software expect that each guest domain has each HBA, and control the
> > > > HBA directly. (Ex. resetting SCSI bus and getting WWN, ...)
> > >
> > > How do you support storage management software that uses non-scsi?
> >
> > Current our scope is only SCSI on FC.
> > What do you mean as the "non-scsi" ?
>
> James Smart also asked you guys about this at the previous submission:
>
> http://lists.xensource.com/archives/html/xen-devel/2007-05/msg00689.html
>
> ---
> > We want to use SAN management software on guest OS. The software
> > works on native(no VM) linux. So we think it is necesarry to
> > have guest OS shown whether HBA card is FC or SCSI in the same
> > way of native linux.
>
> Well - depends on what/how your san mgmt works. If it's straight scsi,
> then it would be fine - but you can't talk to anything non-scsi and
> not enumerated by the hba. If it's layered on hbaapi, it does mean
> you want to talk FC, not just scsi, and now things change significantly.
Jun Kamada
Linux Technology Development Div.
Server Systems Unit
Fujitsu Ltd.
kama@jp.fujitsu.com
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2007-07-06 8:54 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [RFC] [4/4] PV driver for FC transport layer (FC transport layer driver) Jun Kamada
2007-07-03 0:07 ` [RFC] [0/4] PV driver for FC transport layer Ian Pratt
2007-07-04 11:03 ` Jun Kamada
2007-07-06 0:22 ` FUJITA Tomonori
2007-07-06 6:44 ` Jun Kamada
2007-07-06 7:26 ` FUJITA Tomonori
2007-07-06 8:54 ` Jun Kamada
2007-07-06 0:22 ` FUJITA Tomonori
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.