ia64/linux-2.6.18-xen.hg

changeset 563:3b3701ad4eec

pvSCSI frontend driver

Signed-off-by: Tomonari Horikoshi <t.horikoshi@jp.fujitsu.com>
Signed-off-by: Jun Kamada <kama@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jun 02 09:58:56 2008 +0100 (2008-06-02)
parents 66faefe721eb
children 1bc7c710abd7
files buildconfigs/linux-defconfig_xen0_ia64 buildconfigs/linux-defconfig_xen0_x86_32 buildconfigs/linux-defconfig_xen0_x86_64 buildconfigs/linux-defconfig_xenU_ia64 buildconfigs/linux-defconfig_xenU_x86_32 buildconfigs/linux-defconfig_xenU_x86_64 buildconfigs/linux-defconfig_xen_ia64 buildconfigs/linux-defconfig_xen_x86_32 buildconfigs/linux-defconfig_xen_x86_64 drivers/xen/Kconfig drivers/xen/Makefile drivers/xen/scsifront/Makefile drivers/xen/scsifront/common.h drivers/xen/scsifront/scsifront.c drivers/xen/scsifront/xenbus.c
line diff
     1.1 --- a/buildconfigs/linux-defconfig_xen0_ia64	Mon Jun 02 09:58:27 2008 +0100
     1.2 +++ b/buildconfigs/linux-defconfig_xen0_ia64	Mon Jun 02 09:58:56 2008 +0100
     1.3 @@ -1684,6 +1684,7 @@ CONFIG_XEN_TPMDEV_BACKEND=m
     1.4  CONFIG_XEN_SCSI_BACKEND=m
     1.5  CONFIG_XEN_BLKDEV_FRONTEND=y
     1.6  CONFIG_XEN_NETDEV_FRONTEND=y
     1.7 +CONFIG_XEN_SCSI_FRONTEND=m
     1.8  CONFIG_XEN_GRANT_DEV=y
     1.9  # CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
    1.10  CONFIG_XEN_FRAMEBUFFER=y
     2.1 --- a/buildconfigs/linux-defconfig_xen0_x86_32	Mon Jun 02 09:58:27 2008 +0100
     2.2 +++ b/buildconfigs/linux-defconfig_xen0_x86_32	Mon Jun 02 09:58:56 2008 +0100
     2.3 @@ -1421,6 +1421,7 @@ CONFIG_XEN_TPMDEV_BACKEND=m
     2.4  CONFIG_XEN_SCSI_BACKEND=m
     2.5  CONFIG_XEN_BLKDEV_FRONTEND=y
     2.6  CONFIG_XEN_NETDEV_FRONTEND=y
     2.7 +CONFIG_XEN_SCSI_FRONTEND=m
     2.8  CONFIG_XEN_GRANT_DEV=y
     2.9  # CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
    2.10  CONFIG_XEN_SCRUB_PAGES=y
     3.1 --- a/buildconfigs/linux-defconfig_xen0_x86_64	Mon Jun 02 09:58:27 2008 +0100
     3.2 +++ b/buildconfigs/linux-defconfig_xen0_x86_64	Mon Jun 02 09:58:56 2008 +0100
     3.3 @@ -1362,6 +1362,7 @@ CONFIG_XEN_PCIDEV_BACKEND_PASS=y
     3.4  # CONFIG_XEN_SCSI_BACKEND is not set
     3.5  CONFIG_XEN_BLKDEV_FRONTEND=y
     3.6  CONFIG_XEN_NETDEV_FRONTEND=y
     3.7 +CONFIG_XEN_SCSI_FRONTEND=m
     3.8  CONFIG_XEN_GRANT_DEV=y
     3.9  # CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
    3.10  CONFIG_XEN_SCRUB_PAGES=y
     4.1 --- a/buildconfigs/linux-defconfig_xenU_ia64	Mon Jun 02 09:58:27 2008 +0100
     4.2 +++ b/buildconfigs/linux-defconfig_xenU_ia64	Mon Jun 02 09:58:56 2008 +0100
     4.3 @@ -1492,6 +1492,7 @@ CONFIG_XEN_XENBUS_DEV=y
     4.4  # CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set
     4.5  CONFIG_XEN_BLKDEV_FRONTEND=y
     4.6  CONFIG_XEN_NETDEV_FRONTEND=y
     4.7 +CONFIG_XEN_SCSI_FRONTEND=m
     4.8  # CONFIG_XEN_GRANT_DEV is not set
     4.9  # CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
    4.10  CONFIG_XEN_FRAMEBUFFER=y
     5.1 --- a/buildconfigs/linux-defconfig_xenU_x86_32	Mon Jun 02 09:58:27 2008 +0100
     5.2 +++ b/buildconfigs/linux-defconfig_xenU_x86_32	Mon Jun 02 09:58:56 2008 +0100
     5.3 @@ -916,6 +916,7 @@ CONFIG_XEN_XENBUS_DEV=y
     5.4  # CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set
     5.5  CONFIG_XEN_BLKDEV_FRONTEND=y
     5.6  CONFIG_XEN_NETDEV_FRONTEND=y
     5.7 +CONFIG_XEN_SCSI_FRONTEND=m
     5.8  # CONFIG_XEN_GRANT_DEV is not set
     5.9  # CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
    5.10  CONFIG_XEN_SCRUB_PAGES=y
     6.1 --- a/buildconfigs/linux-defconfig_xenU_x86_64	Mon Jun 02 09:58:27 2008 +0100
     6.2 +++ b/buildconfigs/linux-defconfig_xenU_x86_64	Mon Jun 02 09:58:56 2008 +0100
     6.3 @@ -878,6 +878,7 @@ CONFIG_XEN_XENBUS_DEV=y
     6.4  # CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set
     6.5  CONFIG_XEN_BLKDEV_FRONTEND=y
     6.6  CONFIG_XEN_NETDEV_FRONTEND=y
     6.7 +CONFIG_XEN_SCSI_FRONTEND=m
     6.8  CONFIG_XEN_GRANT_DEV=y
     6.9  # CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
    6.10  CONFIG_XEN_SCRUB_PAGES=y
     7.1 --- a/buildconfigs/linux-defconfig_xen_ia64	Mon Jun 02 09:58:27 2008 +0100
     7.2 +++ b/buildconfigs/linux-defconfig_xen_ia64	Mon Jun 02 09:58:56 2008 +0100
     7.3 @@ -1684,6 +1684,7 @@ CONFIG_XEN_TPMDEV_BACKEND=m
     7.4  CONFIG_XEN_SCSI_BACKEND=m
     7.5  CONFIG_XEN_BLKDEV_FRONTEND=y
     7.6  CONFIG_XEN_NETDEV_FRONTEND=y
     7.7 +CONFIG_XEN_SCSI_FRONTEND=m
     7.8  CONFIG_XEN_GRANT_DEV=y
     7.9  # CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
    7.10  CONFIG_XEN_FRAMEBUFFER=y
     8.1 --- a/buildconfigs/linux-defconfig_xen_x86_32	Mon Jun 02 09:58:27 2008 +0100
     8.2 +++ b/buildconfigs/linux-defconfig_xen_x86_32	Mon Jun 02 09:58:56 2008 +0100
     8.3 @@ -3279,6 +3279,7 @@ CONFIG_XEN_TPMDEV_BACKEND=m
     8.4  CONFIG_XEN_SCSI_BACKEND=m
     8.5  CONFIG_XEN_BLKDEV_FRONTEND=y
     8.6  CONFIG_XEN_NETDEV_FRONTEND=y
     8.7 +CONFIG_XEN_SCSI_FRONTEND=m
     8.8  CONFIG_XEN_GRANT_DEV=y
     8.9  # CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
    8.10  CONFIG_XEN_FRAMEBUFFER=y
     9.1 --- a/buildconfigs/linux-defconfig_xen_x86_64	Mon Jun 02 09:58:27 2008 +0100
     9.2 +++ b/buildconfigs/linux-defconfig_xen_x86_64	Mon Jun 02 09:58:56 2008 +0100
     9.3 @@ -3109,6 +3109,7 @@ CONFIG_XEN_TPMDEV_BACKEND=m
     9.4  CONFIG_XEN_SCSI_BACKEND=m
     9.5  CONFIG_XEN_BLKDEV_FRONTEND=y
     9.6  CONFIG_XEN_NETDEV_FRONTEND=y
     9.7 +CONFIG_XEN_SCSI_FRONTEND=m
     9.8  CONFIG_XEN_GRANT_DEV=y
     9.9  # CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
    9.10  CONFIG_XEN_FRAMEBUFFER=y
    10.1 --- a/drivers/xen/Kconfig	Mon Jun 02 09:58:27 2008 +0100
    10.2 +++ b/drivers/xen/Kconfig	Mon Jun 02 09:58:56 2008 +0100
    10.3 @@ -199,6 +199,14 @@ config XEN_NETDEV_ACCEL_SFC_FRONTEND
    10.4  	select XEN_NETDEV_ACCEL_SFC_UTIL
    10.5  	default m
    10.6  
    10.7 +config XEN_SCSI_FRONTEND
    10.8 +	tristate "SCSI frontend driver"
    10.9 +	depends on SCSI
   10.10 +	default m
   10.11 +	help
   10.12 +	  The SCSI frontend driver allows the kernel to access SCSI Devices
   10.13 +	  within another guest OS.
   10.14 +
   10.15  config XEN_GRANT_DEV
   10.16  	tristate "User-space granted page access driver"
   10.17  	default XEN_PRIVILEGED_GUEST
    11.1 --- a/drivers/xen/Makefile	Mon Jun 02 09:58:27 2008 +0100
    11.2 +++ b/drivers/xen/Makefile	Mon Jun 02 09:58:56 2008 +0100
    11.3 @@ -17,6 +17,7 @@ obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pci
    11.4  obj-$(CONFIG_XEN_FRAMEBUFFER)		+= fbfront/
    11.5  obj-$(CONFIG_XEN_KEYBOARD)		+= fbfront/
    11.6  obj-$(CONFIG_XEN_SCSI_BACKEND)		+= scsiback/
    11.7 +obj-$(CONFIG_XEN_SCSI_FRONTEND)		+= scsifront/
    11.8  obj-$(CONFIG_XEN_PRIVCMD)	+= privcmd/
    11.9  obj-$(CONFIG_XEN_GRANT_DEV)	+= gntdev/
   11.10  obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL)		+= sfc_netutil/
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/drivers/xen/scsifront/Makefile	Mon Jun 02 09:58:56 2008 +0100
    12.3 @@ -0,0 +1,3 @@
    12.4 +
    12.5 +obj-$(CONFIG_XEN_SCSI_FRONTEND)	:= xenscsi.o
    12.6 +xenscsi-objs := scsifront.o xenbus.o
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/drivers/xen/scsifront/common.h	Mon Jun 02 09:58:56 2008 +0100
    13.3 @@ -0,0 +1,132 @@
    13.4 +/*
    13.5 + * Xen SCSI frontend driver
    13.6 + *
    13.7 + * Copyright (c) 2008, FUJITSU Limited
    13.8 + *
    13.9 + * This program is free software; you can redistribute it and/or
   13.10 + * modify it under the terms of the GNU General Public License version 2
   13.11 + * as published by the Free Software Foundation; or, when distributed
   13.12 + * separately from the Linux kernel or incorporated into other
   13.13 + * software packages, subject to the following license:
   13.14 + * 
   13.15 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   13.16 + * of this source file (the "Software"), to deal in the Software without
   13.17 + * restriction, including without limitation the rights to use, copy, modify,
   13.18 + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   13.19 + * and to permit persons to whom the Software is furnished to do so, subject to
   13.20 + * the following conditions:
   13.21 + * 
   13.22 + * The above copyright notice and this permission notice shall be included in
   13.23 + * all copies or substantial portions of the Software.
   13.24 + * 
   13.25 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   13.26 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   13.27 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   13.28 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   13.29 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   13.30 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   13.31 + * IN THE SOFTWARE.
   13.32 + */
   13.33 +
   13.34 +#ifndef __XEN_DRIVERS_SCSIFRONT_H__
   13.35 +#define __XEN_DRIVERS_SCSIFRONT_H__
   13.36 +
   13.37 +#include <linux/version.h>
   13.38 +#include <linux/module.h>
   13.39 +#include <linux/kernel.h>
   13.40 +#include <linux/device.h>
   13.41 +#include <linux/kthread.h>
   13.42 +#include <linux/wait.h>
   13.43 +#include <linux/interrupt.h>
   13.44 +#include <linux/spinlock.h>
   13.45 +#include <linux/sched.h>
   13.46 +#include <linux/blkdev.h>
   13.47 +#include <scsi/scsi_cmnd.h>
   13.48 +#include <scsi/scsi_device.h>
   13.49 +#include <scsi/scsi.h>
   13.50 +#include <scsi/scsi_host.h>
   13.51 +#include <xen/xenbus.h>
   13.52 +#include <xen/gnttab.h>
   13.53 +#include <xen/evtchn.h>
   13.54 +#include <xen/interface/xen.h>
   13.55 +#include <xen/interface/io/ring.h>
   13.56 +#include <xen/interface/io/vscsiif.h>
   13.57 +#include <asm/delay.h>
   13.58 +
   13.59 +
   13.60 +#define GRANT_INVALID_REF	0
   13.61 +#define VSCSI_IN_ABORT		1
   13.62 +#define VSCSI_IN_RESET		2
   13.63 +
   13.64 +/* tuning point*/
   13.65 +#define VSCSIIF_DEFAULT_CMD_PER_LUN 10
   13.66 +#define VSCSIIF_MAX_TARGET          64
   13.67 +#define VSCSIIF_MAX_LUN             255
   13.68 +
   13.69 +#define VSCSIIF_RING_SIZE	\
   13.70 +    __RING_SIZE((struct vscsiif_sring *)0, PAGE_SIZE)
   13.71 +#define VSCSIIF_MAX_REQS	VSCSIIF_RING_SIZE
   13.72 +
   13.73 +struct vscsifrnt_shadow {
   13.74 +	uint16_t next_free;
   13.75 +	
   13.76 +	/* command between backend and frontend
   13.77 +	 * VSCSIIF_ACT_SCSI_CDB or VSCSIIF_ACT_SCSI_RESET */
   13.78 +	unsigned char act;
   13.79 +	
   13.80 +	/* do reset function */
   13.81 +	wait_queue_head_t wq_reset;	/* reset work queue           */
   13.82 +	int wait_reset;			/* reset work queue condition */
   13.83 +	int32_t rslt_reset;		/* reset response status      */
   13.84 +					/* (SUCESS or FAILED)         */
   13.85 +
   13.86 +	/* for DMA_TO_DEVICE(1), DMA_FROM_DEVICE(2), DMA_NONE(3) 
   13.87 +	   requests */
   13.88 +	unsigned int sc_data_direction;
   13.89 +	
   13.90 +	/* Number of pieces of scatter-gather */
   13.91 +	unsigned int nr_segments;
   13.92 +
   13.93 +	/* requested struct scsi_cmnd is stored from kernel */
   13.94 +	unsigned long req_scsi_cmnd;
   13.95 +	int gref[VSCSIIF_SG_TABLESIZE];
   13.96 +};
   13.97 +
   13.98 +struct vscsifrnt_info {
   13.99 +	struct xenbus_device *dev;
  13.100 +
  13.101 +	struct Scsi_Host *host;
  13.102 +
  13.103 +	spinlock_t io_lock;
  13.104 +	spinlock_t shadow_lock;
  13.105 +	unsigned int evtchn;
  13.106 +	unsigned int irq;
  13.107 +
  13.108 +	grant_ref_t ring_ref;
  13.109 +	struct vscsiif_front_ring ring;
  13.110 +	struct vscsiif_response	ring_res;
  13.111 +
  13.112 +	struct vscsifrnt_shadow shadow[VSCSIIF_MAX_REQS];
  13.113 +	uint32_t shadow_free;
  13.114 +
  13.115 +	struct task_struct *kthread;
  13.116 +	wait_queue_head_t wq;
  13.117 +	unsigned int waiting_resp;
  13.118 +	
  13.119 +	/* abort reset condition bit*/
  13.120 +	atomic_t abort_reset_cond;
  13.121 +
  13.122 +};
  13.123 +
  13.124 +#define DPRINTK(_f, _a...)				\
  13.125 +	pr_debug("(file=%s, line=%d) " _f,	\
  13.126 +		 __FILE__ , __LINE__ , ## _a )
  13.127 +
  13.128 +int scsifront_xenbus_init(void);
  13.129 +void scsifront_xenbus_unregister(void);
  13.130 +int scsifront_schedule(void *data);
  13.131 +irqreturn_t scsifront_intr(int irq, void *dev_id, struct pt_regs *ptregs);
  13.132 +int scsifront_cmd_done(struct vscsifrnt_info *info);
  13.133 +
  13.134 +
  13.135 +#endif /* __XEN_DRIVERS_SCSIFRONT_H__  */
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/drivers/xen/scsifront/scsifront.c	Mon Jun 02 09:58:56 2008 +0100
    14.3 @@ -0,0 +1,519 @@
    14.4 +/*
    14.5 + * Xen SCSI frontend driver
    14.6 + *
    14.7 + * Copyright (c) 2008, FUJITSU Limited
    14.8 + *
    14.9 + * This program is free software; you can redistribute it and/or
   14.10 + * modify it under the terms of the GNU General Public License version 2
   14.11 + * as published by the Free Software Foundation; or, when distributed
   14.12 + * separately from the Linux kernel or incorporated into other
   14.13 + * software packages, subject to the following license:
   14.14 + * 
   14.15 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   14.16 + * of this source file (the "Software"), to deal in the Software without
   14.17 + * restriction, including without limitation the rights to use, copy, modify,
   14.18 + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   14.19 + * and to permit persons to whom the Software is furnished to do so, subject to
   14.20 + * the following conditions:
   14.21 + * 
   14.22 + * The above copyright notice and this permission notice shall be included in
   14.23 + * all copies or substantial portions of the Software.
   14.24 + * 
   14.25 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   14.26 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   14.27 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   14.28 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   14.29 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   14.30 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   14.31 + * IN THE SOFTWARE.
   14.32 + */
   14.33 + 
   14.34 +
   14.35 +#include <linux/version.h>
   14.36 +#include "common.h"
   14.37 +
   14.38 +static int get_id_from_freelist(struct vscsifrnt_info *info)
   14.39 +{
   14.40 +	unsigned long flags;
   14.41 +	uint32_t free;
   14.42 +
   14.43 +	spin_lock_irqsave(&info->shadow_lock, flags);
   14.44 +
   14.45 +	free = info->shadow_free;
   14.46 +	BUG_ON(free > VSCSIIF_MAX_REQS);
   14.47 +	info->shadow_free = info->shadow[free].next_free;
   14.48 +	info->shadow[free].next_free = 0x0fff;
   14.49 +
   14.50 +	info->shadow[free].wait_reset = 0;
   14.51 +
   14.52 +	spin_unlock_irqrestore(&info->shadow_lock, flags);
   14.53 +
   14.54 +	return free;
   14.55 +}
   14.56 +
   14.57 +static void add_id_to_freelist(struct vscsifrnt_info *info, uint32_t id)
   14.58 +{
   14.59 +	unsigned long flags;
   14.60 +
   14.61 +	spin_lock_irqsave(&info->shadow_lock, flags);
   14.62 +
   14.63 +	info->shadow[id].next_free  = info->shadow_free;
   14.64 +	info->shadow[id].req_scsi_cmnd = 0;
   14.65 +	info->shadow_free = id;
   14.66 +
   14.67 +	spin_unlock_irqrestore(&info->shadow_lock, flags);
   14.68 +}
   14.69 +
   14.70 +
   14.71 +struct vscsiif_request * scsifront_pre_request(struct vscsifrnt_info *info)
   14.72 +{
   14.73 +	struct vscsiif_front_ring *ring = &(info->ring);
   14.74 +	vscsiif_request_t *ring_req;
   14.75 +	uint32_t id;
   14.76 +
   14.77 +	ring_req = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
   14.78 +
   14.79 +	ring->req_prod_pvt++;
   14.80 +	
   14.81 +	id = get_id_from_freelist(info);	/* use id by response */
   14.82 +	ring_req->rqid = (uint16_t)id;
   14.83 +
   14.84 +	return ring_req;
   14.85 +}
   14.86 +
   14.87 +
   14.88 +static void scsifront_notify_work(struct vscsifrnt_info *info)
   14.89 +{
   14.90 +	info->waiting_resp = 1;
   14.91 +	wake_up(&info->wq);
   14.92 +}
   14.93 +
   14.94 +
   14.95 +static void scsifront_do_request(struct vscsifrnt_info *info)
   14.96 +{
   14.97 +	struct vscsiif_front_ring *ring = &(info->ring);
   14.98 +	unsigned int irq = info->irq;
   14.99 +	int notify;
  14.100 +
  14.101 +	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify);
  14.102 +	if (notify)
  14.103 +		notify_remote_via_irq(irq);
  14.104 +}
  14.105 +
  14.106 +irqreturn_t scsifront_intr(int irq, void *dev_id, struct pt_regs *ptregs)
  14.107 +{
  14.108 +	scsifront_notify_work((struct vscsifrnt_info *)dev_id);
  14.109 +	return IRQ_HANDLED;
  14.110 +}
  14.111 +
  14.112 +
  14.113 +static void scsifront_gnttab_done(struct vscsifrnt_shadow *s, uint32_t id)
  14.114 +{
  14.115 +	int i;
  14.116 +
  14.117 +	if (s->sc_data_direction == DMA_NONE)
  14.118 +		return;
  14.119 +
  14.120 +	if (s->nr_segments) {
  14.121 +		for (i = 0; i < s->nr_segments; i++) {
  14.122 +			if (unlikely(gnttab_query_foreign_access(
  14.123 +				s->gref[i]) != 0)) {
  14.124 +				printk(KERN_ALERT "scsifront: "
  14.125 +					"grant still in use by backend.\n");
  14.126 +				BUG();
  14.127 +			}
  14.128 +			gnttab_end_foreign_access(s->gref[i], 0UL);
  14.129 +		}
  14.130 +	}
  14.131 +
  14.132 +	return;
  14.133 +}
  14.134 +
  14.135 +
  14.136 +static void scsifront_cdb_cmd_done(struct vscsifrnt_info *info,
  14.137 +		       vscsiif_response_t *ring_res)
  14.138 +{
  14.139 +	struct scsi_cmnd *sc;
  14.140 +	uint32_t id;
  14.141 +	uint8_t sense_len;
  14.142 +
  14.143 +	id = ring_res->rqid;
  14.144 +	sc = (struct scsi_cmnd *)info->shadow[id].req_scsi_cmnd;
  14.145 +
  14.146 +	if (sc == NULL)
  14.147 +		BUG();
  14.148 +
  14.149 +	scsifront_gnttab_done(&info->shadow[id], id);
  14.150 +	add_id_to_freelist(info, id);
  14.151 +
  14.152 +	rmb();
  14.153 +	if (atomic_read(&info->abort_reset_cond) == VSCSI_IN_RESET) {
  14.154 +		sc->result = (DID_RESET << 16);
  14.155 +	} else {
  14.156 +		sc->result = ring_res->rslt;
  14.157 +	}
  14.158 +
  14.159 +	sc->resid  = 0;
  14.160 +
  14.161 +	if (ring_res->sense_len > VSCSIIF_SENSE_BUFFERSIZE)
  14.162 +		sense_len = VSCSIIF_SENSE_BUFFERSIZE;
  14.163 +	else
  14.164 +		sense_len = ring_res->sense_len;
  14.165 +
  14.166 +	if (sense_len)
  14.167 +		memcpy(sc->sense_buffer, ring_res->sense_buffer, sense_len);
  14.168 +
  14.169 +	sc->scsi_done(sc);
  14.170 +
  14.171 +	return;
  14.172 +}
  14.173 +
  14.174 +
  14.175 +static void scsifront_sync_cmd_done(struct vscsifrnt_info *info,
  14.176 +				vscsiif_response_t *ring_res)
  14.177 +{
  14.178 +	uint16_t id = ring_res->rqid;
  14.179 +	unsigned long flags;
  14.180 +	
  14.181 +	spin_lock_irqsave(&info->shadow_lock, flags);
  14.182 +	info->shadow[id].wait_reset = 1;
  14.183 +	info->shadow[id].rslt_reset = ring_res->rslt;
  14.184 +	spin_unlock_irqrestore(&info->shadow_lock, flags);
  14.185 +
  14.186 +	wake_up(&(info->shadow[id].wq_reset));
  14.187 +}
  14.188 +
  14.189 +
  14.190 +int scsifront_cmd_done(struct vscsifrnt_info *info)
  14.191 +{
  14.192 +	vscsiif_response_t *ring_res;
  14.193 +
  14.194 +	RING_IDX i, rp;
  14.195 +	int more_to_do = 0;
  14.196 +	unsigned long flags;
  14.197 +
  14.198 +	spin_lock_irqsave(&info->io_lock, flags);
  14.199 +
  14.200 +	rp = info->ring.sring->rsp_prod;
  14.201 +	rmb();
  14.202 +	for (i = info->ring.rsp_cons; i != rp; i++) {
  14.203 +		
  14.204 +		ring_res = RING_GET_RESPONSE(&info->ring, i);
  14.205 +
  14.206 +		if (info->shadow[ring_res->rqid].act == VSCSIIF_ACT_SCSI_CDB)
  14.207 +			scsifront_cdb_cmd_done(info, ring_res);
  14.208 +		else
  14.209 +			scsifront_sync_cmd_done(info, ring_res);
  14.210 +	}
  14.211 +
  14.212 +	info->ring.rsp_cons = i;
  14.213 +
  14.214 +	if (i != info->ring.req_prod_pvt) {
  14.215 +		RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do);
  14.216 +	} else {
  14.217 +		info->ring.sring->rsp_event = i + 1;
  14.218 +	}
  14.219 +
  14.220 +	spin_unlock_irqrestore(&info->io_lock, flags);
  14.221 +
  14.222 +	return more_to_do;
  14.223 +}
  14.224 +
  14.225 +
  14.226 +
  14.227 +
  14.228 +int scsifront_schedule(void *data)
  14.229 +{
  14.230 +	struct vscsifrnt_info *info = (struct vscsifrnt_info *)data;
  14.231 +
  14.232 +	while (!kthread_should_stop()) {
  14.233 +		wait_event_interruptible(
  14.234 +			info->wq,
  14.235 +			info->waiting_resp || kthread_should_stop());
  14.236 +
  14.237 +		info->waiting_resp = 0;
  14.238 +		smp_mb();
  14.239 +
  14.240 +		if (scsifront_cmd_done(info))
  14.241 +			info->waiting_resp = 1;
  14.242 +	}
  14.243 +
  14.244 +	info->kthread = NULL;
  14.245 +
  14.246 +	return 0;
  14.247 +}
  14.248 +
  14.249 +
  14.250 +
  14.251 +static int map_data_for_request(struct vscsifrnt_info *info,
  14.252 +		struct scsi_cmnd *sc, vscsiif_request_t *ring_req, uint32_t id)
  14.253 +{
  14.254 +	grant_ref_t gref_head;
  14.255 +	struct page *page;
  14.256 +	int err, i, ref, ref_cnt = 0;
  14.257 +	int write = (sc->sc_data_direction == DMA_TO_DEVICE);
  14.258 +	int nr_pages, off, len, bytes;
  14.259 +	unsigned long buffer_pfn;
  14.260 +	unsigned int data_len = 0;
  14.261 +
  14.262 +	if (sc->sc_data_direction == DMA_NONE)
  14.263 +		return 0;
  14.264 +
  14.265 +	err = gnttab_alloc_grant_references(VSCSIIF_SG_TABLESIZE, &gref_head);
  14.266 +	if (err) {
  14.267 +		printk(KERN_ERR "scsifront: gnttab_alloc_grant_references() error\n");
  14.268 +		return -ENOMEM;
  14.269 +	}
  14.270 +
  14.271 +	if (sc->use_sg) {
  14.272 +		/* quoted scsi_lib.c/scsi_req_map_sg . */
  14.273 +		struct scatterlist *sg = (struct scatterlist *)sc->request_buffer;
  14.274 +		nr_pages = (sc->request_bufflen + sg[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
  14.275 +
  14.276 +		if (nr_pages > VSCSIIF_SG_TABLESIZE) {
  14.277 +			printk(KERN_ERR "scsifront: Unable to map request_buffer for command!\n");
  14.278 +			ref_cnt = (-E2BIG);
  14.279 +			goto big_to_sg;
  14.280 +		}
  14.281 +
  14.282 +		for (i = 0; i < sc->use_sg; i++) {
  14.283 +			page = sg[i].page;
  14.284 +			off = sg[i].offset;
  14.285 +			len = sg[i].length;
  14.286 +			data_len += len;
  14.287 +
  14.288 +			buffer_pfn = page_to_phys(page) >> PAGE_SHIFT;
  14.289 +
  14.290 +			while (len > 0) {
  14.291 +				bytes = min_t(unsigned int, len, PAGE_SIZE - off);
  14.292 +				
  14.293 +				ref = gnttab_claim_grant_reference(&gref_head);
  14.294 +				BUG_ON(ref == -ENOSPC);
  14.295 +
  14.296 +				gnttab_grant_foreign_access_ref(ref, info->dev->otherend_id,
  14.297 +					buffer_pfn, write);
  14.298 +
  14.299 +				info->shadow[id].gref[ref_cnt]  = ref;
  14.300 +				ring_req->seg[ref_cnt].gref     = ref;
  14.301 +				ring_req->seg[ref_cnt].offset   = (uint16_t)off;
  14.302 +				ring_req->seg[ref_cnt].length   = (uint16_t)bytes;
  14.303 +
  14.304 +				buffer_pfn++;
  14.305 +				len -= bytes;
  14.306 +				off = 0;
  14.307 +				ref_cnt++;
  14.308 +			}
  14.309 +		}
  14.310 +	} else if (sc->request_bufflen) {
  14.311 +		unsigned long end   = ((unsigned long)sc->request_buffer
  14.312 +					+ sc->request_bufflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
  14.313 +		unsigned long start = (unsigned long)sc->request_buffer >> PAGE_SHIFT;
  14.314 +
  14.315 +		page = virt_to_page(sc->request_buffer);
  14.316 +		nr_pages = end - start;
  14.317 +		len = sc->request_bufflen;
  14.318 +
  14.319 +		if (nr_pages > VSCSIIF_SG_TABLESIZE) {
  14.320 +			ref_cnt = (-E2BIG);
  14.321 +			goto big_to_sg;
  14.322 +		}
  14.323 +
  14.324 +		buffer_pfn = page_to_phys(page) >> PAGE_SHIFT;
  14.325 +
  14.326 +		off = offset_in_page((unsigned long)sc->request_buffer);
  14.327 +		for (i = 0; i < nr_pages; i++) {
  14.328 +			bytes = PAGE_SIZE - off;
  14.329 +
  14.330 +			if (bytes > len)
  14.331 +				bytes = len;
  14.332 +
  14.333 +			ref = gnttab_claim_grant_reference(&gref_head);
  14.334 +			BUG_ON(ref == -ENOSPC);
  14.335 +
  14.336 +			gnttab_grant_foreign_access_ref(ref, info->dev->otherend_id,
  14.337 +				buffer_pfn, write);
  14.338 +
  14.339 +			info->shadow[id].gref[i] = ref;
  14.340 +			ring_req->seg[i].gref     = ref;
  14.341 +			ring_req->seg[i].offset   = (uint16_t)off;
  14.342 +			ring_req->seg[i].length   = (uint16_t)bytes;
  14.343 +
  14.344 +			buffer_pfn++;
  14.345 +			len -= bytes;
  14.346 +			off = 0;
  14.347 +			ref_cnt++;
  14.348 +		}
  14.349 +	}
  14.350 +
  14.351 +big_to_sg:
  14.352 +
  14.353 +	gnttab_free_grant_references(gref_head);
  14.354 +
  14.355 +	return ref_cnt;
  14.356 +}
  14.357 +
  14.358 +static int scsifront_queuecommand(struct scsi_cmnd *sc,
  14.359 +				  void (*done)(struct scsi_cmnd *))
  14.360 +{
  14.361 +	struct vscsifrnt_info *info =
  14.362 +		(struct vscsifrnt_info *) sc->device->host->hostdata;
  14.363 +	vscsiif_request_t *ring_req;
  14.364 +	int ref_cnt;
  14.365 +	uint16_t rqid;
  14.366 +
  14.367 +	if (RING_FULL(&info->ring)) {
  14.368 +		goto out_host_busy;
  14.369 +	}
  14.370 +
  14.371 +	sc->scsi_done = done;
  14.372 +	sc->result    = 0;
  14.373 +
  14.374 +	ring_req          = scsifront_pre_request(info);
  14.375 +	rqid              = ring_req->rqid;
  14.376 +	ring_req->act     = VSCSIIF_ACT_SCSI_CDB;
  14.377 +
  14.378 +	ring_req->id      = sc->device->id;
  14.379 +	ring_req->lun     = sc->device->lun;
  14.380 +	ring_req->channel = sc->device->channel;
  14.381 +	ring_req->cmd_len = sc->cmd_len;
  14.382 +
  14.383 +	BUG_ON(sc->cmd_len > VSCSIIF_MAX_COMMAND_SIZE);
  14.384 +
  14.385 +	if ( sc->cmd_len )
  14.386 +		memcpy(ring_req->cmnd, sc->cmnd, sc->cmd_len);
  14.387 +	else
  14.388 +		memset(ring_req->cmnd, 0, VSCSIIF_MAX_COMMAND_SIZE);
  14.389 +
  14.390 +	ring_req->sc_data_direction   = (uint8_t)sc->sc_data_direction;
  14.391 +	ring_req->timeout_per_command = (sc->timeout_per_command / HZ);
  14.392 +
  14.393 +	info->shadow[rqid].req_scsi_cmnd     = (unsigned long)sc;
  14.394 +	info->shadow[rqid].sc_data_direction = sc->sc_data_direction;
  14.395 +	info->shadow[rqid].act               = ring_req->act;
  14.396 +
  14.397 +	ref_cnt = map_data_for_request(info, sc, ring_req, rqid);
  14.398 +	if (ref_cnt < 0) {
  14.399 +		add_id_to_freelist(info, rqid);
  14.400 +		if (ref_cnt == (-ENOMEM))
  14.401 +			goto out_host_busy;
  14.402 +		else {
  14.403 +			sc->result = (DID_ERROR << 16);
  14.404 +			goto out_fail_command;
  14.405 +		}
  14.406 +	}
  14.407 +
  14.408 +	ring_req->nr_segments          = (uint8_t)ref_cnt;
  14.409 +	info->shadow[rqid].nr_segments = ref_cnt;
  14.410 +
  14.411 +	scsifront_do_request(info);
  14.412 +
  14.413 +	return 0;
  14.414 +
  14.415 +out_host_busy:
  14.416 +	return SCSI_MLQUEUE_HOST_BUSY;
  14.417 +
  14.418 +out_fail_command:
  14.419 +	done(sc);
  14.420 +	return 0;
  14.421 +}
  14.422 +
  14.423 +
  14.424 +static int scsifront_eh_abort_handler(struct scsi_cmnd *sc)
  14.425 +{
  14.426 +	return (FAILED);
  14.427 +}
  14.428 +
  14.429 +/* vscsi supports only device_reset, because it is each of LUNs */
  14.430 +static int scsifront_dev_reset_handler(struct scsi_cmnd *sc)
  14.431 +{
  14.432 +	struct Scsi_Host *host = sc->device->host;
  14.433 +	struct vscsifrnt_info *info =
  14.434 +		(struct vscsifrnt_info *) sc->device->host->hostdata;
  14.435 +
  14.436 +	vscsiif_request_t *ring_req;
  14.437 +	int err;
  14.438 +
  14.439 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
  14.440 +	spin_lock_irq(host->host_lock);
  14.441 +#endif
  14.442 +
  14.443 +	atomic_set(&info->abort_reset_cond, VSCSI_IN_RESET);
  14.444 +	while (RING_HAS_UNCONSUMED_RESPONSES(&info->ring)) {
  14.445 +		if (!scsifront_cmd_done(info))
  14.446 +			break;
  14.447 +	}
  14.448 +
  14.449 +	ring_req      = scsifront_pre_request(info);
  14.450 +	ring_req->act = VSCSIIF_ACT_SCSI_RESET;
  14.451 +
  14.452 +	info->shadow[ring_req->rqid].act = VSCSIIF_ACT_SCSI_RESET;
  14.453 +
  14.454 +	ring_req->channel = sc->device->channel;
  14.455 +	ring_req->id      = sc->device->id;
  14.456 +	ring_req->lun     = sc->device->lun;
  14.457 +	ring_req->cmd_len = sc->cmd_len;
  14.458 +
  14.459 +	if ( sc->cmd_len )
  14.460 +		memcpy(ring_req->cmnd, sc->cmnd, sc->cmd_len);
  14.461 +	else
  14.462 +		memset(ring_req->cmnd, 0, VSCSIIF_MAX_COMMAND_SIZE);
  14.463 +
  14.464 +	ring_req->sc_data_direction   = (uint8_t)sc->sc_data_direction;
  14.465 +	ring_req->timeout_per_command = (sc->timeout_per_command / HZ);
  14.466 +	ring_req->nr_segments         = 0;
  14.467 +
  14.468 +	spin_unlock_irq(host->host_lock);
  14.469 +	scsifront_do_request(info);	
  14.470 +	wait_event_interruptible(info->shadow[ring_req->rqid].wq_reset,
  14.471 +			 info->shadow[ring_req->rqid].wait_reset);
  14.472 +
  14.473 +	spin_lock_irq(host->host_lock);
  14.474 +
  14.475 +	err = info->shadow[ring_req->rqid].rslt_reset;
  14.476 +	atomic_set(&info->abort_reset_cond, 0);
  14.477 +
  14.478 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
  14.479 +	spin_unlock_irq(host->host_lock);
  14.480 +#endif
  14.481 +
  14.482 +	return (err);
  14.483 +}
  14.484 +
  14.485 +
  14.486 +struct scsi_host_template scsifront_sht = {
  14.487 +	.module			= THIS_MODULE,
  14.488 +	.name			= "Xen SCSI frontend driver",
  14.489 +	.queuecommand		= scsifront_queuecommand,
  14.490 +	.eh_abort_handler	= scsifront_eh_abort_handler,
  14.491 +	.eh_device_reset_handler= scsifront_dev_reset_handler,
  14.492 +	.cmd_per_lun		= VSCSIIF_DEFAULT_CMD_PER_LUN,
  14.493 +	.can_queue		= VSCSIIF_MAX_REQS,
  14.494 +	.this_id 		= -1,
  14.495 +	.sg_tablesize		= VSCSIIF_SG_TABLESIZE,
  14.496 +	.use_clustering		= DISABLE_CLUSTERING,
  14.497 +	.proc_name		= "scsifront",
  14.498 +};
  14.499 +
  14.500 +
  14.501 +static int __init scsifront_init(void)
  14.502 +{
  14.503 +	int err;
  14.504 +
  14.505 +	if (!is_running_on_xen())
  14.506 +		return -ENODEV;
  14.507 +
  14.508 +	err = scsifront_xenbus_init();
  14.509 +
  14.510 +	return err;
  14.511 +}
  14.512 +
  14.513 +static void __exit scsifront_exit(void)
  14.514 +{
  14.515 +	scsifront_xenbus_unregister();
  14.516 +}
  14.517 +
  14.518 +module_init(scsifront_init);
  14.519 +module_exit(scsifront_exit);
  14.520 +
  14.521 +MODULE_DESCRIPTION("Xen SCSI frontend driver");
  14.522 +MODULE_LICENSE("GPL");
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/drivers/xen/scsifront/xenbus.c	Mon Jun 02 09:58:56 2008 +0100
    15.3 @@ -0,0 +1,446 @@
    15.4 +/*
    15.5 + * Xen SCSI frontend driver
    15.6 + *
    15.7 + * Copyright (c) 2008, FUJITSU Limited
    15.8 + *
    15.9 + * This program is free software; you can redistribute it and/or
   15.10 + * modify it under the terms of the GNU General Public License version 2
   15.11 + * as published by the Free Software Foundation; or, when distributed
   15.12 + * separately from the Linux kernel or incorporated into other
   15.13 + * software packages, subject to the following license:
   15.14 + * 
   15.15 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   15.16 + * of this source file (the "Software"), to deal in the Software without
   15.17 + * restriction, including without limitation the rights to use, copy, modify,
   15.18 + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   15.19 + * and to permit persons to whom the Software is furnished to do so, subject to
   15.20 + * the following conditions:
   15.21 + * 
   15.22 + * The above copyright notice and this permission notice shall be included in
   15.23 + * all copies or substantial portions of the Software.
   15.24 + * 
   15.25 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   15.26 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   15.27 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   15.28 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   15.29 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   15.30 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   15.31 + * IN THE SOFTWARE.
   15.32 + */
   15.33 + 
   15.34 +
   15.35 +#include <linux/version.h>
   15.36 +#include "common.h"
   15.37 +
   15.38 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
   15.39 +  #define DEFAULT_TASK_COMM_LEN	16
   15.40 +#else
   15.41 +  #define DEFAULT_TASK_COMM_LEN	TASK_COMM_LEN
   15.42 +#endif
   15.43 +
   15.44 +extern struct scsi_host_template scsifront_sht;
   15.45 +
   15.46 +static void scsifront_free(struct vscsifrnt_info *info)
   15.47 +{
   15.48 +	struct Scsi_Host *host = info->host;
   15.49 +
   15.50 +	if (scsi_host_get(host) != NULL)
   15.51 +		scsi_host_put(host);
   15.52 +
   15.53 +	if (info->ring_ref != GRANT_INVALID_REF) {
   15.54 +		gnttab_end_foreign_access(info->ring_ref,
   15.55 +					(unsigned long)info->ring.sring);
   15.56 +		info->ring_ref = GRANT_INVALID_REF;
   15.57 +		info->ring.sring = NULL;
   15.58 +	}
   15.59 +
   15.60 +	if (info->irq)
   15.61 +		unbind_from_irqhandler(info->irq, info);
   15.62 +	info->irq = 0;
   15.63 +}
   15.64 +
   15.65 +
   15.66 +static int scsifront_alloc_ring(struct vscsifrnt_info *info)
   15.67 +{
   15.68 +	struct xenbus_device *dev = info->dev;
   15.69 +	struct vscsiif_sring *sring;
   15.70 +	int err = -ENOMEM;
   15.71 +
   15.72 +
   15.73 +	info->ring_ref = GRANT_INVALID_REF;
   15.74 +
   15.75 +	/***** Frontend to Backend ring start *****/
   15.76 +	sring = (struct vscsiif_sring *) __get_free_page(GFP_KERNEL);
   15.77 +	if (!sring) {
   15.78 +		xenbus_dev_fatal(dev, err, "fail to allocate shared ring (Front to Back)");
   15.79 +		return err;
   15.80 +	}
   15.81 +	SHARED_RING_INIT(sring);
   15.82 +	FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
   15.83 +
   15.84 +	err = xenbus_grant_ring(dev, virt_to_mfn(sring));
   15.85 +	if (err < 0) {
   15.86 +		free_page((unsigned long) sring);
   15.87 +		info->ring.sring = NULL;
   15.88 +		xenbus_dev_fatal(dev, err, "fail to grant shared ring (Front to Back)");
   15.89 +		goto free_sring;
   15.90 +	}
   15.91 +	info->ring_ref = err;
   15.92 +
   15.93 +	err = bind_listening_port_to_irqhandler(
   15.94 +			dev->otherend_id, scsifront_intr,
   15.95 +			SA_SAMPLE_RANDOM, "scsifront", info);
   15.96 +
   15.97 +	if (err <= 0) {
   15.98 +		xenbus_dev_fatal(dev, err, "bind_listening_port_to_irqhandler");
   15.99 +		goto fail;
  15.100 +	}
  15.101 +	info->irq = err;
  15.102 +
  15.103 +	return 0;
  15.104 +fail:
  15.105 +	/* free resource */
  15.106 +free_sring:
  15.107 +	scsifront_free(info);
  15.108 +
  15.109 +	return err;
  15.110 +}
  15.111 +
  15.112 +
  15.113 +static int scsifront_init_ring(struct vscsifrnt_info *info)
  15.114 +{
  15.115 +	struct xenbus_device *dev = info->dev;
  15.116 +	struct xenbus_transaction xbt;
  15.117 +	int err;
  15.118 +
  15.119 +	DPRINTK("%s\n",__FUNCTION__);
  15.120 +
  15.121 +	err = scsifront_alloc_ring(info);
  15.122 +	if (err)
  15.123 +		return err;
  15.124 +	DPRINTK("%u %u\n", info->ring_ref, info->evtchn);
  15.125 +
  15.126 +again:
  15.127 +	err = xenbus_transaction_start(&xbt);
  15.128 +	if (err) {
  15.129 +		xenbus_dev_fatal(dev, err, "starting transaction");
  15.130 +	}
  15.131 +
  15.132 +	err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u",
  15.133 +				info->ring_ref);
  15.134 +	if (err) {
  15.135 +		xenbus_dev_fatal(dev, err, "%s", "writing ring-ref");
  15.136 +		goto fail;
  15.137 +	}
  15.138 +
  15.139 +	err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
  15.140 +				irq_to_evtchn_port(info->irq));
  15.141 +
  15.142 +	if (err) {
  15.143 +		xenbus_dev_fatal(dev, err, "%s", "writing event-channel");
  15.144 +		goto fail;
  15.145 +	}
  15.146 +
  15.147 +	err = xenbus_printf(xbt, dev->nodename, "vhostno", "%u",
  15.148 +				info->host->host_no);
  15.149 +	if (err) {
  15.150 +		xenbus_dev_fatal(dev, err, "%s", "writing vhostno");
  15.151 +		goto fail;
  15.152 +	}
  15.153 +
  15.154 +	err = xenbus_transaction_end(xbt, 0);
  15.155 +	if (err) {
  15.156 +		if (err == -EAGAIN)
  15.157 +			goto again;
  15.158 +		xenbus_dev_fatal(dev, err, "completing transaction");
  15.159 +	} else
  15.160 +		xenbus_switch_state(dev, XenbusStateInitialised);
  15.161 +
  15.162 +	return 0;
  15.163 +
  15.164 +fail:
  15.165 +	xenbus_transaction_end(xbt, 1);
  15.166 +	/* free resource */
  15.167 +	scsifront_free(info);
  15.168 +	
  15.169 +	return err;
  15.170 +}
  15.171 +
  15.172 +
  15.173 +static int scsifront_probe(struct xenbus_device *dev,
  15.174 +				const struct xenbus_device_id *id)
  15.175 +{
  15.176 +	struct vscsifrnt_info *info;
  15.177 +	struct Scsi_Host *host;
  15.178 +	int i, err = -ENOMEM;
  15.179 +	char name[DEFAULT_TASK_COMM_LEN];
  15.180 +
  15.181 +	host = scsi_host_alloc(&scsifront_sht, sizeof(*info));
  15.182 +	if (!host) {
  15.183 +		xenbus_dev_fatal(dev, err, "fail to allocate scsi host");
  15.184 +		return err;
  15.185 +	}
  15.186 +	info = (struct vscsifrnt_info *) host->hostdata;
  15.187 +	info->host = host;
  15.188 +
  15.189 +
  15.190 +	dev->dev.driver_data = info;
  15.191 +	info->dev  = dev;
  15.192 +
  15.193 +	for (i = 0; i < VSCSIIF_MAX_REQS; i++) {
  15.194 +		info->shadow[i].next_free = i + 1;
  15.195 +		init_waitqueue_head(&(info->shadow[i].wq_reset));
  15.196 +		info->shadow[i].wait_reset = 0;
  15.197 +	}
  15.198 +	info->shadow[VSCSIIF_MAX_REQS - 1].next_free = 0x0fff;
  15.199 +
  15.200 +	atomic_set(&info->abort_reset_cond, 0);
  15.201 +
  15.202 +	err = scsifront_init_ring(info);
  15.203 +	if (err) {
  15.204 +		scsi_host_put(host);
  15.205 +		return err;
  15.206 +	}
  15.207 +
  15.208 +	init_waitqueue_head(&info->wq);
  15.209 +	spin_lock_init(&info->io_lock);
  15.210 +	spin_lock_init(&info->shadow_lock);
  15.211 +
  15.212 +	snprintf(name, DEFAULT_TASK_COMM_LEN, "vscsiif.%d", info->host->host_no);
  15.213 +
  15.214 +	info->kthread = kthread_run(scsifront_schedule, info, name);
  15.215 +	if (IS_ERR(info->kthread)) {
  15.216 +		err = PTR_ERR(info->kthread);
  15.217 +		info->kthread = NULL;
  15.218 +	}
  15.219 +
  15.220 +	host->max_id      = VSCSIIF_MAX_TARGET;
  15.221 +	host->max_channel = 0;
  15.222 +	host->max_lun     = VSCSIIF_MAX_LUN;
  15.223 +	host->max_sectors = (VSCSIIF_SG_TABLESIZE * PAGE_SIZE / 512);
  15.224 +
  15.225 +	err = scsi_add_host(host, &dev->dev);
  15.226 +	if (err) {
  15.227 +		printk(KERN_ERR "scsifront: fail to add scsi host %d\n", err);
  15.228 +		return err;
  15.229 +	}
  15.230 +
  15.231 +	xenbus_switch_state(dev, XenbusStateInitialised);
  15.232 +
  15.233 + #if 0
  15.234 +	/* All SCSI device scan */
  15.235 +	scsi_scan_host(host);
  15.236 +
  15.237 +	err = xenbus_printf(XBT_NIL, dev->nodename, "hotplug-status", "%s",
  15.238 +								"connected");
  15.239 +	if (err) {
  15.240 +		xenbus_dev_fatal(dev, err, "%s", "writing hotplug-status");
  15.241 +		return err;
  15.242 +	}
  15.243 + #endif
  15.244 +	return 0;
  15.245 +}
  15.246 +
  15.247 +static int scsifront_remove(struct xenbus_device *dev)
  15.248 +{
  15.249 +	struct vscsifrnt_info *info = dev->dev.driver_data;
  15.250 +
  15.251 +	DPRINTK("%s: %s removed\n",__FUNCTION__ ,dev->nodename);
  15.252 +
  15.253 +	if (info->kthread) {
  15.254 +		kthread_stop(info->kthread);
  15.255 +		info->kthread = NULL;
  15.256 +	}
  15.257 +
  15.258 +	scsifront_free(info);
  15.259 +	
  15.260 +	return 0;
  15.261 +}
  15.262 +
  15.263 +
  15.264 +static int scsifront_disconnect(struct vscsifrnt_info *info)
  15.265 +{
  15.266 +	struct xenbus_device *dev = info->dev;
  15.267 +	struct Scsi_Host *host = info->host;
  15.268 +
  15.269 +	unsigned long flags;
  15.270 +
  15.271 +	DPRINTK("%s: %s disconnect\n",__FUNCTION__ ,dev->nodename);
  15.272 +
  15.273 +	spin_lock_irqsave(host->host_lock, flags);
  15.274 +	while (RING_HAS_UNCONSUMED_RESPONSES(&info->ring)) {
  15.275 +		if (!scsifront_cmd_done(info))
  15.276 +			break;
  15.277 +	}
  15.278 +
  15.279 +	spin_unlock_irqrestore(host->host_lock, flags);
  15.280 +
  15.281 +	spin_lock(&info->io_lock);
  15.282 +
  15.283 +	scsi_remove_host(host);
  15.284 +	scsi_host_put(host);
  15.285 +
  15.286 +	spin_unlock(&info->io_lock);
  15.287 +
  15.288 +
  15.289 +	xenbus_frontend_closed(dev);
  15.290 +
  15.291 +	return 0;
  15.292 +}
  15.293 +
  15.294 +#define VSCSIFRONT_OP_ADD_LUN	1
  15.295 +#define VSCSIFRONT_OP_DEL_LUN	2
  15.296 +
  15.297 +static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op)
  15.298 +{
  15.299 +	struct xenbus_device *dev = info->dev;
  15.300 +	int i, err = 0;
  15.301 +	char str[64], state_str[64];
  15.302 +	char **dir;
  15.303 +	unsigned int dir_n = 0;
  15.304 +	unsigned int device_state;
  15.305 +	unsigned int hst, chn, tgt, lun;
  15.306 +	struct scsi_device *sdev;
  15.307 +
  15.308 +	dir = xenbus_directory(XBT_NIL, dev->otherend, "vscsi-devs", &dir_n);
  15.309 +	if (IS_ERR(dir))
  15.310 +		return;
  15.311 +
  15.312 +	for (i = 0; i < dir_n; i++) {
  15.313 +		/* read status */
  15.314 +		snprintf(str, sizeof(str), "vscsi-devs/%s/state", dir[i]);
  15.315 +		err = xenbus_scanf(XBT_NIL, dev->otherend, str, "%u",
  15.316 +			&device_state);
  15.317 +		if (XENBUS_EXIST_ERR(err))
  15.318 +			goto fail;
  15.319 +		
  15.320 +		/* virtual SCSI device */
  15.321 +		snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", dir[i]);
  15.322 +		err = xenbus_scanf(XBT_NIL, dev->otherend, str,
  15.323 +			"%u:%u:%u:%u", &hst, &chn, &tgt, &lun);
  15.324 +		if (XENBUS_EXIST_ERR(err))
  15.325 +			goto fail;
  15.326 +
  15.327 +		/* front device state path */
  15.328 +		snprintf(state_str, sizeof(state_str), "vscsi-devs/%s/state", dir[i]);
  15.329 +
  15.330 +		switch (op) {
  15.331 +		case VSCSIFRONT_OP_ADD_LUN:
  15.332 +			if (device_state == XenbusStateInitialised) {
  15.333 +				sdev = scsi_device_lookup(info->host, chn, tgt, lun);
  15.334 +				if (sdev) {
  15.335 +					xenbus_printf(XBT_NIL, dev->nodename,
  15.336 +						state_str, "%d", XenbusStateClosing);
  15.337 +				} else {
  15.338 +					scsi_add_device(info->host, chn, tgt, lun);
  15.339 +					xenbus_printf(XBT_NIL, dev->nodename,
  15.340 +						state_str, "%d", XenbusStateInitialised);
  15.341 +				}
  15.342 +			}
  15.343 +			break;
  15.344 +		case VSCSIFRONT_OP_DEL_LUN:
  15.345 +			if (device_state == XenbusStateClosing) {
  15.346 +				sdev = scsi_device_lookup(info->host, chn, tgt, lun);
  15.347 +				if (sdev) {
  15.348 +					scsi_remove_device(sdev);
  15.349 +					scsi_device_put(sdev);
  15.350 +					xenbus_printf(XBT_NIL, dev->nodename,
  15.351 +						state_str, "%d", XenbusStateClosing);
  15.352 +				} else {
  15.353 +					err = PTR_ERR(sdev);
  15.354 +					goto scsi_del_fail;
  15.355 +				}
  15.356 +			}
  15.357 +			break;
  15.358 +		default:
  15.359 +			goto fail;
  15.360 +			break;
  15.361 +		}
  15.362 +	}
  15.363 +	
  15.364 +	kfree(dir);
  15.365 +	return;
  15.366 +
  15.367 +fail:
  15.368 +	kfree(dir);
  15.369 +	xenbus_dev_fatal(dev, err, "read or write %s ", str);
  15.370 +	return;
  15.371 +
  15.372 +scsi_del_fail:
  15.373 +	kfree(dir);
  15.374 +	printk(KERN_ERR "scsifront: fail to del scsi lun %d\n", err);
  15.375 +	return;
  15.376 +
  15.377 +}
  15.378 +
  15.379 +
  15.380 +
  15.381 +
  15.382 +static void scsifront_backend_changed(struct xenbus_device *dev,
  15.383 +				enum xenbus_state backend_state)
  15.384 +{
  15.385 +	struct vscsifrnt_info *info = dev->dev.driver_data;
  15.386 +
  15.387 +	DPRINTK("%p %u %u\n", dev, dev->state, backend_state);
  15.388 +
  15.389 +	switch (backend_state) {
  15.390 +	case XenbusStateUnknown:
  15.391 +	case XenbusStateInitialising:
  15.392 +	case XenbusStateInitWait:
  15.393 +	case XenbusStateClosed:
  15.394 +		break;
  15.395 +
  15.396 +	case XenbusStateInitialised:
  15.397 +		break;
  15.398 +
  15.399 +	case XenbusStateConnected:
  15.400 +		if (xenbus_read_driver_state(dev->nodename) ==
  15.401 +			XenbusStateInitialised) {
  15.402 +			scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN);
  15.403 +		}
  15.404 +		xenbus_switch_state(dev, XenbusStateConnected);
  15.405 +		break;
  15.406 +
  15.407 +	case XenbusStateClosing:
  15.408 +		scsifront_disconnect(info);
  15.409 +		break;
  15.410 +
  15.411 +	case XenbusStateReconfiguring:
  15.412 +		scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_DEL_LUN);
  15.413 +		xenbus_switch_state(dev, XenbusStateReconfiguring);
  15.414 +		break;
  15.415 +
  15.416 +	case XenbusStateReconfigured:
  15.417 +		scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN);
  15.418 +		xenbus_switch_state(dev, XenbusStateConnected);
  15.419 +		break;
  15.420 +	}
  15.421 +}
  15.422 +
  15.423 +
  15.424 +static struct xenbus_device_id scsifront_ids[] = {
  15.425 +	{ "vscsi" },
  15.426 +	{ "" }
  15.427 +};
  15.428 +
  15.429 +
  15.430 +static struct xenbus_driver scsifront_driver = {
  15.431 +	.name			= "vscsi",
  15.432 +	.owner			= THIS_MODULE,
  15.433 +	.ids			= scsifront_ids,
  15.434 +	.probe			= scsifront_probe,
  15.435 +	.remove			= scsifront_remove,
  15.436 +/* 	.resume			= scsifront_resume, */
  15.437 +	.otherend_changed	= scsifront_backend_changed,
  15.438 +};
  15.439 +
  15.440 +int scsifront_xenbus_init(void)
  15.441 +{
  15.442 +	return xenbus_register_frontend(&scsifront_driver);
  15.443 +}
  15.444 +
  15.445 +void scsifront_xenbus_unregister(void)
  15.446 +{
  15.447 +	xenbus_unregister_driver(&scsifront_driver);
  15.448 +}
  15.449 +