From: Jun Kamada <kama@jp.fujitsu.com>
Cc: kama@jp.fujitsu.com, xen-devel@lists.xensource.com
Subject: [PATCH 2/6] pvSCSI (SCSI pass through) driver
Date: Tue, 30 Oct 2007 19:39:16 +0900 [thread overview]
Message-ID: <20071030193915.441C.KAMA@jp.fujitsu.com> (raw)
In-Reply-To: <20071025105803.5A32.KAMA@jp.fujitsu.com>
[-- Attachment #1: Type: text/plain, Size: 286 bytes --]
This patch is for backend 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_scsiback.patch --]
[-- Type: application/octet-stream, Size: 69814 bytes --]
# HG changeset patch
# User t.horikoshi@jp.fujitsu.com
# Date 1193730190 -32400
# Node ID 374aa5b731056b2182ff60d2efa9f3524232d8d8
# Parent 24e0cb9fe9df6f4a6df226823562bec3089072e6
[LINUX][scsiback] add scsi backend 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 24e0cb9fe9df -r 374aa5b73105 drivers/xen/scsiback/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/Makefile Tue Oct 30 16:43:10 2007 +0900
@@ -0,0 +1,8 @@
+ifeq ($(CONFIG_XEN_FC),y)
+ EXTRA_CFLAGS += -DCONFIG_XEN_FC
+ obj-$(CONFIG_XEN_SCSI_BACKEND) += xen-fcscsibk.o
+ xen-fcscsibk-y += interface.o scsiback.o xenbus.o fcback.o comback.o traceback.o
+else
+ obj-$(CONFIG_XEN_SCSI_BACKEND) += xen-scsibk.o
+ xen-scsibk-y += interface.o scsiback.o xenbus.o comback.o traceback.o
+endif
diff -r 24e0cb9fe9df -r 374aa5b73105 drivers/xen/scsiback/comback.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/comback.c Tue Oct 30 16:43:10 2007 +0900
@@ -0,0 +1,272 @@
+/*
+ * 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 <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#ifdef CONFIG_XEN_FC
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_fc.h>
+#endif
+
+#include "comback.h"
+
+extern struct list_head pending_free;
+extern int vscsiif_reqs;
+
+static DEFINE_SPINLOCK(pending_free_lock);
+static DECLARE_WAIT_QUEUE_HEAD(pending_free_wq);
+
+extern void scsiback_cmd_exec(pending_req_t *);
+extern int copy_request_ring_info(struct comback_info *,
+ struct vscsiif_ftb_request *, pending_req_t *);
+extern void scsiback_reset_exec(pending_req_t *);
+extern void scsi_trace(unsigned long, unsigned char *, unsigned int);
+
+#ifdef CONFIG_XEN_FC
+extern void fcback_cmd_exec(pending_req_t *);
+#endif
+
+static void read_btf_ring_resp_cons(struct comback_info *info);
+
+/* ------------------------------------------------------------ */
+/* for frontend to backend communication */
+/* ------------------------------------------------------------ */
+
+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, u.scsi.free_list);
+ list_del(&req->u.scsi.free_list);
+ }
+ spin_unlock_irqrestore(&pending_free_lock, flags);
+ return req;
+}
+
+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->u.scsi.free_list, &pending_free);
+ spin_unlock_irqrestore(&pending_free_lock, flags);
+ if (was_empty)
+ wake_up(&pending_free_wq);
+}
+
+static void comback_notify_work(struct comback_info *info)
+{
+ info->waiting_reqs = 1;
+ wake_up(&info->wq);
+}
+
+irqreturn_t comback_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ comback_notify_work((struct comback_info *)dev_id);
+ return IRQ_HANDLED;
+}
+
+static int __copy_request_ring_info(struct comback_info *info,
+ struct vscsiif_ftb_request *ftb_req, pending_req_t *pending_req)
+{
+ pending_req->cmnd = ftb_req->cmnd;
+ pending_req->info = info;
+
+ if (ftb_req->cmnd == CMND_SCSI || ftb_req->cmnd == CMND_SCSI_RESET) {
+ return copy_request_ring_info(info, ftb_req, pending_req);
+ } else {
+#ifdef CONFIG_XEN_FC
+ pending_req->u.fc.ftb_req = *ftb_req;
+#else
+ BUG();
+#endif
+ }
+ return 0;
+}
+
+static int do_comback_cmd_fn(struct comback_info *info)
+{
+ struct vscsiif_ftb_back_ring *ftb_ring = &info->ftb_ring;
+ struct vscsiif_ftb_request *ftb_req;
+ struct vscsiif_ftb_response *ftb_resp;
+
+ pending_req_t *pending_req[vscsiif_reqs];
+ RING_IDX rc, rp;
+ int i, err, more_to_do = 0;
+ int queued = 0;
+ int notify;
+
+ DPRINTK("%s\n",__FUNCTION__);
+
+ rc = ftb_ring->req_cons;
+ rp = ftb_ring->sring->req_prod;
+ rmb();
+
+ while ((rc != rp) && !RING_REQUEST_CONS_OVERFLOW(ftb_ring, rc)) {
+ pending_req[queued] = alloc_req();
+ if (NULL == pending_req[queued]) {
+ more_to_do = 1;
+ break;
+ }
+
+ /***** Front to Back request consume *****/
+
+ ftb_req = RING_GET_REQUEST(ftb_ring, rc);
+ ftb_ring->req_cons = ++rc;
+
+ err = __copy_request_ring_info(info, ftb_req, pending_req[queued]);
+
+ scsi_trace(0, (unsigned char *)(pending_req[queued]),
+ sizeof(pending_req_t));
+
+ /* It responds immediately after the command is issued. */
+ ftb_resp = RING_GET_RESPONSE(ftb_ring,
+ ftb_ring->rsp_prod_pvt);
+
+ if (!RING_FULL(&info->btf_ring)) {
+ ftb_resp->status = SCSIIF_REQ_OKAY;
+ } else {
+ ftb_resp->status = SCSIIF_BTFRING_BUSY;
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->btf_ring, notify);
+ if (notify)
+ notify_remote_via_irq(info->irq);
+ }
+
+ ftb_ring->rsp_prod_pvt++;
+ RING_PUSH_RESPONSES(ftb_ring);
+
+ queued++;
+ }
+
+ for (i = 0; i < queued; i++) {
+ if (pending_req[i]->cmnd == CMND_SCSI) {
+ scsiback_cmd_exec(pending_req[i]);
+ } else if (pending_req[i]->cmnd == CMND_SCSI_RESET) {
+ scsiback_reset_exec(pending_req[i]);
+#ifndef CONFIG_XEN_FC
+ }
+#else
+ } else {
+ fcback_cmd_exec(pending_req[i]);
+ }
+#endif
+ }
+
+ if (ftb_ring->rsp_prod_pvt == rc) {
+ RING_FINAL_CHECK_FOR_REQUESTS(ftb_ring, more_to_do);
+
+ } else if (RING_HAS_UNCONSUMED_REQUESTS(ftb_ring)) {
+ more_to_do = 1;
+ }
+
+ return more_to_do;
+}
+
+int comback_schedule(void *data)
+{
+ struct comback_info *info = (struct comback_info *)data;
+
+ DPRINTK("%s\n",__FUNCTION__);
+
+ 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_comback_cmd_fn(info))
+ info->waiting_reqs = 1;
+
+ /***** Back to Front response consume *****/
+ read_btf_ring_resp_cons(info);
+ }
+
+ info->kthread = NULL;
+ scsiback_put(info);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------ */
+/* for backend to frontend communication */
+/* ------------------------------------------------------------ */
+
+struct vscsiif_btf_request *comback_pre_reply(struct comback_info *info)
+{
+ struct vscsiif_btf_request *btf_req;
+
+ rmb();
+ btf_req = RING_GET_REQUEST(&info->btf_ring, info->btf_ring.req_prod_pvt);
+ info->btf_ring.req_prod_pvt++;
+
+ return btf_req;
+}
+
+static void read_btf_ring_resp_cons(struct comback_info *info)
+{
+ RING_IDX rp;
+
+ rp = info->btf_ring.sring->rsp_prod;
+ rmb();
+
+ if (info->btf_ring.rsp_cons != rp)
+ info->btf_ring.rsp_cons = rp;
+}
+
+void comback_do_reply(struct comback_info *info)
+{
+ int notify;
+
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->btf_ring, notify);
+ if (notify)
+ notify_remote_via_irq(info->irq);
+
+ /***** Back to Front response consume *****/
+ read_btf_ring_resp_cons(info);
+
+ if (RING_HAS_UNCONSUMED_REQUESTS(&info->ftb_ring)) {
+ comback_notify_work(info);
+ }
+}
diff -r 24e0cb9fe9df -r 374aa5b73105 drivers/xen/scsiback/comback.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/comback.h Tue Oct 30 16:43:10 2007 +0900
@@ -0,0 +1,148 @@
+/*
+ * 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 <linux/sched.h>
+#include <linux/kthread.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/pgalloc.h>
+#include <asm/delay.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/vscsiif.h>
+
+
+#define DPRINTK(_f, _a...) \
+ pr_debug("(file=%s, line=%d) " _f, \
+ __FILE__ , __LINE__ , ## _a )
+
+struct comback_info {
+ struct xenbus_device *dev;
+ struct Scsi_Host *host;
+
+ domid_t domid;
+ unsigned int evtchn;
+ unsigned int irq;
+
+ unsigned short host_no;
+
+ struct vscsiif_ftb_back_ring ftb_ring;
+ struct vscsiif_btf_front_ring btf_ring;
+ struct vm_struct *ftb_ring_area;
+ struct vm_struct *btf_ring_area;
+
+ grant_handle_t ftb_shmem_handle;
+ grant_ref_t ftb_shmem_ref;
+ grant_handle_t btf_shmem_handle;
+ grant_ref_t btf_shmem_ref;
+
+ struct work_struct scsiback_work;
+
+ spinlock_t ring_lock_ftb;
+ spinlock_t ring_lock_btf;
+ atomic_t refcnt;
+
+ struct task_struct *kthread;
+ wait_queue_head_t waiting_to_free;
+ wait_queue_head_t wq;
+ unsigned int waiting_reqs;
+#ifdef CONFIG_XEN_FC
+ void *fcinfo;
+#endif
+ struct page **mmap_pages;
+
+};
+
+typedef struct {
+ unsigned int cmnd;
+ struct comback_info *info;
+ union {
+ struct scsi_pending_req {
+ struct scsi_device *sdev;
+ unsigned short data_dir;
+ uint32_t rqid;
+ int use_sg;
+ int request_bufflen;
+ atomic_t pendcnt;
+ struct request *rq;
+ struct scsiback_request_segment{
+ grant_ref_t gref;
+ uint32_t offset;
+ uint32_t length;
+ } pend_seg[SG_TABLESIZE];
+ struct list_head free_list;
+ } scsi;
+#ifdef CONFIG_XEN_FC
+ struct {
+ struct vscsiif_ftb_request ftb_req;
+ } fc;
+#endif
+ } u;
+} pending_req_t;
+
+typedef struct scsi_pending_req scsi_pending_req_t;
+
+irqreturn_t scsiback_intr(int, void *, struct pt_regs *);
+int scsiback_init_sring(struct comback_info *,
+ unsigned long, 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 comback_info *scsiinfo_alloc(domid_t domid);
+void scsiback_free(struct comback_info *info);
+void scsiback_disconnect(struct comback_info *info);
+void __init scsiback_interface_init(void);
+void __exit scsiback_interface_exit(void);
+int scsiif_xenbus_init(void);
+void scsiif_xenbus_unregister(void);
+
+
+#endif /* __SCSIIF__BACKEND__COMMON_H__ */
diff -r 24e0cb9fe9df -r 374aa5b73105 drivers/xen/scsiback/fcback.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/fcback.c Tue Oct 30 16:43:10 2007 +0900
@@ -0,0 +1,610 @@
+/*
+ * Xen SCSI FC backend driver
+ *
+ * Copyright (c) 2007, FUJITSU Limited
+ *
+ * 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/module.h>
+#include <linux/device.h>
+#include <linux/kthread.h>
+#include <linux/kernel.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.h>
+#include <scsi/scsi_transport_fc.h>
+#include <asm/delay.h>
+
+#include "comback.h"
+#include "fcback.h"
+
+#define SET_FT(x, z, y) \
+ if ((x)->z == 0) { \
+ (y)->z = 0; \
+ } else { \
+ (y)->z = 1; \
+ }
+
+
+extern void unbind_from_irqhandler(unsigned int, void *);
+extern struct fc_function_template *fc_shost2ft(struct Scsi_Host *);
+extern struct vscsiif_btf_request *comback_pre_reply(struct comback_info *);
+extern void comback_do_reply(struct comback_info *);
+
+
+/* ---------------------------------------------------------------------- */
+
+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 vscsiif_ftb_request *ring_req_tmp)
+{
+ struct comback_info *cominfo = info->cominfo;
+ struct vscsiif_ftb_request *ring_req = &(info->ftb_req);
+ struct vscsiif_btf_request *ring_res;
+ struct fc_function_template *ft = fc_shost2ft(cominfo->host);
+ struct scsi_target *starget;
+ struct fc_rport *rport;
+
+ /* Must check by class or something ... */
+ if ((strcmp(cominfo->host->hostt->name, "qla2xxx") != 0) &&
+ (strcmp(cominfo->host->hostt->name, "lpfc") != 0)) {
+ printk(KERN_ERR
+ "fcback: %s: not a supported fibre channel card>>>\n",
+ __FUNCTION__);
+ return -1;
+ }
+
+ memcpy(ring_req, ring_req_tmp, sizeof(struct vscsiif_ftb_request));
+
+ /*
+ Perform specified function and send response to DomU
+ */
+
+ ring_res = comback_pre_reply(cominfo);
+
+ 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(cominfo->host);
+ ring_res->u.ghpi.port_id = ((struct fc_host_attrs *)
+ (cominfo->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(cominfo->host);
+ ring_res->u.ghpt.port_type = ((struct fc_host_attrs *)
+ (cominfo->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(cominfo->host);
+ ring_res->u.ghps.port_state = ((struct fc_host_attrs *)
+ (cominfo->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(cominfo->host);
+ memcpy(ring_res->u.ghaf.active_fc4s,
+ ((struct fc_host_attrs *)
+ (cominfo->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(cominfo->host);
+ ring_res->u.ghsp.speed = ((struct fc_host_attrs *)
+ (cominfo->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(cominfo->host);
+ ring_res->u.ghfn.fabric_name =
+ ((struct fc_host_attrs *)
+ (cominfo->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(
+ cominfo->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(cominfo->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(cominfo->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(cominfo->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(cominfo->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(cominfo->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(cominfo->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(cominfo->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 *)
+ (cominfo->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(
+ cominfo->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,
+ &(cominfo->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(cominfo->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);
+ struct fc_function_template_shared *fts = &(gftp->ft);
+
+ ft = fc_shost2ft(cominfo->host);
+
+ SET_FT(ft, get_rport_dev_loss_tmo, fts);
+ SET_FT(ft, set_rport_dev_loss_tmo, fts);
+ SET_FT(ft, get_starget_node_name, fts);
+ SET_FT(ft, get_starget_port_name, fts);
+ SET_FT(ft, get_starget_port_id, fts);
+ SET_FT(ft, get_host_port_id, fts);
+ SET_FT(ft, get_host_port_type, fts);
+ SET_FT(ft, get_host_port_state, fts);
+ SET_FT(ft, get_host_active_fc4s, fts);
+ SET_FT(ft, get_host_speed, fts);
+ SET_FT(ft, get_host_fabric_name, fts);
+ SET_FT(ft, get_fc_host_stats, fts);
+ SET_FT(ft, reset_fc_host_stats, fts);
+ SET_FT(ft, issue_fc_host_lip, fts);
+
+ fts->dd_fcrport_size = ft->dd_fcrport_size;
+
+ SET_FT(ft, show_rport_maxframe_size, fts);
+ SET_FT(ft, show_rport_supported_classes, fts);
+ SET_FT(ft, show_rport_dev_loss_tmo, fts);
+ SET_FT(ft, show_starget_node_name, fts);
+ SET_FT(ft, show_starget_port_name, fts);
+ SET_FT(ft, show_starget_port_id, fts);
+ SET_FT(ft, show_host_node_name, fts);
+ SET_FT(ft, show_host_port_name, fts);
+ SET_FT(ft, show_host_permanent_port_name, fts);
+ SET_FT(ft, show_host_supported_classes, fts);
+ SET_FT(ft, show_host_supported_fc4s, fts);
+ SET_FT(ft, show_host_symbolic_name, fts);
+ SET_FT(ft, show_host_supported_speeds, fts);
+ SET_FT(ft, show_host_maxframe_size, fts);
+ SET_FT(ft, show_host_serial_number, fts);
+ SET_FT(ft, show_host_port_id, fts);
+ SET_FT(ft, show_host_port_type, fts);
+ SET_FT(ft, show_host_port_state, fts);
+ SET_FT(ft, show_host_active_fc4s, fts);
+ SET_FT(ft, show_host_speed, fts);
+ SET_FT(ft, show_host_fabric_name, fts);
+
+ ring_res->rqid = ring_req->rqid;
+ ring_res->rslt = 0;
+
+ break; }
+
+ default:
+ printk(KERN_ERR "fcback: %s: unknown command>>>\n",
+ __FUNCTION__);
+ ring_res->rslt = -1;
+ break;
+ }
+
+ comback_do_reply(cominfo);
+
+ return 0;
+}
+
+void fcback_cmd_exec(pending_req_t *pending_req)
+{
+ (void)fcback_main((struct fcback_info *)(pending_req->info->fcinfo),
+ &(pending_req->u.fc.ftb_req));
+}
+
+
+/* ---------------------------------------------------------------------- */
+static int __setup_xenstore(struct fcback_info *info)
+{
+ struct xenbus_device *dev = info->cominfo->dev;
+ int gntref;
+ int ret = 0;
+
+ if ((ret = xenbus_gather(XBT_NIL, dev->otherend,
+ "fc_gntref", "%d", &gntref, NULL)) != 0) {
+ printk(KERN_ERR "fcback: %s: xenbus_gather() error>>>\n",
+ __FUNCTION__);
+ return ret;
+ }
+
+ info->gntref = gntref;
+
+ return 0;
+}
+
+static void __unsetup_xenstore(struct fcback_info *info)
+{
+ /* currently, nothing to do */
+}
+
+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 "fcback: %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->cominfo->dev->otherend_id);
+
+ err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
+ if (op.status) {
+ printk(KERN_ERR
+ "fcback: %s: HYPERVISOR_grant_table_op() error>>>\n",
+ __FUNCTION__);
+ return op.status;
+ }
+
+ info->gnt_area = gnt_area;
+
+ return 0;
+}
+
+static void __unsetup_grant_table(struct fcback_info *info)
+{
+ /* currently, nothing to do */
+}
+
+int fcback_connection_setup(struct comback_info *cominfo)
+{
+ struct fcback_info *info;
+ int ret = 0;
+
+#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 fcback_info),
+ GFP_KERNEL);
+ if (cominfo->fcinfo == NULL) {
+ ret = -ENOMEM;
+ goto out0;
+ }
+ memset(cominfo->fcinfo, 0, sizeof(struct fcback_info));
+ info = (struct fcback_info *)(cominfo->fcinfo);
+ info->cominfo = cominfo;
+ }
+
+ /* exchange various parameters through xenstore */
+ if ((ret = __setup_xenstore(info)) != 0) {
+ printk(KERN_ERR "fcback: %s: __setup_xenstore() error>>>\n",
+ __FUNCTION__);
+ goto out1;
+ }
+
+ /* prepare for grant table */
+ if ((ret = __setup_grant_table(info)) != 0) {
+ printk(KERN_ERR "fcback: %s: __setup_grant_table() error>>>\n",
+ __FUNCTION__);
+ goto out2;
+ }
+
+ return 0;
+
+out2:
+ __unsetup_xenstore(info);
+
+out1:
+ kfree(cominfo->fcinfo);
+
+out0:
+ return ret;
+}
+
+void
+fcback_connection_unsetup(struct comback_info *cominfo)
+{
+ struct fcback_info *info = (struct fcback_info *)(cominfo->fcinfo);
+
+ __unsetup_grant_table(info);
+ __unsetup_xenstore(info);
+
+ kfree(cominfo->fcinfo);
+}
+
+
+MODULE_DESCRIPTION("Xen Para-Virtual SCSI Fibre Channel Backend Driver");
+MODULE_LICENSE("GPL");
diff -r 24e0cb9fe9df -r 374aa5b73105 drivers/xen/scsiback/fcback.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/fcback.h Tue Oct 30 16:43:10 2007 +0900
@@ -0,0 +1,191 @@
+/*
+ * 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;
+};
+
+
+static struct fc_function_template *
+fc_shost2ft(struct Scsi_Host *shost)
+{
+ struct fc_internal_head *i;
+
+ i = container_of(shost->transportt, struct fc_internal_head, t);
+ return i->f;
+}
+
+#endif /*__XEN_DRIVERS_FCFRONT_H__*/
diff -r 24e0cb9fe9df -r 374aa5b73105 drivers/xen/scsiback/interface.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/interface.c Tue Oct 30 16:43:10 2007 +0900
@@ -0,0 +1,215 @@
+/*
+ * 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 <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#ifdef CONFIG_XEN_FC
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_fc.h>
+#endif
+
+#include "comback.h"
+
+#include <xen/evtchn.h>
+#include <linux/kthread.h>
+
+extern irqreturn_t comback_intr(int, void *, struct pt_regs *);
+
+
+static kmem_cache_t *scsiback_cachep;
+
+struct comback_info *scsiinfo_alloc(domid_t domid)
+{
+ struct comback_info *info;
+
+ info = kmem_cache_alloc(scsiback_cachep, GFP_KERNEL);
+ if (!info)
+ return ERR_PTR(-ENOMEM);
+
+ memset(info, 0, sizeof(*info));
+ info->domid = domid;
+/* spin_lock_init(&info->ring_lock_ftb);*/
+ spin_lock_init(&info->ring_lock_btf);
+ 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 comback_info *info,
+ unsigned long ftb_ring_ref, unsigned long btf_ring_ref)
+{
+ struct gnttab_map_grant_ref op;
+ int err;
+
+ gnttab_set_map_op(&op, (unsigned long)info->ftb_ring_area->addr,
+ GNTMAP_host_map, ftb_ring_ref,
+ info->domid);
+
+ err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
+ BUG_ON(err);
+
+ if (op.status) {
+ printk(KERN_ERR "scsiback: Grant table operation failure !\n");
+ return op.status;
+ }
+
+ info->ftb_shmem_ref = ftb_ring_ref;
+ info->ftb_shmem_handle = op.handle;
+
+ gnttab_set_map_op(&op, (unsigned long)info->btf_ring_area->addr,
+ GNTMAP_host_map, btf_ring_ref, info->domid);
+
+ err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
+ BUG_ON(err);
+
+ if (op.status) {
+ printk(KERN_ERR "scsiback: Grant table operation failure !\n");
+ return op.status;
+ }
+
+ info->btf_shmem_ref = btf_ring_ref;
+ info->btf_shmem_handle = op.handle;
+
+ return 0;
+}
+
+static void unmap_frontend_page(struct comback_info *info)
+{
+ struct gnttab_unmap_grant_ref op;
+ int err;
+
+ gnttab_set_unmap_op(&op, (unsigned long)info->ftb_ring_area->addr,
+ GNTMAP_host_map, info->ftb_shmem_handle);
+
+ err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
+ BUG_ON(err);
+
+ gnttab_set_unmap_op(&op, (unsigned long)info->btf_ring_area->addr,
+ GNTMAP_host_map, info->btf_shmem_handle);
+
+ err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
+ BUG_ON(err);
+}
+
+int scsiback_init_sring(struct comback_info *info,
+ unsigned long ftb_ring_ref, unsigned long btf_ring_ref, unsigned int evtchn)
+{
+ struct vscsiif_ftb_sring *ftb_sring;
+ struct vscsiif_btf_sring *btf_sring;
+ int err;
+
+ if (info->irq) {
+ printk(KERN_ERR "scsiback: Already connected through?\n");
+ return 0;
+ }
+
+ info->ftb_ring_area = alloc_vm_area(PAGE_SIZE);
+ if (!info)
+ return -ENOMEM;
+ info->btf_ring_area = alloc_vm_area(PAGE_SIZE);
+ if (!info)
+ return -ENOMEM;
+
+ err = map_frontend_page(info, ftb_ring_ref, btf_ring_ref);
+ if (err)
+ goto free_vm;
+
+ ftb_sring = (struct vscsiif_ftb_sring *) info->ftb_ring_area->addr;
+ BACK_RING_INIT(&info->ftb_ring, ftb_sring, PAGE_SIZE);
+
+ btf_sring = (struct vscsiif_btf_sring *) info->btf_ring_area->addr;
+ FRONT_RING_INIT(&info->btf_ring, btf_sring, PAGE_SIZE);
+
+ err = bind_interdomain_evtchn_to_irqhandler(
+ info->domid, evtchn,
+ comback_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->ftb_ring_area);
+ free_vm_area(info->btf_ring_area);
+ return err;
+}
+
+void scsiback_disconnect(struct comback_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->ftb_ring.sring || info->btf_ring.sring) {
+ unmap_frontend_page(info);
+ free_vm_area(info->ftb_ring_area);
+ free_vm_area(info->btf_ring_area);
+ info->ftb_ring.sring = NULL;
+ info->btf_ring.sring = NULL;
+ }
+}
+
+void scsiback_free(struct comback_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 comback_info), 0, 0, NULL, NULL);
+}
+
+void __exit scsiback_interface_exit(void)
+{
+ kmem_cache_destroy(scsiback_cachep);
+}
diff -r 24e0cb9fe9df -r 374aa5b73105 drivers/xen/scsiback/scsiback.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/scsiback.c Tue Oct 30 16:43:10 2007 +0900
@@ -0,0 +1,556 @@
+/*
+ * 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 <scsi/scsi_eh.h>
+
+#ifdef CONFIG_XEN_FC
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_fc.h>
+#endif
+
+#include "comback.h"
+
+extern struct vscsiif_btf_request * comback_pre_reply(struct comback_info *);
+extern void comback_do_reply(struct comback_info *);
+extern void free_req(pending_req_t *req);
+extern int __init scsi_trace_init(void);
+extern void __exit scsi_trace_exit(void);
+
+int vscsiif_reqs = DEFAULT_CAN_QUEUE;
+module_param_named(reqs, vscsiif_reqs, int, 0);
+MODULE_PARM_DESC(reqs, "Number of scsiback requests to allocate");
+
+
+#define INVALID_GRANT_HANDLE 0xFFFF
+#define SCSIBACK_INVALID_HANDLE (~0)
+
+static pending_req_t *pending_reqs;
+struct list_head pending_free;
+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)])
+
+
+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;
+
+ if (req->u.scsi.use_sg) {
+ for (i = 0; i < req->u.scsi.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);
+ } else if (req->u.scsi.request_bufflen) {
+ handle = pending_handle(req, 0);
+ if (handle == SCSIBACK_INVALID_HANDLE)
+ return;
+ gnttab_set_unmap_op(&unmap[0], vaddr(req, 0),
+ GNTMAP_host_map, handle);
+ pending_handle(req, 0) = SCSIBACK_INVALID_HANDLE;
+
+ err = HYPERVISOR_grant_table_op(
+ GNTTABOP_unmap_grant_ref, unmap, 1);
+ BUG_ON(err);
+ }
+
+ return;
+}
+
+
+static void make_sense(struct comback_info *info, struct request *req,
+ int32_t result, uint64_t rqid)
+{
+ struct vscsiif_btf_request *btf_req;
+
+ DPRINTK("%s\n",__FUNCTION__);
+
+ btf_req = comback_pre_reply(info);
+
+ memset(btf_req->u.scsi.sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+
+ btf_req->rslt = result;
+ btf_req->rqid = rqid;
+
+ if (result != 0 && req != NULL ) {
+ memcpy(btf_req->u.scsi.sense_buffer, req->sense, req->sense_len);
+ btf_req->u.scsi.sense_len = req->sense_len;
+ } else
+ btf_req->u.scsi.sense_len = 0;
+
+ comback_do_reply(info);
+
+}
+
+
+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->u.scsi.rq = req;
+
+ DPRINTK("%s\n",__FUNCTION__);
+
+ if (req->errors != 0) {
+
+ printk("scsiback: SCSI CMD return. req->errors = 0x%08x\n",
+ req->errors);
+ printk("scsiback: status = 0x%02x, message = 0x%02x, host = 0x%02x, driver = 0x%02x\n",
+ status_byte(req->errors), msg_byte(req->errors),
+ host_byte(req->errors), driver_byte(req->errors));
+ memcpy(sense_buffer, req->sense, req->sense_len);
+ __scsi_print_sense("scsiback", sense_buffer, req->sense_len);
+
+ }
+
+ if (atomic_dec_and_test(&pending_req->u.scsi.pendcnt)) {
+ fast_flush_area(pending_req);
+ make_sense(pending_req->info, pending_req->u.scsi.rq,
+ req->errors, pending_req->u.scsi.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(pending_req_t *pending_req, int count)
+{
+ struct request *rq = pending_req->u.scsi.rq;
+ struct request_queue *q = pending_req->u.scsi.rq->q;
+ int nr_pages;
+ int nsegs = count;
+
+ 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 = pending_req->u.scsi.pend_seg[i].offset;
+ len = pending_req->u.scsi.pend_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;
+}
+
+int copy_request_ring_info(struct comback_info *info,
+ struct vscsiif_ftb_request *ftb_req, pending_req_t *pending_req)
+{
+ int write;
+ char sense[SCSI_SENSE_BUFFERSIZE];
+ int i;
+
+ DPRINTK("%s\n",__FUNCTION__);
+
+ pending_req->u.scsi.rqid = ftb_req->rqid;
+ pending_req->u.scsi.sdev = scsi_device_lookup(info->host,
+ ftb_req->u.scsi.channel, ftb_req->u.scsi.id, ftb_req->u.scsi.lun);
+ if (!pending_req->u.scsi.sdev) {
+ goto fail_response;
+ }
+
+ write = (ftb_req->u.scsi.sc_data_direction == DMA_TO_DEVICE);
+ pending_req->u.scsi.data_dir = ftb_req->u.scsi.sc_data_direction;
+ pending_req->u.scsi.rq =
+ blk_get_request(pending_req->u.scsi.sdev->request_queue,
+ write, GFP_KERNEL);
+ pending_req->info = info;
+ pending_req->u.scsi.use_sg = ftb_req->u.scsi.use_sg;
+ pending_req->u.scsi.request_bufflen = ftb_req->u.scsi.request_bufflen;
+
+
+ pending_req->u.scsi.rq->flags |= REQ_BLOCK_PC;
+ pending_req->u.scsi.rq->cmd_len = ftb_req->u.scsi.cmd_len;
+ memcpy(pending_req->u.scsi.rq->cmd, ftb_req->u.scsi.cmnd,
+ ftb_req->u.scsi.cmd_len);
+
+ memset(sense, 0, sizeof(sense)); /*FIXME*/
+ pending_req->u.scsi.rq->sense = sense;
+ pending_req->u.scsi.rq->sense_len = SCSI_SENSE_BUFFERSIZE;
+
+/* pending_req->u.scsi.rq->retries = ftb_req->u.scsi.retries;*/
+ pending_req->u.scsi.rq->retries = 0;
+ pending_req->u.scsi.rq->timeout = ftb_req->u.scsi.timeout_per_command;
+
+ pending_req->u.scsi.rq->end_io_data = pending_req;
+
+ if (ftb_req->u.scsi.use_sg) {
+ for (i = 0; i < ftb_req->u.scsi.use_sg; i++) {
+ pending_req->u.scsi.pend_seg[i].gref = ftb_req->u.scsi.seg[i].gref;
+ pending_req->u.scsi.pend_seg[i].offset = ftb_req->u.scsi.seg[i].offset;
+ pending_req->u.scsi.pend_seg[i].length = ftb_req->u.scsi.seg[i].length;
+ }
+ } else if (ftb_req->u.scsi.request_bufflen) {
+ pending_req->u.scsi.pend_seg[0].gref = ftb_req->u.scsi.seg[0].gref;
+ pending_req->u.scsi.pend_seg[0].offset = ftb_req->u.scsi.seg[0].offset;
+ pending_req->u.scsi.pend_seg[0].length = ftb_req->u.scsi.seg[0].length;
+ }
+
+ return 0;
+
+fail_response:
+ return 1;
+}
+
+
+void scsiback_cmd_exec(pending_req_t *pending_req)
+{
+
+ struct gnttab_map_grant_ref map[SG_TABLESIZE];
+ struct comback_info *info = pending_req->info;
+
+ int write = (pending_req->u.scsi.data_dir == DMA_TO_DEVICE);
+ u32 flags;
+ int i, err = 0;
+
+ DPRINTK("%s\n",__FUNCTION__);
+
+ if (!pending_req->u.scsi.sdev) {
+ goto fail_response;
+ }
+
+ if (pending_req->u.scsi.use_sg) {
+
+ for (i = 0; i < pending_req->u.scsi.use_sg; i++) {
+ flags = GNTMAP_host_map;
+ if (write)
+ flags |= GNTMAP_readonly;
+ gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags,
+ pending_req->u.scsi.pend_seg[i].gref,
+ info->domid);
+ }
+
+ err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
+ map, pending_req->u.scsi.use_sg);
+ BUG_ON(err);
+
+ for (i = 0; i < pending_req->u.scsi.use_sg; i++) {
+ if (unlikely(map[i].status != 0)) {
+ printk(KERN_ERR "scsiback: 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 (requset_map_sg(pending_req, pending_req->u.scsi.use_sg)) {
+ printk(KERN_ERR "scsiback: SG Request Map Error\n");
+ goto fail_map;
+ }
+
+ } else if (pending_req->u.scsi.request_bufflen) {
+
+ flags = GNTMAP_host_map;
+ if (write)
+ flags |= GNTMAP_readonly;
+ gnttab_set_map_op(&map[0], vaddr(pending_req, 0), flags,
+ pending_req->u.scsi.pend_seg[0].gref,
+ info->domid);
+
+ err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, 1);
+ BUG_ON(err);
+
+ if (unlikely(map[0].status != 0)) {
+ printk(KERN_ERR "scsiback: invalid buffer single -- could not remap it\n");
+ map[0].handle = SCSIBACK_INVALID_HANDLE;
+ err |= 1;
+ }
+
+ pending_handle(pending_req, 0) = map[0].handle;
+
+ set_phys_to_machine(__pa(vaddr(
+ pending_req, 0)) >> PAGE_SHIFT,
+ FOREIGN_FRAME(map[0].dev_bus_addr >> PAGE_SHIFT));
+
+ if (err)
+ goto fail_flush;
+
+ if (requset_map_sg(pending_req, 1)) {
+ printk(KERN_ERR "scsiback: SG Request Map Error\n");
+ goto fail_map;
+ }
+ }
+
+ atomic_set(&pending_req->u.scsi.pendcnt, 1);
+ scsiback_get(info);
+
+ blk_execute_rq_nowait(pending_req->u.scsi.rq->q, NULL,
+ pending_req->u.scsi.rq, 1, scsiback_end_cmd_fn);
+
+ return ;
+
+fail_map:
+fail_flush:
+ fast_flush_area(pending_req);
+fail_response:
+ make_sense(info, NULL, (DID_NO_CONNECT << 16), pending_req->u.scsi.rqid);
+ free_req(pending_req);
+
+}
+
+
+void scsiback_reset_exec(pending_req_t *pending_req)
+{
+ struct scsi_device *sdev = pending_req->u.scsi.sdev;
+ struct comback_info *info = pending_req->info;
+ struct vscsiif_btf_request *ring_res;
+ int err;
+
+ err = scsi_reset_provider(sdev, SCSI_TRY_RESET_HOST);
+ if (err != SUCCESS)
+ err = scsi_reset_provider(sdev, SCSI_TRY_RESET_BUS);
+
+ ring_res = comback_pre_reply(info);
+
+ ring_res->rqid = pending_req->u.scsi.rqid;
+ ring_res->rslt = err;
+
+ comback_do_reply(info);
+
+}
+
+
+static int __init scsiback_init(void)
+{
+ int i, mmap_pages;
+
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ mmap_pages = vscsiif_reqs * SG_TABLESIZE;
+
+ pending_reqs = kmalloc(sizeof(pending_reqs[0]) *
+ vscsiif_reqs, 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 < vscsiif_reqs; i++)
+ list_add_tail(&pending_reqs[i].u.scsi.free_list, &pending_free);
+
+ if (scsiif_xenbus_init())
+ goto out_of_memory;
+
+ (void)scsi_trace_init();
+
+#if 0 /*DEBUG*/
+ printk(KERN_ERR "%s: ftb_req=%ld\n", __FUNCTION__,
+ sizeof(struct vscsiif_ftb_request));
+ printk(KERN_ERR "%s: ftb_res=%ld\n", __FUNCTION__,
+ sizeof(struct vscsiif_ftb_response));
+ printk(KERN_ERR "%s: btf_req=%ld\n", __FUNCTION__,
+ sizeof(struct vscsiif_btf_request));
+ printk(KERN_ERR "%s: btf_res=%ld\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 /*DEBUG*/
+
+
+ return 0;
+
+ out_of_memory:
+ kfree(pending_reqs);
+ kfree(pending_grant_handles);
+ free_empty_pages_and_pagevec(pending_pages, mmap_pages);
+ printk(KERN_ERR "scsiback: %s: out of memory\n", __FUNCTION__);
+ return -ENOMEM;
+}
+
+static void __exit scsiback_exit(void)
+{
+ scsiif_xenbus_unregister();
+ scsiback_interface_exit();
+ scsi_trace_exit();
+ kfree(pending_reqs);
+ kfree(pending_grant_handles);
+ free_empty_pages_and_pagevec(pending_pages, (vscsiif_reqs * SG_TABLESIZE));
+}
+
+module_init(scsiback_init);
+module_exit(scsiback_exit);
+
+MODULE_DESCRIPTION("Xen SCSI backend driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff -r 24e0cb9fe9df -r 374aa5b73105 drivers/xen/scsiback/traceback.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/traceback.c Tue Oct 30 16:43:10 2007 +0900
@@ -0,0 +1,109 @@
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+
+#include <linux/time.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 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].size = 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 __init 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;
+}
+
+void __exit scsi_trace_exit(void)
+{
+ vfree(scsi_trace_buf);
+ remove_proc_entry("scsi_trace", NULL);
+}
+
diff -r 24e0cb9fe9df -r 374aa5b73105 drivers/xen/scsiback/xenbus.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/scsiback/xenbus.c Tue Oct 30 16:43:10 2007 +0900
@@ -0,0 +1,300 @@
+/*
+ * 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 <stdarg.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+
+#ifdef CONFIG_XEN_FC
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_fc.h>
+#endif
+
+#include "comback.h"
+
+extern int comback_schedule(void *);
+#ifdef CONFIG_XEN_FC
+extern int fcback_connection_setup(struct comback_info *cominfo);
+#endif
+
+struct backend_info
+{
+ struct xenbus_device *dev;
+ struct comback_info *info;
+ struct xenbus_watch backend_watch;
+};
+
+
+static int scsiback_remove(struct xenbus_device *dev)
+{
+ struct backend_info *be = dev->dev.driver_data;
+
+ if (be->backend_watch.node) {
+ unregister_xenbus_watch(&be->backend_watch);
+ kfree(be->backend_watch.node);
+ be->backend_watch.node = NULL;
+ }
+
+ if (be->info) {
+ scsiback_disconnect(be->info);
+ scsiback_free(be->info);
+ be->info = NULL;
+ }
+
+ kfree(be);
+ dev->dev.driver_data = NULL;
+
+ return 0;
+}
+
+static int scsiif_name(struct backend_info *be, char *buf)
+{
+ char *devpath;
+ struct xenbus_device *dev = be->dev;
+
+ devpath = xenbus_read(XBT_NIL, dev->nodename, "hostno", NULL);
+ if (IS_ERR(devpath))
+ return PTR_ERR(devpath);
+
+ snprintf(buf, TASK_COMM_LEN, "scsiif.%d.%s", be->info->domid, devpath);
+ kfree(devpath);
+
+ return 0;
+}
+
+static int scsiback_connect(struct backend_info *be)
+{
+ struct xenbus_device *dev = be->dev;
+ unsigned long ftb_ring_ref, btf_ring_ref;
+ unsigned int evtchn;
+ int err;
+ char name[TASK_COMM_LEN];
+
+ err = xenbus_gather(XBT_NIL, dev->otherend,
+ "ftb-ring-ref", "%lu", &ftb_ring_ref,
+ "btf-ring-ref", "%lu", &btf_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(be->info,
+ ftb_ring_ref, btf_ring_ref, evtchn);
+ if (err)
+ return err;
+
+ err = scsiif_name(be, name);
+ if (err) {
+ xenbus_dev_error(dev, err, "get scsiback dev name");
+ return err;
+ }
+
+ be->info->kthread = kthread_run(comback_schedule, be->info, name);
+ if (IS_ERR(be->info->kthread)) {
+ err = PTR_ERR(be->info->kthread);
+ be->info->kthread = NULL;
+ xenbus_dev_error(be->dev, err, "start scsiif");
+ return err;
+ }
+
+#ifdef CONFIG_XEN_FC
+ {
+ int ret;
+
+ if ((ret = fcback_connection_setup(be->info)) != 0) {
+ printk(KERN_ERR "scsiback: %s: fcback_setup() error>>>\n",
+ __FUNCTION__);
+ return ret;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static void scsiback_frontend_changed(struct xenbus_device *dev,
+ enum xenbus_state frontend_state)
+{
+ struct backend_info *be = dev->dev.driver_data;
+ int err;
+
+ switch (frontend_state) {
+ case XenbusStateInitialising:
+ break;
+
+ case XenbusStateInitialised:
+ case XenbusStateConnected:
+ if (dev->state == XenbusStateConnected)
+ break;
+
+ err = scsiback_connect(be);
+ 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(be->info);
+ xenbus_switch_state(dev, XenbusStateClosing);
+ break;
+
+ case XenbusStateClosed:
+ xenbus_switch_state(dev, XenbusStateClosed);
+ if (xenbus_dev_is_online(dev))
+ break;
+
+ case XenbusStateUnknown:
+ 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)
+{
+ int err;
+ struct backend_info *be =
+ container_of(watch, struct backend_info, backend_watch);
+ struct xenbus_device *dev = be->dev;
+
+ 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));
+
+ be->info->host = scsi_host_lookup(be->info->host_no);
+ if (IS_ERR(be->info->host)) {
+ err = PTR_ERR(be->info->host);
+ xenbus_dev_fatal(dev, err, "no lookup scsi host");
+ goto fail;
+ }
+
+ return;
+fail:
+ scsiback_remove(dev);
+}
+
+
+static int scsiback_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ int err;
+ int hostno;
+ struct backend_info *be = kzalloc(sizeof(struct backend_info),
+ GFP_KERNEL);
+
+ DPRINTK("%p %d\n", dev, dev->otherend_id);
+
+ if (!be) {
+ xenbus_dev_fatal(dev, -ENOMEM,
+ "allocating backend structure");
+ return -ENOMEM;
+ }
+ be->dev = dev;
+ dev->dev.driver_data = be;
+
+ be->info = scsiinfo_alloc(dev->otherend_id);
+ if (IS_ERR(be->info)) {
+ err = PTR_ERR(be->info);
+ be->info = NULL;
+ xenbus_dev_fatal(dev, err, "creating scsihost interface");
+ goto fail;
+ }
+
+ be->info->dev = dev;
+ be->info->irq = 0;
+
+ err = xenbus_scanf(XBT_NIL, dev->nodename, "hostno", "%d", &hostno);
+ if (err == -ENOENT ) {
+ printk(KERN_WARNING "scsiback: error xenbus_scanf hostno=%d\n",hostno);
+ goto fail;
+ }
+
+ be->info->host_no = (unsigned short)hostno;
+
+ err = xenbus_watch_path2(dev, dev->nodename,
+ "scsi-host",
+ &be->backend_watch,
+ scsiback_backend_changed);
+ if (err)
+ goto fail;
+
+ err = xenbus_switch_state(dev, XenbusStateInitWait);
+ if (err)
+ goto fail;
+
+ return 0;
+
+fail:
+ printk(KERN_WARNING "scsiback: %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
+};
+
+int scsiif_xenbus_init(void)
+{
+ return xenbus_register_backend(&scsiback);
+}
+
+void scsiif_xenbus_unregister(void)
+{
+ xenbus_unregister_driver(&scsiback);
+}
[-- 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 ` [PATCH 1/6] " Jun Kamada
2007-10-30 10:39 ` Jun Kamada [this message]
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=20071030193915.441C.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.