From: Jun Kamada <kama@jp.fujitsu.com>
Cc: kama@jp.fujitsu.com, xen-devel@lists.xensource.com
Subject: [PATCH 1/6] pvSCSI (SCSI pass through) driver
Date: Tue, 30 Oct 2007 19:39:14 +0900 [thread overview]
Message-ID: <20071030193911.4419.KAMA@jp.fujitsu.com> (raw)
In-Reply-To: <20071025105803.5A32.KAMA@jp.fujitsu.com>
[-- Attachment #1: Type: text/plain, Size: 287 bytes --]
This patch is for frontend driver.
Signed-off-by: Tomonari Horikoshi <t.horikoshi@jp.fujitsu.com>
Signed-off-by: Tsunehisa Doi <Doi.Tsunehisa@jp.fujitsu.com>
Signed-off-by: Jun Kamada <kama@jp.fujitsu.com>
Signed-off-by: Akira Hayakawa <hayakawa.akira@jp.fujitsu.com>
-----
Jun Kamada
[-- Attachment #2: linux_scsifront.patch --]
[-- Type: application/octet-stream, Size: 64658 bytes --]
# HG changeset patch
# User t.horikoshi@jp.fujitsu.com
# Date 1193730096 -32400
# Node ID 24e0cb9fe9df6f4a6df226823562bec3089072e6
# Parent 709db80c03c3d7606744a71f48f5186358a5e659
[LINUX][scsifront] add scsi frontend driver
Signed-off-by: Tomonari Horikoshi <t.horikoshi@jp.fujitsu.com>
Signed-off-by: Tsunehisa Doi <Doi.Tsunehisa@jp.fujitsu.com>
Signed-off-by: Jun Kamada <kama@jp.fujitsu.com>
Signed-off-by: Akira Hayakawa <hayakawa.akira@jp.fujitsu.com>
diff -r 709db80c03c3 -r 24e0cb9fe9df drivers/xen/scsifront/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/Makefile Tue Oct 30 16:41:36 2007 +0900
@@ -0,0 +1,8 @@
+ifeq ($(CONFIG_XEN_FC),y)
+ EXTRA_CFLAGS += -DCONFIG_XEN_FC
+ obj-$(CONFIG_XEN_SCSI_FRONTEND) := xenfcscsi.o
+ xenfcscsi-objs := scsifront.o fcfront.o comfront.o tracefront.o
+else
+ obj-$(CONFIG_XEN_SCSI_FRONTEND) := xenscsi.o
+ xenscsi-objs := scsifront.o comfront.o tracefront.o
+endif
diff -r 709db80c03c3 -r 24e0cb9fe9df drivers/xen/scsifront/comfront.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/comfront.c Tue Oct 30 16:41:36 2007 +0900
@@ -0,0 +1,265 @@
+/*
+ * Xen SCSI frontend driver
+ *
+ * Copyright (c) 2007, FUJITSU Limited
+ *
+ * Based on the scsifront driver code by FUJITA Tomonori
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+#include <linux/version.h>
+#include "comfront.h"
+
+extern int scsifront_cmd_done(struct comfront_info *, struct vscsiif_btf_request *);
+static void comfront_notify_work(struct comfront_info *info);
+#ifdef CONFIG_XEN_FC
+extern void fcfront_cmd_done(struct comfront_info *, struct vscsiif_btf_request *);
+#endif
+
+extern void scsi_trace(unsigned long, unsigned char *, unsigned int);
+
+static inline int GET_ID_FROM_FREELIST(struct comfront_info *info)
+{
+ unsigned long flags;
+ uint32_t free;
+
+ spin_lock_irqsave(&info->shadow_lock, flags);
+
+ free = info->shadow_free;
+ BUG_ON(free > DEFAULT_CAN_QUEUE);
+ info->shadow_free = info->shadow[free].rqid;
+ info->shadow[free].rqid = 0x0fffffee; /* debug */
+
+ info->shadow[free].cond = 0;
+
+ spin_unlock_irqrestore(&info->shadow_lock, flags);
+
+ return free;
+}
+
+void ADD_ID_TO_FREELIST(struct comfront_info *info, uint32_t id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->shadow_lock, flags);
+
+ info->shadow[id].rqid = info->shadow_free;
+ info->shadow[id].u.scsi.req_scsi_cmnd = 0;
+ info->shadow_free = id;
+
+ spin_unlock_irqrestore(&info->shadow_lock, flags);
+}
+
+
+/* ------------------------------------------------------------ */
+/* for frontend to backend communication */
+/* ------------------------------------------------------------ */
+
+int read_ftb_ring_resp_cons(struct comfront_info *info)
+{
+ RING_IDX i, ftb_rp;
+ struct vscsiif_ftb_response *ring_res;
+ int err;
+
+ ftb_rp = info->ftb_ring.sring->rsp_prod;
+ err = SCSIIF_REQ_OKAY;
+ rmb();
+
+ for (i = info->ftb_ring.rsp_cons; i != ftb_rp; i++) {
+ ring_res = RING_GET_RESPONSE(&info->ftb_ring, i);
+
+ if (ring_res->status == SCSIIF_BTFRING_BUSY) {
+ err = SCSIIF_BTFRING_BUSY;
+ comfront_notify_work(info);
+ }
+ }
+
+ info->ftb_ring.rsp_cons = i;
+
+ return err;
+}
+
+struct vscsiif_ftb_request * comfront_pre_request(struct comfront_info *info)
+{
+ struct vscsiif_ftb_front_ring *ring = &(info->ftb_ring);
+ struct vscsiif_ftb_request *ring_req;
+ uint32_t id;
+
+ ring_req = RING_GET_REQUEST(&(info->ftb_ring), ring->req_prod_pvt);
+
+ id = GET_ID_FROM_FREELIST(info); /* use id by response */
+ ring_req->rqid = id;
+
+ return ring_req;
+}
+
+void comfront_do_request(struct comfront_info *info)
+{
+ struct vscsiif_ftb_front_ring *ring = &(info->ftb_ring);
+ unsigned int irq = info->irq;
+ int notify;
+
+ ring->req_prod_pvt++;
+
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify);
+
+ if (notify)
+ notify_remote_via_irq(irq);
+
+ /***** Front to Back response consume *****/
+ read_ftb_ring_resp_cons(info);
+}
+
+
+/* ------------------------------------------------------------ */
+/* for backend to frontend communication */
+/* ------------------------------------------------------------ */
+
+static void comfront_notify_work(struct comfront_info *info)
+{
+
+ info->waiting_resp = 1;
+ wake_up(&info->wq);
+}
+
+irqreturn_t comfront_intr(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ comfront_notify_work((struct comfront_info *)dev_id);
+ return IRQ_HANDLED;
+}
+
+static void __sync_cmd_done(struct comfront_info *info,
+ struct vscsiif_btf_request *btf_req)
+{
+ uint32_t id = btf_req->rqid;
+
+ info->btf_req = *btf_req;
+
+ info->shadow[id].cond++;
+ wake_up(&(info->shadow[id].wq));
+}
+
+int do_comfront_cmd_done(struct comfront_info *info)
+{
+ struct vscsiif_btf_back_ring *btf_ring = &info->btf_ring;
+ struct vscsiif_btf_request *btf_req;
+
+ int btf_rc, btf_rp;
+ int more_to_do = 0;
+
+ if (info->dev->state != XenbusStateConnected)
+ return 0;
+
+ /***** Back to Front request consume *****/
+ DPRINTK("%s\n",__FUNCTION__);
+
+ btf_rc = btf_ring->req_cons;
+ btf_rp = btf_ring->sring->req_prod;
+
+ while ((btf_rc != btf_rp) &&
+ !RING_REQUEST_CONS_OVERFLOW(btf_ring, btf_rc)) {
+
+ rmb();
+ btf_req = RING_GET_REQUEST(btf_ring, btf_rc);
+ btf_ring->req_cons = ++btf_rc;
+
+ if (info->shadow[btf_req->rqid].cmnd == CMND_SCSI) {
+ scsi_trace(2, (unsigned char *)btf_req,
+ sizeof(struct vscsiif_btf_request));
+
+ if (scsifront_cmd_done(info, btf_req)) {
+ BUG();
+ }
+
+ } else {
+ __sync_cmd_done(info, btf_req);
+ }
+
+ btf_ring->rsp_prod_pvt++;
+ RING_PUSH_RESPONSES(btf_ring);
+ }
+
+ if (btf_ring->rsp_prod_pvt == btf_rc) {
+ RING_FINAL_CHECK_FOR_REQUESTS(btf_ring, more_to_do);
+
+ } else if (RING_HAS_UNCONSUMED_REQUESTS(btf_ring)) {
+ more_to_do = 1;
+ }
+
+ return more_to_do;
+}
+
+int comfront_schedule(void *data)
+{
+ struct comfront_info *info = (struct comfront_info *)data;
+
+ while (!kthread_should_stop()) {
+ wait_event_interruptible(
+ info->wq,
+ info->waiting_resp || kthread_should_stop());
+
+ info->waiting_resp = 0;
+ smp_mb();
+
+ if (do_comfront_cmd_done(info))
+ info->waiting_resp = 1;
+
+ read_ftb_ring_resp_cons(info);
+
+ }
+
+ info->kthread = NULL;
+
+ return 0;
+}
+
+struct vscsiif_btf_request *comfront_do_request_and_wait_response(
+ struct comfront_info *info,
+ struct vscsiif_ftb_request *ring_req)
+{
+ struct vscsiif_btf_request *ring_res;
+ uint32_t rqid = ring_req->rqid;
+
+ info->shadow[rqid].cmnd = ring_req->cmnd;
+
+ scsi_trace(1, (unsigned char *)ring_req,
+ sizeof(struct vscsiif_ftb_request));
+
+ comfront_do_request(info);
+ wait_event_interruptible(info->shadow[rqid].wq,
+ info->shadow[rqid].cond);
+ info->shadow[rqid].cond--;
+
+ ADD_ID_TO_FREELIST(info, rqid);
+
+ ring_res = &(info->btf_req);
+
+ scsi_trace(2, (unsigned char *)ring_res,
+ sizeof(struct vscsiif_btf_request));
+
+ return ring_res;
+}
diff -r 709db80c03c3 -r 24e0cb9fe9df drivers/xen/scsifront/comfront.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/comfront.h Tue Oct 30 16:41:36 2007 +0900
@@ -0,0 +1,130 @@
+/*
+ * Xen SCSI frontend driver
+ *
+ * Copyright (c) 2007, FUJITSU Limited
+ *
+ * Based on the scsifront driver code by FUJITA Tomonori
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __XEN_DRIVERS_SCSIFRONT_H__
+#define __XEN_DRIVERS_SCSIFRONT_H__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#ifdef CONFIG_XEN_FC
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_fc.h>
+#endif
+#include <xen/xenbus.h>
+#include <xen/gnttab.h>
+#include <xen/evtchn.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/io/vscsiif.h>
+#include <asm/delay.h>
+
+
+#define GRANT_INVALID_REF 0
+
+struct comfront_shadow {
+ uint32_t rqid;
+ unsigned int cmnd;
+ wait_queue_head_t wq;
+ int cond;
+ union {
+ struct {
+ unsigned int sc_data_direction;
+ unsigned int use_sg;
+ unsigned int request_bufflen;
+ unsigned long req_scsi_cmnd;
+ int gref[SG_TABLESIZE];
+ } scsi;
+#ifdef CONFIG_XEN_FC
+ struct {
+ } fc;
+#endif
+ } u;
+};
+
+struct comfront_info {
+ struct xenbus_device *dev;
+ struct Scsi_Host *host;
+ spinlock_t io_lock;
+ spinlock_t shadow_lock;
+ unsigned int evtchn;
+ unsigned int irq;
+ int ftb_ring_ref;
+ int btf_ring_ref;
+ struct vscsiif_ftb_front_ring ftb_ring;
+ struct vscsiif_btf_back_ring btf_ring;
+ struct comfront_shadow shadow[DEFAULT_CAN_QUEUE];
+ uint32_t shadow_free;
+ struct vscsiif_btf_request btf_req;
+
+ struct task_struct *kthread;
+ wait_queue_head_t wq;
+ unsigned int waiting_resp;
+
+ void *fcinfo;
+};
+
+#define DPRINTK(_f, _a...) \
+ pr_debug("(file=%s, line=%d) " _f, \
+ __FILE__ , __LINE__ , ## _a )
+
+
+void ADD_ID_TO_FREELIST(struct comfront_info *info, uint32_t id);
+
+#ifdef CONFIG_XEN_FC
+extern int fcfront_get_initial_attribute(struct comfront_info *cominfo);
+extern int fcfront_get_function_template(struct comfront_info *cominfo);
+extern int fcfront_connection_setup(struct comfront_info *cominfo);
+extern void fcfront_connection_unsetup(struct comfront_info *cominfo);
+#endif
+
+
+struct vscsiif_ftb_request * comfront_pre_request(struct comfront_info *);
+struct vscsiif_btf_request *comfront_do_request_and_wait_response(
+ struct comfront_info *info,
+ struct vscsiif_ftb_request *ring_req);
+void comfront_do_request(struct comfront_info *);
+irqreturn_t comfront_intr(int, void *, struct pt_regs *);
+int comfront_schedule(void *);
+
+#endif /* __XEN_DRIVERS_SCSIFRONT_H__ */
diff -r 709db80c03c3 -r 24e0cb9fe9df drivers/xen/scsifront/fcfront.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/fcfront.c Tue Oct 30 16:41:36 2007 +0900
@@ -0,0 +1,777 @@
+/*
+ * Xen SCSI FC frontend driver
+ *
+ * Copyright (c) 2007, FUJITSU Limited
+ *
+ * Based on the scsifront driver code by FUJITA Tomonori
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/version.h>
+#include "comfront.h"
+#include "fcfront.h"
+
+
+extern void notify_remote_via_irq(int);
+extern int irq_to_evtchn_port(int);
+extern int bind_listening_port_to_irqhandler(unsigned int,
+ irqreturn_t (*handler)(int, void *, struct pt_regs *),
+ unsigned long, const char *, void *);
+extern void unbind_from_irqhandler(unsigned int, void *);
+extern int gnttab_grant_foreign_access(domid_t, unsigned long, int);
+extern int gnttab_end_foreign_access_ref(grant_ref_t, int);
+extern void gnttab_end_foreign_access(grant_ref_t, int, unsigned long);
+
+extern struct vscsiif_ftb_request *comfront_pre_request(struct comfront_info *);
+extern void comfront_do_request(struct comfront_info *);
+
+extern struct vscsiif_btf_request *comfront_do_request_and_wait_response(
+ struct comfront_info *,
+ struct vscsiif_ftb_request *);
+
+
+
+/* ---------------------------------------------------------------------- */
+
+static void fc_get_host_port_id(struct Scsi_Host *shost)
+{
+ struct comfront_info *cominfo = (struct comfront_info *)
+ (shost->hostdata);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_GET_HOST_PORT_ID;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt == 0) {
+ fc_host_port_id(shost) = ring_res->u.ghpi.port_id;
+ } else {
+ fc_host_port_id(shost) = (u32)0xffffffff;
+ }
+
+}
+
+static void fc_get_host_port_type(struct Scsi_Host *shost)
+{
+ struct comfront_info *cominfo = (struct comfront_info *)
+ (shost->hostdata);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_GET_HOST_PORT_TYPE;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt == 0) {
+ fc_host_port_type(shost) = ring_res->u.ghpt.port_type;
+ } else {
+ fc_host_port_type(shost) = (u32)0xffffffff;
+ }
+
+}
+
+static void fc_get_host_port_state(struct Scsi_Host *shost)
+{
+ struct comfront_info *cominfo = (struct comfront_info *)
+ (shost->hostdata);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_GET_HOST_PORT_STATE;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt == 0) {
+ fc_host_port_state(shost) = ring_res->u.ghps.port_state;
+ } else {
+ fc_host_port_state(shost) = (u32)0xffffffff;
+ }
+
+}
+
+static void fc_get_host_active_fc4s(struct Scsi_Host *shost)
+{
+ struct comfront_info *cominfo = (struct comfront_info *)
+ (shost->hostdata);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_GET_HOST_ACTIVE_FC4S;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt == 0) {
+ memcpy(fc_host_active_fc4s(shost),
+ ring_res->u.ghaf.active_fc4s,
+ sizeof(fc_host_active_fc4s(shost)));
+ } else {
+ memset(fc_host_active_fc4s(shost), 0,
+ sizeof(fc_host_active_fc4s(shost)));
+ }
+
+}
+
+static void fc_get_host_speed(struct Scsi_Host *shost)
+{
+ struct comfront_info *cominfo = (struct comfront_info *)
+ (shost->hostdata);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_GET_HOST_SPEED;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt == 0) {
+ fc_host_speed(shost) = ring_res->u.ghsp.speed;
+ } else {
+ fc_host_speed(shost) = (u32)0xffffffff;
+ }
+
+}
+
+static void fc_get_host_fabric_name(struct Scsi_Host *shost)
+{
+ struct comfront_info *cominfo = (struct comfront_info *)
+ (shost->hostdata);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_GET_HOST_FABRIC_NAME;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt == 0) {
+ fc_host_fabric_name(shost) = ring_res->u.ghfn.fabric_name;
+ } else {
+ fc_host_fabric_name(shost) = (u32)0xffffffff;
+ }
+
+}
+
+static struct fc_host_statistics * fc_get_stats(struct Scsi_Host *shost)
+{
+ struct comfront_info *cominfo = (struct comfront_info *)
+ (shost->hostdata);
+ struct fcfront_info *fcinfo = (struct fcfront_info *)
+ (cominfo->fcinfo);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+ struct fc_host_statistics *ret;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_GET_HOST_STATS;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt == 0) {
+ /* "info->hs" is appropriate position ? */
+ memcpy(&(fcinfo->hs), &(ring_res->u.ghst.stats),
+ sizeof(fcinfo->hs));
+ ret = &(ring_res->u.ghst.stats);
+ } else {
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+static void fc_reset_stats(struct Scsi_Host *shost)
+{
+ struct comfront_info *cominfo = (struct comfront_info *)
+ (shost->hostdata);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_RESET_HOST_STATS;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+}
+
+static int fc_issue_lip(struct Scsi_Host *shost)
+{
+ struct comfront_info *cominfo = (struct comfront_info *)
+ (shost->hostdata);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_ISSUE_HOST_LIP;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ return ring_res->rslt;
+}
+
+static void fc_get_starget_port_id(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct comfront_info *cominfo = (struct comfront_info *)
+ (shost->hostdata);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_GET_STARGET_PORT_ID;
+ ring_req->u.gtpi.channel = starget->channel;
+ ring_req->u.gtpi.id = starget->id;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt == 0) {
+ fc_starget_port_id(starget) = ring_res->u.gtpi.port_id;
+ } else {
+ fc_starget_port_id(starget) = (u32)0xffffffff;
+ }
+
+}
+
+static void fc_get_starget_node_name(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct comfront_info *cominfo = (struct comfront_info *)
+ (shost->hostdata);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_GET_STARGET_NODE_NAME;
+ ring_req->u.gtnn.channel = starget->channel;
+ ring_req->u.gtnn.id = starget->id;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt == 0) {
+ fc_starget_node_name(starget) = ring_res->u.gtnn.node_name;
+ } else {
+ fc_starget_node_name(starget) = (u32)0xffffffff;
+ }
+
+}
+
+static void fc_get_starget_port_name(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct comfront_info *cominfo = (struct comfront_info *)
+ (shost->hostdata);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_GET_STARGET_PORT_NAME;
+ ring_req->u.gtpn.channel = starget->channel;
+ ring_req->u.gtpn.id = starget->id;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt == 0) {
+ fc_starget_port_name(starget) = ring_res->u.gtpn.port_name;
+ } else {
+ fc_starget_port_name(starget) = (u32)0xffffffff;
+ }
+
+}
+
+static void fc_get_rport_loss_tmo(struct fc_rport *rport)
+{
+ struct Scsi_Host *shost = rport_to_shost(rport);
+ struct comfront_info *cominfo = (struct comfront_info *)
+ (shost->hostdata);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_GET_RPORT_LOSS_TMO;
+ ring_req->u.gplt.node_name = rport->node_name;
+ ring_req->u.gplt.port_name = rport->port_name;
+ ring_req->u.gplt.port_id = rport->port_id;
+ ring_req->u.gplt.roles = rport->roles;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt == 0) {
+ rport->dev_loss_tmo = ring_res->u.gplt.timeout;
+ } else {
+ rport->dev_loss_tmo = (u32)0xffffffff;
+ }
+
+}
+
+static void fc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+{
+ struct Scsi_Host *shost = rport_to_shost(rport);
+ struct comfront_info *cominfo = (struct comfront_info *)
+ (shost->hostdata);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_SET_RPORT_LOSS_TMO;
+ ring_req->u.splt.node_name = rport->node_name;
+ ring_req->u.splt.port_name = rport->port_name;
+ ring_req->u.splt.port_id = rport->port_id;
+ ring_req->u.splt.roles = rport->roles;
+ ring_req->u.splt.timeout = timeout;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt == 0) {
+ rport->dev_loss_tmo = ring_res->u.splt.timeout;
+ } else {
+ rport->dev_loss_tmo = (u32)0xffffffff;
+ }
+
+}
+
+struct fc_function_template fc_transport_functions = {
+ .get_rport_dev_loss_tmo = fc_get_rport_loss_tmo,
+ .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo,
+ .get_starget_node_name = fc_get_starget_node_name,
+ .get_starget_port_name = fc_get_starget_port_name,
+ .get_starget_port_id = fc_get_starget_port_id,
+ .get_host_port_id = fc_get_host_port_id,
+ .get_host_port_type = fc_get_host_port_type,
+ .get_host_port_state = fc_get_host_port_state,
+ .get_host_active_fc4s = fc_get_host_active_fc4s,
+ /* lpfc does not support */
+ .get_host_speed = fc_get_host_speed,
+ .get_host_fabric_name = fc_get_host_fabric_name,
+ .get_fc_host_stats = fc_get_stats,
+ .reset_fc_host_stats = fc_reset_stats,
+ .issue_fc_host_lip = fc_issue_lip,
+
+ /* remote port fixed attributes */
+ .show_rport_maxframe_size = 1,
+ .show_rport_supported_classes = 1,
+ .show_rport_dev_loss_tmo = 1,
+
+ /* target dynamic attributes */
+ .show_starget_node_name = 1,
+ .show_starget_port_name = 1,
+ .show_starget_port_id = 1,
+
+ /* host fixed attributes */
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+ .show_host_permanent_port_name = 1, /* lpfc does not support */
+ .show_host_supported_classes = 1,
+ .show_host_supported_fc4s = 1,
+ .show_host_symbolic_name = 1,
+ .show_host_supported_speeds = 1,
+ .show_host_maxframe_size = 1,
+ .show_host_serial_number = 1, /* lpfc does not support */
+
+ /* host dynamic attribute */
+ .show_host_port_id = 1,
+ .show_host_port_type = 1,
+ .show_host_port_state = 1,
+ .show_host_active_fc4s = 1,
+ .show_host_speed = 1,
+ .show_host_fabric_name = 1,
+};
+
+
+/* ---------------------------------------------------------------------- */
+
+static int __setup_grant_table(struct fcfront_info *info)
+{
+ void *addr;
+ int gntref;
+
+ if ((addr = kmalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) {
+ return -ENOMEM;
+ }
+
+ gntref = gnttab_grant_foreign_access(info->cominfo->dev->otherend_id,
+ virt_to_mfn(addr), 0);
+ if (gntref < 0) {
+ printk(KERN_ERR
+ "fcfront: %s: gnttab_grant_foreign_access() error\n",
+ __FUNCTION__);
+ return gntref;
+ }
+
+ info->addr = addr;
+ info->gntref = gntref;
+
+ return 0;
+}
+
+static void __unsetup_grant_table(struct fcfront_info *info)
+{
+ /* currently, nothing to do */
+}
+
+static int __setup_xenstore(struct fcfront_info *info)
+{
+ struct xenbus_device *dev = info->cominfo->dev;
+ struct xenbus_transaction xbt;
+ int ret = 0;
+
+again:
+ if ((ret = xenbus_transaction_start(&xbt)) != 0) {
+ printk(KERN_ERR
+ "fcfront: %s: xenbus_transaction_start() error\n",
+ __FUNCTION__);
+ goto out0;
+ }
+
+ if ((ret = xenbus_printf(xbt, dev->nodename,
+ "fc_gntref", "%d", info->gntref)) != 0) {
+ printk(KERN_ERR "fcfront: %s: xenbus_printf() error\n",
+ __FUNCTION__);
+ goto out1;
+ }
+
+ if ((ret = xenbus_transaction_end(xbt, 0)) != 0) {
+ if (ret == -EAGAIN) {
+ goto again;
+ } else {
+ printk(KERN_ERR
+ "fcfront: %s: xenbus_transaction_end() error\n",
+ __FUNCTION__);
+ goto out0;
+ }
+ }
+
+ return 0;
+
+out1:
+ (void)xenbus_transaction_end(xbt, 0);
+
+out0:
+ return ret;
+}
+
+static void __unsetup_xenstore(struct fcfront_info *info)
+{
+ /* currently, nothing to do */
+}
+
+int fcfront_connection_setup(struct comfront_info *cominfo)
+{
+ struct fcfront_info *info;
+ int ret;
+
+#if 0 /* for DEBUG */
+ printk(KERN_ERR "%s: giha=%ld\n", sizeof(struct giha), __FUNCTION__);
+ printk(KERN_ERR "%s: gita=%ld\n", sizeof(struct gita), __FUNCTION__);
+ printk(KERN_ERR "%s: gipa=%ld\n", sizeof(struct gipa), __FUNCTION__);
+ printk(KERN_ERR "%s: gftp=%ld\n", sizeof(struct gftp), __FUNCTION__);
+#endif
+
+ {
+ cominfo->fcinfo = kmalloc(sizeof(struct fcfront_info),
+ GFP_KERNEL);
+ if (cominfo->fcinfo == NULL) {
+ ret = -ENOMEM;
+ goto out0;
+ }
+ memset(cominfo->fcinfo, 0, sizeof(struct fcfront_info));
+ info = (struct fcfront_info *)(cominfo->fcinfo);
+ info->cominfo = cominfo;
+ }
+
+ /* prepare for grant table */
+ if ((ret = __setup_grant_table(info)) != 0) {
+ printk(KERN_ERR "fcfront: %s: __setup_grant_table() error\n",
+ __FUNCTION__);
+ goto out1;
+ }
+
+ /* exchange various parameters through xenstore */
+ if ((ret = __setup_xenstore(info)) != 0) {
+ printk(KERN_ERR "fcfront: %s: "
+ "__setup_xenstore() error\n", __FUNCTION__);
+ goto out2;
+ }
+
+ return 0;
+
+out2:
+ __unsetup_grant_table(info);
+
+out1:
+ kfree(cominfo->fcinfo);
+
+out0:
+ return ret;
+}
+
+void fcfront_connection_unsetup(struct comfront_info *cominfo)
+{
+ struct fcfront_info *info = (struct fcfront_info *)(cominfo->fcinfo);
+
+ __unsetup_xenstore(info);
+ __unsetup_grant_table(info);
+
+ kfree(cominfo->fcinfo);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+static int __get_host_attrib(struct comfront_info *cominfo)
+{
+ struct fcfront_info *fcinfo = (struct fcfront_info *)(cominfo->fcinfo);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+ struct fc_host_attrs *host_attrs =
+ (struct fc_host_attrs *)(cominfo->host->shost_data);
+ struct giha *giha = (struct giha *)(fcinfo->addr);
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_GET_INITIAL_SHOST_ATTRIB;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt != 0) {
+ return 0;
+ }
+
+ memcpy(host_attrs->active_fc4s, giha->active_fc4s,
+ sizeof(host_attrs->active_fc4s));
+ host_attrs->fabric_name = giha->fabric_name;
+ host_attrs->maxframe_size = giha->maxframe_size;
+ host_attrs->node_name = giha->node_name;
+ host_attrs->permanent_port_name = giha->permanent_port_name;
+ host_attrs->port_id = giha->port_id;
+ host_attrs->port_name = giha->port_name;
+ host_attrs->port_state = giha->port_state;
+ host_attrs->port_type = giha->port_type;
+ memcpy(host_attrs->serial_number, giha->serial_number,
+ sizeof(host_attrs->serial_number));
+ host_attrs->speed = giha->speed;
+ /* "fcinfo->hs" is appropriate position ? */
+ memcpy(&(fcinfo->hs), &(giha->stats), sizeof(fcinfo->hs));
+ host_attrs->supported_classes = giha->supported_classes;
+ memcpy(host_attrs->supported_fc4s, giha->supported_fc4s,
+ sizeof(host_attrs->supported_fc4s));
+ host_attrs->supported_speeds = giha->supported_speeds;
+ memcpy(host_attrs->symbolic_name, giha->symbolic_name,
+ sizeof(host_attrs->symbolic_name));
+ host_attrs->tgtid_bind_type = giha->tgtid_bind_type;
+
+ return 0;
+}
+
+static int __get_target_attrib(struct comfront_info *cominfo)
+{
+ struct fcfront_info *fcinfo = (struct fcfront_info *)(cominfo->fcinfo);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+ struct scsi_target *starget;
+ struct fc_starget_attrs *starget_attrs;
+ struct gita *gita = (struct gita *)(fcinfo->addr);
+ unsigned int i;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_GET_INITIAL_STARGET_ATTRIB;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt != 0) {
+ return 0;
+ }
+
+ for (i = 0; i < gita->num; i++) {
+ list_for_each_entry(starget, &(cominfo->host->__targets),
+ siblings) {
+ starget_attrs = (struct fc_starget_attrs *)
+ (&(starget->starget_data));
+ if ((starget->channel == gita->e[i].channel) &&
+ (starget->id == gita->e[i].id)) {
+ starget_attrs->node_name =
+ gita->e[i].node_name;
+ starget_attrs->port_id =
+ gita->e[i].port_id;
+ starget_attrs->port_name =
+ gita->e[i].port_name;
+ break;
+ } else {
+ /* printk(KERN_ERR
+ "fcfront: %s: SCSI target not added\n",
+ __FUNCTION__);*/
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int __get_port_attrib(struct comfront_info *cominfo)
+{
+ struct fcfront_info *fcinfo = (struct fcfront_info *)(cominfo->fcinfo);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+ int channel;
+ struct fc_rport_identifiers ids;
+ struct fc_rport *rport;
+ struct gipa *gipa = (struct gipa *)(fcinfo->addr);
+ unsigned int i;
+ int ret = 0;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_GET_INITIAL_RPORT_ATTRIB;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt != 0) {
+ return ret;
+ }
+
+ for (i = 0; i < gipa->num; i++) {
+ channel = gipa->e[i].channel;
+ ids.node_name = gipa->e[i].node_name;
+ ids.port_id = gipa->e[i].port_id;
+ ids.port_name = gipa->e[i].port_name;
+ ids.roles = gipa->e[i].roles;
+
+ rport = fc_remote_port_add(cominfo->host, channel, &ids);
+ if (rport == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ rport->dev_loss_tmo = gipa->e[i].dev_loss_tmo;
+ rport->maxframe_size = gipa->e[i].maxframe_size;
+ rport->port_state = gipa->e[i].port_state;
+ rport->scsi_target_id = gipa->e[i].scsi_target_id;
+ rport->supported_classes = gipa->e[i].supported_classes;
+ }
+
+ return ret;
+}
+
+int fcfront_get_initial_attribute(struct comfront_info *cominfo)
+{
+ int ret = 0;
+
+ /* get SCSI host attributes */
+ (void)__get_host_attrib(cominfo);
+
+ /* get SCSI target attributes */
+ (void)__get_target_attrib(cominfo);
+
+ /* get remote port attibutes */
+ ret = __get_port_attrib(cominfo);
+
+ return ret;
+}
+
+#define CORRECT_FT(s, f, v, d) \
+ if (((s)->f) == (v)) { \
+ (d)->f = (v); \
+ }
+
+int fcfront_get_function_template(struct comfront_info *cominfo)
+{
+ struct fcfront_info *fcinfo = (struct fcfront_info *)(cominfo->fcinfo);
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+ struct gftp *gftp = (struct gftp *)(fcinfo->addr);
+ struct fc_function_template_shared *ft = &(gftp->ft);
+ struct fc_function_template *pvfcft = &fc_transport_functions;
+
+ ring_req = comfront_pre_request(cominfo);
+
+ ring_req->cmnd = CMND_GET_FUNCTION_TEMPLATE;
+
+ ring_res = comfront_do_request_and_wait_response(cominfo, ring_req);
+
+ if (ring_res->rslt == 0) {
+
+ CORRECT_FT(ft, get_rport_dev_loss_tmo, 0, pvfcft);
+ CORRECT_FT(ft, set_rport_dev_loss_tmo, 0, pvfcft);
+ CORRECT_FT(ft, get_starget_node_name, 0, pvfcft);
+ CORRECT_FT(ft, get_starget_port_name, 0, pvfcft);
+ CORRECT_FT(ft, get_starget_port_id, 0, pvfcft);
+ CORRECT_FT(ft, get_host_port_id, 0, pvfcft);
+ CORRECT_FT(ft, get_host_port_type, 0, pvfcft);
+ CORRECT_FT(ft, get_host_port_state, 0, pvfcft);
+ CORRECT_FT(ft, get_host_active_fc4s, 0, pvfcft);
+ CORRECT_FT(ft, get_host_speed, 0, pvfcft);
+ CORRECT_FT(ft, get_host_fabric_name, 0, pvfcft);
+ CORRECT_FT(ft, get_fc_host_stats, 0, pvfcft);
+ CORRECT_FT(ft, reset_fc_host_stats, 0, pvfcft);
+ CORRECT_FT(ft, issue_fc_host_lip, 0, pvfcft);
+
+ pvfcft->dd_fcrport_size = ft->dd_fcrport_size;
+
+ CORRECT_FT(ft, show_rport_maxframe_size, 0, pvfcft);
+ CORRECT_FT(ft, show_rport_supported_classes, 0, pvfcft);
+ CORRECT_FT(ft, show_rport_dev_loss_tmo, 0, pvfcft);
+ CORRECT_FT(ft, show_starget_node_name, 0, pvfcft);
+ CORRECT_FT(ft, show_starget_port_name, 0, pvfcft);
+ CORRECT_FT(ft, show_starget_port_id, 0, pvfcft);
+ CORRECT_FT(ft, show_host_node_name, 0, pvfcft);
+ CORRECT_FT(ft, show_host_port_name, 0, pvfcft);
+ CORRECT_FT(ft, show_host_permanent_port_name, 0, pvfcft);
+ CORRECT_FT(ft, show_host_supported_classes, 0, pvfcft);
+ CORRECT_FT(ft, show_host_supported_fc4s, 0, pvfcft);
+ CORRECT_FT(ft, show_host_symbolic_name, 0, pvfcft);
+ CORRECT_FT(ft, show_host_supported_speeds, 0, pvfcft);
+ CORRECT_FT(ft, show_host_maxframe_size, 0, pvfcft);
+ CORRECT_FT(ft, show_host_serial_number, 0, pvfcft);
+ CORRECT_FT(ft, show_host_port_id, 0, pvfcft);
+ CORRECT_FT(ft, show_host_port_type, 0, pvfcft);
+ CORRECT_FT(ft, show_host_port_state, 0, pvfcft);
+ CORRECT_FT(ft, show_host_active_fc4s, 0, pvfcft);
+ CORRECT_FT(ft, show_host_speed, 0, pvfcft);
+ CORRECT_FT(ft, show_host_fabric_name, 0, pvfcft);
+ }
+
+ return 0;
+}
+
+MODULE_DESCRIPTION("Xen Para-Virtual SCSI Fibre Channel Frontend Driver");
+MODULE_LICENSE("GPL");
diff -r 709db80c03c3 -r 24e0cb9fe9df drivers/xen/scsifront/fcfront.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/fcfront.h Tue Oct 30 16:41:36 2007 +0900
@@ -0,0 +1,179 @@
+/*
+ * Xen SCSI frontend driver
+ *
+ * Copyright (c) 2007, FUJITSU Limited
+ *
+ * Based on the scsifront driver code by FUJITA Tomonori
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+#ifndef __XEN_DRIVERS_FCFRONT_H__
+#define __XEN_DRIVERS_FCFRONT_H__
+
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_fc.h>
+
+/* ----------------------------------------------------------------------
+ Definition of Grant Table Structures
+ ---------------------------------------------------------------------- */
+
+#define SCSI_FC_MAX_STARGET 32 /* limited by PAGE_SIZE */
+#define SCSI_FC_MAX_RPORT 32 /* limited by PAGE_SIZE */
+
+struct giha {
+ u8 active_fc4s[FC_FC4_LIST_SIZE];
+ u64 fabric_name;
+ u64 node_name;
+ u64 permanent_port_name;
+ u32 maxframe_size;
+ u32 port_id;
+ u64 port_name;
+ enum fc_port_state port_state;
+ enum fc_port_type port_type;
+ char serial_number[FC_SERIAL_NUMBER_SIZE];
+ struct fc_host_statistics stats;
+ u32 speed;
+ u32 supported_classes;
+ u8 supported_fc4s[FC_FC4_LIST_SIZE];
+ char symbolic_name[FC_SYMBOLIC_NAME_SIZE];
+ u32 supported_speeds;
+ enum fc_tgtid_binding_type tgtid_bind_type;
+};
+
+struct gita {
+ u32 num;
+ u32 padding1;
+ struct {
+ u64 node_name;
+ u64 port_name;
+ u32 port_id;
+ u32 channel;
+ u32 id;
+ u32 padding2;
+ } e[SCSI_FC_MAX_STARGET];
+};
+
+struct gipa {
+ u32 num;
+ u32 padding1;
+ struct {
+ u32 dev_loss_tmo;
+ u32 maxframe_size;
+ u64 node_name;
+ u64 port_name;
+ u32 port_id;
+ enum fc_port_state port_state;
+ u32 roles;
+ u32 scsi_target_id;
+ u32 supported_classes;
+ u32 channel;
+ } e[SCSI_FC_MAX_RPORT];
+};
+
+struct fc_function_template_shared {
+ u64 get_rport_dev_loss_tmo:1;
+ u64 set_rport_dev_loss_tmo:1;
+ u64 get_starget_node_name:1;
+ u64 get_starget_port_name:1;
+ u64 get_starget_port_id:1;
+ u64 get_host_port_id:1;
+ u64 get_host_port_type:1;
+ u64 get_host_port_state:1;
+ u64 get_host_active_fc4s:1;
+ u64 get_host_speed:1;
+ u64 get_host_fabric_name:1;
+ u64 get_fc_host_stats:1;
+ u64 reset_fc_host_stats:1;
+ u64 issue_fc_host_lip:1;
+ u64 padding1:50;
+
+ u64 show_rport_maxframe_size:1;
+ u64 show_rport_supported_classes:1;
+ u64 show_rport_dev_loss_tmo:1;
+ u64 show_starget_node_name:1;
+ u64 show_starget_port_name:1;
+ u64 show_starget_port_id:1;
+ u64 show_host_node_name:1;
+ u64 show_host_port_name:1;
+ u64 show_host_permanent_port_name:1;
+ u64 show_host_supported_classes:1;
+ u64 show_host_supported_fc4s:1;
+ u64 show_host_symbolic_name:1;
+ u64 show_host_supported_speeds:1;
+ u64 show_host_maxframe_size:1;
+ u64 show_host_serial_number:1;
+ u64 show_host_port_id:1;
+ u64 show_host_port_type:1;
+ u64 show_host_port_state:1;
+ u64 show_host_active_fc4s:1;
+ u64 show_host_speed:1;
+ u64 show_host_fabric_name:1;
+ u64 padding2:43;
+
+ u32 dd_fcrport_size;
+ u32 padding3;
+};
+
+struct gftp {
+ struct fc_function_template_shared ft;
+};
+
+
+/* ----------------------------------------------------------------------
+ Definition of Internal Information Structures
+ ---------------------------------------------------------------------- */
+
+struct fcfront_info {
+ struct comfront_info *cominfo;
+
+ int gntref;
+ void *addr;
+
+ /* On backend, "hs" is stored in ***_hba */
+ struct fc_host_statistics hs;
+};
+
+struct fcback_info {
+ struct comback_info *cominfo;
+
+ int gntref;
+ struct vm_struct *gnt_area;
+
+ struct vscsiif_ftb_request ftb_req;
+};
+
+
+/* ----------------------------------------------------------------------
+ Definition of Front/Back common functions
+ ---------------------------------------------------------------------- */
+
+struct fc_internal_head {
+ struct scsi_transport_template t;
+ struct fc_function_template *f;
+};
+
+#endif /*__XEN_DRIVERS_FCFRONT_H__*/
diff -r 709db80c03c3 -r 24e0cb9fe9df drivers/xen/scsifront/scsifront.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/scsifront.c Tue Oct 30 16:41:36 2007 +0900
@@ -0,0 +1,739 @@
+/*
+ * Xen SCSI frontend driver
+ *
+ * Copyright (c) 2007, FUJITSU Limited
+ *
+ * Based on the scsifront driver code by FUJITA Tomonori
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+#include <linux/version.h>
+#include "comfront.h"
+
+
+#define DEFAULT_CMD_PER_LUN 10
+#define DEFAULT_TASK_COMM_LEN 16
+
+extern int scsi_trace_init(void);
+extern void scsi_trace(unsigned long, unsigned char *, unsigned int);
+
+static int req_per_lun = DEFAULT_CMD_PER_LUN;
+module_param_named(cmds_lun, req_per_lun, int, 0);
+MODULE_PARM_DESC(reqs, "Number of lun requests to allocate");
+
+#ifdef CONFIG_XEN_FC
+extern struct fc_function_template fc_transport_functions;
+static struct scsi_transport_template * fc_transport_template = NULL;
+#endif
+extern int read_ftb_ring_resp_cons(struct comfront_info *info);
+
+static void scsifront_free(struct comfront_info *info)
+{
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+ if (info->host->shost_state != SHOST_DEL) {
+#else
+ if (!test_bit(SHOST_DEL, &info->host->shost_state)) {
+#endif
+
+#ifdef CONFIG_XEN_FC
+ fc_remove_host(info->host);
+#endif
+ scsi_remove_host(info->host);
+ scsi_host_put(info->host);
+ }
+
+ flush_scheduled_work();
+
+ if (info->ftb_ring_ref != GRANT_INVALID_REF) {
+ gnttab_end_foreign_access(info->ftb_ring_ref, 0,
+ (unsigned long)info->ftb_ring.sring);
+ info->ftb_ring_ref = GRANT_INVALID_REF;
+ info->ftb_ring.sring = NULL;
+ }
+
+ if (info->btf_ring_ref != GRANT_INVALID_REF) {
+ gnttab_end_foreign_access(info->btf_ring_ref, 0,
+ (unsigned long)info->btf_ring.sring);
+ info->btf_ring_ref = GRANT_INVALID_REF;
+ info->btf_ring.sring = NULL;
+ }
+
+ if (info->irq)
+ unbind_from_irqhandler(info->irq, info);
+ info->irq = 0;
+}
+
+
+static int map_data_for_request(struct comfront_info *info,
+ struct scsi_cmnd *sc, struct vscsiif_ftb_request *ftb_req, uint32_t id)
+{
+ grant_ref_t gref_head;
+ struct page *page;
+ int err, i, ref, ref_cnt = 0;
+ int write = (sc->sc_data_direction == DMA_TO_DEVICE);
+ int nr_pages, off, len, bytes;
+ unsigned long buffer_pfn;
+
+ if (sc->sc_data_direction == DMA_NONE)
+ return 0;
+
+ err = gnttab_alloc_grant_references(SG_TABLESIZE, &gref_head);
+ if (err) {
+ printk(KERN_ERR "scsifront: gnttab_alloc_grant_references() error\n");
+ return -ENOMEM;
+ }
+
+ if (sc->use_sg) {
+ /* quoted scsi_lib.c/scsi_req_map_sg . */
+ struct scatterlist *sg = (struct scatterlist *)sc->request_buffer;
+ unsigned int data_len = 0;
+ nr_pages = (sc->request_bufflen + sg[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ if (nr_pages > SG_TABLESIZE) {
+ ref_cnt = (-ENOMEM);
+ goto big_to_sg;
+ }
+
+ for (i = 0; i < sc->use_sg; i++) {
+ page = sg[i].page;
+ off = sg[i].offset;
+ len = sg[i].length;
+ data_len += len;
+
+ buffer_pfn = page_to_phys(page) >> PAGE_SHIFT;
+
+ while (len > 0) {
+ bytes = min_t(unsigned int, len, PAGE_SIZE - off);
+
+ ref = gnttab_claim_grant_reference(&gref_head);
+ BUG_ON(ref == -ENOSPC); /*FIXME*/
+
+ gnttab_grant_foreign_access_ref(ref, info->dev->otherend_id,
+ buffer_pfn, write);
+
+ info->shadow[id].u.scsi.gref[ref_cnt] = ref;
+ ftb_req->u.scsi.seg[ref_cnt].gref = ref;
+ ftb_req->u.scsi.seg[ref_cnt].offset = off;
+ ftb_req->u.scsi.seg[ref_cnt].length = bytes;
+
+ buffer_pfn++;
+ len -= bytes;
+ off = 0;
+ ref_cnt++;
+ }
+ }
+ } else if (sc->request_bufflen) {
+ unsigned long end = ((unsigned long)sc->request_buffer
+ + sc->request_bufflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ unsigned long start = (unsigned long)sc->request_buffer >> PAGE_SHIFT;
+
+ page = virt_to_page(sc->request_buffer);
+ nr_pages = end - start;
+ len = sc->request_bufflen;
+
+ if (nr_pages > SG_TABLESIZE) {
+ ref_cnt = (-ENOMEM);
+ goto big_to_sg;
+ }
+
+ buffer_pfn = page_to_phys(page) >> PAGE_SHIFT;
+
+ off = offset_in_page((unsigned long)sc->request_buffer);
+ for (i = 0; i < nr_pages; i++) {
+ bytes = PAGE_SIZE - off;
+
+ if (bytes > len)
+ bytes = len;
+
+ ref = gnttab_claim_grant_reference(&gref_head);
+ BUG_ON(ref == -ENOSPC); /*FIXME*/
+
+ gnttab_grant_foreign_access_ref(ref, info->dev->otherend_id,
+ buffer_pfn, write);
+
+ info->shadow[id].u.scsi.gref[i] = ref;
+ ftb_req->u.scsi.seg[i].gref = ref;
+ ftb_req->u.scsi.seg[i].offset = off;
+ ftb_req->u.scsi.seg[i].length = bytes;
+
+/* page = pfn_to_page(++buffer_mfn);*/
+ buffer_pfn++;
+ len -= bytes;
+ off = 0;
+ ref_cnt++;
+ }
+ }
+
+big_to_sg:
+
+ gnttab_free_grant_references(gref_head);
+
+ return ref_cnt;
+}
+
+static int scsifront_queuecommand(struct scsi_cmnd *sc,
+ void (*done)(struct scsi_cmnd *))
+{
+ struct Scsi_Host *host = sc->device->host;
+ struct comfront_info *info = (struct comfront_info *) host->hostdata;
+ struct vscsiif_ftb_request *ftb_req;
+ int ref_cnt;
+
+ if (info->dev->state != XenbusStateConnected) {
+ printk(KERN_ERR "scsifront: XenbusState not connected %u!\n",
+ info->dev->state);
+ sc->result = DID_NO_CONNECT << 16;
+ done(sc);
+ return 0;
+ }
+
+ if (RING_FULL(&info->ftb_ring)) {
+ /*printk(KERN_INFO "scsifront: FTB Ring Full busy\n");*/
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ if (read_ftb_ring_resp_cons(info)) {
+ /*printk("scsifront: BTF Ring Full busy\n");*/
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ sc->scsi_done = done;
+ sc->result = 0;
+
+ ftb_req = comfront_pre_request(info);
+ ftb_req->cmnd = CMND_SCSI;
+
+ ftb_req->u.scsi.id = sc->device->id;
+ ftb_req->u.scsi.lun = sc->device->lun;
+ ftb_req->u.scsi.channel = sc->device->channel;
+ ftb_req->u.scsi.cmd_len = sc->cmd_len;
+
+ BUG_ON(sc->cmd_len > VSCSI_MAX_COMMAND_SIZE);
+ BUG_ON(sc == NULL);
+
+ if ( sc->cmd_len )
+ memcpy(ftb_req->u.scsi.cmnd, sc->cmnd, sc->cmd_len);
+ else
+ memset(ftb_req->u.scsi.cmnd, 0, VSCSI_MAX_COMMAND_SIZE);
+
+ ftb_req->u.scsi.sc_data_direction = sc->sc_data_direction;
+ ftb_req->u.scsi.request_bufflen = sc->request_bufflen;
+ ftb_req->u.scsi.timeout_per_command = sc->timeout_per_command;
+
+ info->shadow[ftb_req->rqid].u.scsi.req_scsi_cmnd = (unsigned long)sc;
+ info->shadow[ftb_req->rqid].u.scsi.sc_data_direction
+ = sc->sc_data_direction;
+ info->shadow[ftb_req->rqid].u.scsi.request_bufflen
+ = sc->request_bufflen;
+ info->shadow[ftb_req->rqid].cmnd = ftb_req->cmnd;
+
+ ref_cnt = map_data_for_request(info, sc, ftb_req, ftb_req->rqid);
+ if (unlikely(ref_cnt < 0)) {
+ ADD_ID_TO_FREELIST(info, ftb_req->rqid);
+ notify_remote_via_irq(info->irq);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ ftb_req->u.scsi.use_sg = ref_cnt;
+ info->shadow[ftb_req->rqid].u.scsi.use_sg = ref_cnt;
+
+ scsi_trace(1, (unsigned char *)ftb_req,
+ sizeof(struct vscsiif_ftb_request));
+
+ comfront_do_request(info);
+
+ return 0;
+}
+
+
+static int scsifront_eh_abort_handler(struct scsi_cmnd *sc)
+{
+ /* not implemented */
+ printk(KERN_ERR "scsifront: abort! 0 return.\n");
+ return (FAILED);
+}
+
+
+static int scsifront_eh_host_reset_handler(struct scsi_cmnd *sc)
+{
+ struct Scsi_Host *host = sc->device->host;
+ struct comfront_info *info = (struct comfront_info *) host->hostdata;
+ struct vscsiif_ftb_request *ring_req;
+ struct vscsiif_btf_request *ring_res;
+ int err = FAILED;
+
+ printk(KERN_INFO "scsifront: reset.\n");
+
+ scsi_block_requests(host);
+
+ ring_req = comfront_pre_request(info);
+
+ ring_req->cmnd = CMND_SCSI_RESET;
+ ring_req->u.scsi.id = sc->device->id;
+ ring_req->u.scsi.lun = sc->device->lun;
+ ring_req->u.scsi.channel = sc->device->channel;
+
+ spin_unlock_irq(info->host->host_lock);
+
+ ring_res = comfront_do_request_and_wait_response(info, ring_req);
+
+ err = (ring_res->rslt ? SUCCESS : FAILED);
+
+ scsi_unblock_requests(host);
+
+ return (err);
+}
+
+
+static void scsifront_gnttab_done(struct comfront_shadow *s, uint32_t id)
+{
+ int i;
+
+ if (s->u.scsi.sc_data_direction == DMA_NONE)
+ return;
+
+ if (s->u.scsi.use_sg) {
+ for (i = 0; i < s->u.scsi.use_sg; i++) {
+ if (unlikely(gnttab_query_foreign_access(
+ s->u.scsi.gref[i]) != 0)) {
+ printk(KERN_ALERT "scsifront: "
+ "grant still in use by backend.\n");
+ BUG();
+ }
+ gnttab_end_foreign_access(s->u.scsi.gref[i], 0, 0UL);
+ }
+ } else if (s->u.scsi.request_bufflen) {
+ gnttab_end_foreign_access(s->u.scsi.gref[0], 0, 0UL);
+ } else {
+ return;
+ }
+}
+
+
+int scsifront_cmd_done(struct comfront_info *info,
+ struct vscsiif_btf_request *btf_req)
+{
+ struct scsi_cmnd *sc;
+ uint32_t id;
+
+ id = btf_req->rqid;
+ sc = (struct scsi_cmnd *)info->shadow[id].u.scsi.req_scsi_cmnd;
+
+ if (sc == NULL)
+ return 1;
+
+ scsifront_gnttab_done(&info->shadow[id], id);
+ ADD_ID_TO_FREELIST(info, id);
+
+ sc->result = btf_req->rslt;
+ sc->resid = 0;
+
+ BUG_ON(btf_req->u.scsi.sense_len > SCSI_SENSE_BUFFERSIZE);
+
+ if( btf_req->rslt != 0 ) {
+ if (btf_req->u.scsi.sense_len)
+ memcpy(sc->sense_buffer, btf_req->u.scsi.sense_buffer,
+ btf_req->u.scsi.sense_len);
+ }
+
+ sc->scsi_done(sc);
+
+ return 0;
+}
+
+
+static int scsifront_alloc_ring(struct comfront_info *info)
+{
+ struct xenbus_device *dev = info->dev;
+ struct vscsiif_ftb_sring *ftb;
+ struct vscsiif_btf_sring *btf;
+ int err = -ENOMEM;
+
+ info->ftb_ring_ref = GRANT_INVALID_REF;
+ info->btf_ring_ref = GRANT_INVALID_REF;
+
+ /***** Frontend to Backend ring start *****/
+ ftb = (struct vscsiif_ftb_sring *) __get_free_page(GFP_KERNEL);
+ if (!ftb) {
+ xenbus_dev_fatal(dev, err, "fail to allocate shared ring (Front to Back)");
+ return err;
+ }
+ SHARED_RING_INIT(ftb);
+ FRONT_RING_INIT(&info->ftb_ring, ftb, PAGE_SIZE);
+
+ err = xenbus_grant_ring(dev, virt_to_mfn(ftb));
+ if (err < 0) {
+ free_page((unsigned long) ftb);
+ info->ftb_ring.sring = NULL;
+ xenbus_dev_fatal(dev, err, "fail to grant shared ring (Front to Back)");
+ goto free_sring;
+ }
+ info->ftb_ring_ref = err;
+
+ /***** Backend to Frontend ring start *****/
+ btf = (struct vscsiif_btf_sring *) __get_free_page(GFP_KERNEL);
+ if (!btf) {
+ xenbus_dev_fatal(dev, err, "fail to allocate shared ring (Back to Front)");
+ return err;
+ }
+ SHARED_RING_INIT(btf);
+ BACK_RING_INIT(&info->btf_ring, btf, PAGE_SIZE);
+
+ err = xenbus_grant_ring(dev, virt_to_mfn(btf));
+ if (err < 0) {
+ free_page((unsigned long) btf);
+ info->btf_ring.sring = NULL;
+ xenbus_dev_fatal(dev, err, "fail to grant shared ring (Back to Front)");
+ goto free_sring;
+ }
+ info->btf_ring_ref = err;
+
+ err = bind_listening_port_to_irqhandler(
+ dev->otherend_id, comfront_intr,
+ SA_SAMPLE_RANDOM, "scsifront", info);
+
+ if (err <= 0) {
+ xenbus_dev_fatal(dev, err, "bind_listening_port_to_irqhandler");
+ goto fail;
+ }
+ info->irq = err;
+
+ return 0;
+fail:
+ /* free resource */
+free_sring:
+ scsifront_free(info);
+
+ return err;
+}
+
+static int scsifront_init_ring(struct comfront_info *info)
+{
+ struct xenbus_device *dev = info->dev;
+ struct xenbus_transaction xbt;
+ int err;
+
+ DPRINTK("%s\n",__FUNCTION__);
+
+ err = scsifront_alloc_ring(info);
+ if (err)
+ return err;
+ DPRINTK("%u %u %u\n", info->ftb_ring_ref, info->ftb_ring_ref, info->evtchn);
+
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "starting transaction");
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "ftb-ring-ref", "%u",
+ info->ftb_ring_ref);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "%s", "writing ftb-ring-ref");
+ goto fail;
+ }
+ err = xenbus_printf(xbt, dev->nodename, "btf-ring-ref", "%u",
+ info->btf_ring_ref);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "%s", "writing btf-ring-ref");
+ goto fail;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+ irq_to_evtchn_port(info->irq));
+
+ if (err) {
+ xenbus_dev_fatal(dev, err, "%s", "writing event-channel");
+ goto fail;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "vhostno", "%d",
+ info->host->host_no);
+
+ if (err) {
+ xenbus_dev_fatal(dev, err, "%s", "writing event-channel");
+ goto fail;
+ }
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err) {
+ if (err == -EAGAIN)
+ goto again;
+ xenbus_dev_fatal(dev, err, "completing transaction");
+ } else
+ xenbus_switch_state(dev, XenbusStateInitialised);
+
+ return 0;
+fail:
+ xenbus_transaction_end(xbt, 1);
+ /* free resource */
+ scsifront_free(info);
+
+ return err;
+}
+
+static struct scsi_host_template scsifront_sht = {
+ .module = THIS_MODULE,
+ .name = "Xen SCSI frontend driver",
+ .queuecommand = scsifront_queuecommand,
+ .eh_abort_handler = scsifront_eh_abort_handler,
+ .eh_host_reset_handler = scsifront_eh_host_reset_handler,
+ .cmd_per_lun = DEFAULT_CMD_PER_LUN,
+ .can_queue = 16,
+ .this_id = -1,
+ .sg_tablesize = SG_TABLESIZE,
+ .use_clustering = DISABLE_CLUSTERING,
+ .proc_name = "scsifront",
+};
+
+static int scsifront_connect(struct comfront_info *info)
+{
+ struct xenbus_device *dev = info->dev;
+ struct Scsi_Host *host = info->host;
+
+ int err = -ENOMEM;
+
+ DPRINTK("%u\n", dev->state);
+ if (dev->state == XenbusStateConnected)
+ return 0;
+
+ xenbus_switch_state(dev, XenbusStateConnected);
+
+#ifdef CONFIG_XEN_FC
+ (void)fcfront_get_function_template(info);
+
+ fc_transport_template = fc_attach_transport(&fc_transport_functions);
+ host->transportt = fc_transport_template;
+#endif
+ /* FIXME */
+ host->max_id = 64;
+ host->max_channel = 0;
+ host->max_lun = 128;
+ host->max_sectors = (SG_TABLESIZE * PAGE_SIZE / 512);
+ host->cmd_per_lun = req_per_lun;
+
+ err = scsi_add_host(host, &dev->dev);
+ if (err) {
+ printk(KERN_ERR "scsifront: fail to add scsi host %d\n", err);
+ return err;
+ }
+
+ scsi_scan_host(host);
+
+#ifdef CONFIG_XEN_FC
+ (void)fcfront_get_initial_attribute(info);
+#endif
+
+ return 0;
+}
+
+static int scsifront_disconnect(struct comfront_info *info)
+{
+ struct xenbus_device *dev = info->dev;
+
+ DPRINTK("%s: %s remove\n",__FUNCTION__ ,dev->nodename);
+
+#ifdef CONFIG_XEN_FC
+ fc_remove_host(info->host);
+#endif
+ scsi_remove_host(info->host);
+ scsi_host_put(info->host);
+
+ xenbus_frontend_closed(dev);
+
+ return 0;
+}
+
+static int scsifront_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ struct Scsi_Host *host;
+ struct comfront_info *info;
+ int i, err = -ENOMEM;
+ char name[DEFAULT_TASK_COMM_LEN];
+
+ host = scsi_host_alloc(&scsifront_sht, sizeof(*info));
+ if (!host) {
+ xenbus_dev_fatal(dev, err, "fail to allocate scsi host");
+ return err;
+ }
+ info = (struct comfront_info *) host->hostdata;
+ dev->dev.driver_data = info;
+ info->dev = dev;
+ info->host = host;
+
+ for (i = 0; i < DEFAULT_CAN_QUEUE; i++) {
+ info->shadow[i].rqid = i + 1;
+ init_waitqueue_head(&(info->shadow[i].wq));
+ info->shadow[i].cond = 0;
+ }
+ info->shadow[DEFAULT_CAN_QUEUE - 1].rqid = 0x0fffffff;
+
+#ifdef CONFIG_XEN_FC
+ if ((err = fcfront_connection_setup(info)) != 0) {
+ printk(KERN_ERR
+ "scsifront: %s: fcfront_connection_setup() error\n",
+ __FUNCTION__);
+ return err;
+ }
+#endif
+
+ err = scsifront_init_ring(info);
+ if (err) {
+ scsi_host_put(host);
+ return err;
+ }
+
+ init_waitqueue_head(&info->wq);
+ spin_lock_init(&info->io_lock);
+ spin_lock_init(&info->shadow_lock);
+
+ snprintf(name, DEFAULT_TASK_COMM_LEN, "scsiif.%d", info->host->host_no);
+
+ info->kthread = kthread_run(comfront_schedule, info, name);
+ if (IS_ERR(info->kthread)) {
+ err = PTR_ERR(info->kthread);
+ info->kthread = NULL;
+ }
+
+ return 0;
+}
+
+
+static int scsifront_remove(struct xenbus_device *dev)
+{
+ struct comfront_info *info = dev->dev.driver_data;
+
+ DPRINTK("%s: %s removed\n",__FUNCTION__ ,dev->nodename);
+
+ if (info->kthread) {
+ kthread_stop(info->kthread);
+ info->kthread = NULL;
+ }
+
+#ifdef CONFIG_XEN_FC
+ fcfront_connection_unsetup(info);
+#endif
+ scsifront_free(info);
+
+ /*kfree(info);*/
+ return 0;
+}
+
+static void scsifront_backend_changed(struct xenbus_device *dev,
+ XenbusState backend_state)
+{
+ struct comfront_info *info = dev->dev.driver_data;
+
+ DPRINTK("%p %u %u\n", dev, dev->state, backend_state);
+
+ switch (backend_state) {
+ case XenbusStateUnknown:
+ case XenbusStateInitialising:
+ case XenbusStateInitWait:
+ case XenbusStateInitialised:
+ case XenbusStateClosed:
+ break;
+
+ case XenbusStateConnected:
+ scsifront_connect(info);
+ break;
+
+ case XenbusStateClosing:
+ scsifront_disconnect(info);
+ break;
+ }
+}
+
+static struct xenbus_device_id scsifront_ids[] = {
+ { "scsihost" },
+ { "" }
+};
+
+
+static struct xenbus_driver scsifront_driver = {
+ .name = "scsihost",
+ .owner = THIS_MODULE,
+ .ids = scsifront_ids,
+ .probe = scsifront_probe,
+ .remove = scsifront_remove,
+/* .resume = scsifront_resume, */
+ .otherend_changed = scsifront_backend_changed,
+};
+
+static int __init scsifront_init(void)
+{
+ int err;
+
+#if 0 /* for DEBUG */
+ printk(KERN_ERR "%s: ftb_req=%d\n", __FUNCTION__,
+ sizeof(struct vscsiif_ftb_request));
+ printk(KERN_ERR "%s: ftb_res=%d\n", __FUNCTION__,
+ sizeof(struct vscsiif_ftb_response));
+ printk(KERN_ERR "%s: btf_req=%d\n", __FUNCTION__,
+ sizeof(struct vscsiif_btf_request));
+ printk(KERN_ERR "%s: btf_res=%d\n", __FUNCTION__,
+ sizeof(struct vscsiif_btf_response));
+
+ printk("%s SCSI_RING_SIZE_ftb=%ld\n", __FUNCTION__,
+ __RING_SIZE((struct vscsiif_ftb_sring *)0, PAGE_SIZE));
+ printk("%s SCSI_RING_SIZE_btf=%ld\n", __FUNCTION__,
+ __RING_SIZE((struct vscsiif_btf_sring *)0, PAGE_SIZE));
+
+#endif /* for DEBUG */
+
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+#ifdef CONFIG_XEN_FC
+ if (is_initial_xendomain()) {
+ return 0;
+ }
+#endif
+
+ err = xenbus_register_frontend(&scsifront_driver);
+
+ (void)scsi_trace_init();
+
+ return err;
+}
+
+static void scsifront_exit(void)
+{
+ xenbus_unregister_driver(&scsifront_driver);
+
+#ifdef CONFIG_XEN_FC
+ fc_release_transport(fc_transport_template);
+#endif
+}
+
+module_init(scsifront_init);
+module_exit(scsifront_exit);
+
+MODULE_DESCRIPTION("Xen SCSI frontend driver");
+MODULE_LICENSE("GPL");
diff -r 709db80c03c3 -r 24e0cb9fe9df drivers/xen/scsifront/tracefront.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsifront/tracefront.c Tue Oct 30 16:41:36 2007 +0900
@@ -0,0 +1,107 @@
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+
+#include <linux/time.h>
+//#include <asm/delay.h>
+
+
+#define MAX_DATA_SIZE 472 /* should be modified */
+ /* according to data */
+ /* to be recorded */
+#define ENTRY_NUM (16 * 1024)
+
+struct scsi_trace_entry {
+ unsigned long dir; /* direction */
+ /* 0: pending(BE) */
+ /* 1: request(FE) */
+ /* 2: response(FE) */
+ unsigned long serial; /* incremental counter */
+ /* starts at 0 */
+ struct timeval tv; /* timeofday */
+// unsigned long itc; /* itc */
+ unsigned int size; /* data size */
+ unsigned char data[MAX_DATA_SIZE]; /* data body */
+};
+
+static struct scsi_trace_entry *scsi_trace_buf;
+EXPORT_SYMBOL(scsi_trace_buf); /* for DUMP */
+
+static DEFINE_SPINLOCK(scsi_trace_lock);
+
+void
+scsi_trace(unsigned long dir, unsigned char *data, unsigned int size)
+{
+ static unsigned long index = 0;
+ static unsigned long serial = 0;
+ unsigned long flags;
+
+ if (size > MAX_DATA_SIZE) {
+ printk(KERN_ERR "%s: data given is too big.\n"
+ "must be smaller than %d bytes.\n",
+ __FUNCTION__, MAX_DATA_SIZE);
+ return;
+ }
+
+ spin_lock_irqsave(&scsi_trace_lock, flags);
+
+ scsi_trace_buf[index].dir = dir;
+ do_gettimeofday(&(scsi_trace_buf[index].tv));
+// scsi_trace_buf[index].itc = ia64_get_itc();
+ scsi_trace_buf[index].size = size;
+// memset(scsi_trace_buf[index].data, 0, MAX_DATA_SIZE);
+ memcpy(scsi_trace_buf[index].data, data, size);
+
+ /* This indicates that the record is successfully recorded */
+ scsi_trace_buf[index].serial = serial++;
+
+ index = (index + 1) % ENTRY_NUM;
+
+ spin_unlock_irqrestore(&scsi_trace_lock, flags);
+
+}
+
+static int
+scsi_trace_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = sizeof(struct scsi_trace_entry) * ENTRY_NUM;
+ unsigned long flags;
+
+ spin_lock_irqsave(&scsi_trace_lock, flags);
+
+ if (len <= off + count) {
+ *eof = 1;
+ }
+ *start = page;
+ len -= off;
+ if (len > count) {
+ len = count;
+ }
+ if (len < 0) {
+ len = 0;
+ } else {
+ memcpy(page, ((unsigned char *)scsi_trace_buf) + off, len);
+ }
+
+ spin_unlock_irqrestore(&scsi_trace_lock, flags);
+
+ return len;
+}
+
+int
+scsi_trace_init(void)
+{
+ unsigned int scsi_trace_buf_size;
+
+ scsi_trace_buf_size = sizeof(struct scsi_trace_entry) * ENTRY_NUM;
+ if ((scsi_trace_buf = vmalloc(scsi_trace_buf_size)) == NULL) {
+ return -1;
+ }
+ memset(scsi_trace_buf, 0, scsi_trace_buf_size);
+
+ create_proc_read_entry("scsi_trace", 0, NULL,
+ scsi_trace_read_proc, NULL);
+
+ return 0;
+}
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
next prev parent reply other threads:[~2007-10-30 10:39 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-10-19 5:15 [PATCH 0/5] pvSCSI (SCSI pass through) driver Jun Kamada
2007-10-19 8:38 ` Keir Fraser
2007-10-19 10:20 ` Ian Pratt
2007-10-22 2:39 ` Jun Kamada
2007-10-22 0:07 ` James Harper
2007-10-23 7:41 ` Jun Kamada
2007-10-22 8:58 ` Keir Fraser
2007-10-23 7:09 ` Jun Kamada
2007-10-23 8:50 ` Keir Fraser
2007-10-23 11:35 ` Jun Kamada
2007-10-23 12:39 ` Keir Fraser
2007-10-24 6:22 ` Jun Kamada
2007-10-24 7:42 ` Keir Fraser
2007-10-25 1:59 ` Jun Kamada
2007-10-30 10:39 ` [PATCH 0/6] " Jun Kamada
2007-10-30 10:56 ` Keir Fraser
2007-10-31 8:37 ` Jun Kamada
2007-10-31 9:10 ` Keir Fraser
2007-10-31 10:56 ` Jun Kamada
2007-10-31 11:15 ` Keir Fraser
2007-11-01 12:14 ` Stephen C. Tweedie
2007-11-02 0:23 ` James Harper
2007-11-05 3:30 ` Jun Kamada
2007-11-05 2:05 ` Jun Kamada
2007-11-08 21:33 ` Stephen C. Tweedie
2007-11-12 8:27 ` Jun Kamada
2007-11-05 3:34 ` Aaron Dailey
2007-10-30 10:39 ` Jun Kamada [this message]
2007-10-30 10:39 ` [PATCH 2/6] " Jun Kamada
2007-10-30 10:39 ` [PATCH 3/6] " Jun Kamada
2007-10-30 10:39 ` [PATCH 4/6] " Jun Kamada
2007-10-30 10:39 ` [PATCH 5/6] " Jun Kamada
2007-10-30 10:39 ` [PATCH 6/6] " Jun Kamada
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20071030193911.4419.KAMA@jp.fujitsu.com \
--to=kama@jp.fujitsu.com \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.