ia64/linux-2.6.18-xen.hg

changeset 562:66faefe721eb

pvSCSI backend 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:27 2008 +0100 (2008-06-02)
parents 557a4a0a5eac
children 3b3701ad4eec
files buildconfigs/linux-defconfig_xen0_ia64 buildconfigs/linux-defconfig_xen0_x86_32 buildconfigs/linux-defconfig_xen0_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/scsiback/Makefile drivers/xen/scsiback/common.h drivers/xen/scsiback/emulate.c drivers/xen/scsiback/interface.c drivers/xen/scsiback/scsiback.c drivers/xen/scsiback/translate.c drivers/xen/scsiback/xenbus.c
line diff
     1.1 --- a/buildconfigs/linux-defconfig_xen0_ia64	Fri May 30 19:08:50 2008 +0100
     1.2 +++ b/buildconfigs/linux-defconfig_xen0_ia64	Mon Jun 02 09:58:27 2008 +0100
     1.3 @@ -1681,6 +1681,7 @@ CONFIG_XEN_PCIDEV_BACKEND=y
     1.4  CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER=y
     1.5  # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
     1.6  CONFIG_XEN_TPMDEV_BACKEND=m
     1.7 +CONFIG_XEN_SCSI_BACKEND=m
     1.8  CONFIG_XEN_BLKDEV_FRONTEND=y
     1.9  CONFIG_XEN_NETDEV_FRONTEND=y
    1.10  CONFIG_XEN_GRANT_DEV=y
     2.1 --- a/buildconfigs/linux-defconfig_xen0_x86_32	Fri May 30 19:08:50 2008 +0100
     2.2 +++ b/buildconfigs/linux-defconfig_xen0_x86_32	Mon Jun 02 09:58:27 2008 +0100
     2.3 @@ -1418,6 +1418,7 @@ CONFIG_XEN_PCIDEV_BACKEND_PASS=y
     2.4  # CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER is not set
     2.5  # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
     2.6  CONFIG_XEN_TPMDEV_BACKEND=m
     2.7 +CONFIG_XEN_SCSI_BACKEND=m
     2.8  CONFIG_XEN_BLKDEV_FRONTEND=y
     2.9  CONFIG_XEN_NETDEV_FRONTEND=y
    2.10  CONFIG_XEN_GRANT_DEV=y
     3.1 --- a/buildconfigs/linux-defconfig_xen0_x86_64	Fri May 30 19:08:50 2008 +0100
     3.2 +++ b/buildconfigs/linux-defconfig_xen0_x86_64	Mon Jun 02 09:58:27 2008 +0100
     3.3 @@ -1359,6 +1359,7 @@ CONFIG_XEN_PCIDEV_BACKEND_PASS=y
     3.4  # CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER is not set
     3.5  # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
     3.6  # CONFIG_XEN_TPMDEV_BACKEND is not set
     3.7 +# CONFIG_XEN_SCSI_BACKEND is not set
     3.8  CONFIG_XEN_BLKDEV_FRONTEND=y
     3.9  CONFIG_XEN_NETDEV_FRONTEND=y
    3.10  CONFIG_XEN_GRANT_DEV=y
     4.1 --- a/buildconfigs/linux-defconfig_xen_ia64	Fri May 30 19:08:50 2008 +0100
     4.2 +++ b/buildconfigs/linux-defconfig_xen_ia64	Mon Jun 02 09:58:27 2008 +0100
     4.3 @@ -1681,6 +1681,7 @@ CONFIG_XEN_PCIDEV_BACKEND=y
     4.4  CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER=y
     4.5  # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
     4.6  CONFIG_XEN_TPMDEV_BACKEND=m
     4.7 +CONFIG_XEN_SCSI_BACKEND=m
     4.8  CONFIG_XEN_BLKDEV_FRONTEND=y
     4.9  CONFIG_XEN_NETDEV_FRONTEND=y
    4.10  CONFIG_XEN_GRANT_DEV=y
     5.1 --- a/buildconfigs/linux-defconfig_xen_x86_32	Fri May 30 19:08:50 2008 +0100
     5.2 +++ b/buildconfigs/linux-defconfig_xen_x86_32	Mon Jun 02 09:58:27 2008 +0100
     5.3 @@ -3276,6 +3276,7 @@ CONFIG_XEN_PCIDEV_BACKEND_VPCI=y
     5.4  # CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER is not set
     5.5  # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
     5.6  CONFIG_XEN_TPMDEV_BACKEND=m
     5.7 +CONFIG_XEN_SCSI_BACKEND=m
     5.8  CONFIG_XEN_BLKDEV_FRONTEND=y
     5.9  CONFIG_XEN_NETDEV_FRONTEND=y
    5.10  CONFIG_XEN_GRANT_DEV=y
     6.1 --- a/buildconfigs/linux-defconfig_xen_x86_64	Fri May 30 19:08:50 2008 +0100
     6.2 +++ b/buildconfigs/linux-defconfig_xen_x86_64	Mon Jun 02 09:58:27 2008 +0100
     6.3 @@ -3106,6 +3106,7 @@ CONFIG_XEN_PCIDEV_BACKEND_PASS=y
     6.4  # CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER is not set
     6.5  # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
     6.6  CONFIG_XEN_TPMDEV_BACKEND=m
     6.7 +CONFIG_XEN_SCSI_BACKEND=m
     6.8  CONFIG_XEN_BLKDEV_FRONTEND=y
     6.9  CONFIG_XEN_NETDEV_FRONTEND=y
    6.10  CONFIG_XEN_GRANT_DEV=y
     7.1 --- a/drivers/xen/Kconfig	Fri May 30 19:08:50 2008 +0100
     7.2 +++ b/drivers/xen/Kconfig	Mon Jun 02 09:58:27 2008 +0100
     7.3 @@ -166,9 +166,17 @@ config XEN_TPMDEV_BACKEND
     7.4  	help
     7.5  	  The TPM-device backend driver
     7.6  
     7.7 +config XEN_SCSI_BACKEND
     7.8 +	tristate "SCSI backend driver"
     7.9 +	depends on XEN_BACKEND
    7.10 +	default n
    7.11 +	help
    7.12 +	  The SCSI backend driver allows the kernel to export its SCSI Devices
    7.13 +	  to other guests via a high-performance shared-memory interface.
    7.14 +
    7.15  config XEN_BLKDEV_FRONTEND
    7.16  	tristate "Block-device frontend driver"
    7.17 -	default y
    7.18 +	default m
    7.19  	help
    7.20  	  The block-device frontend driver allows the kernel to access block
    7.21  	  devices mounted within another guest OS. Unless you are building a
     8.1 --- a/drivers/xen/Makefile	Fri May 30 19:08:50 2008 +0100
     8.2 +++ b/drivers/xen/Makefile	Mon Jun 02 09:58:27 2008 +0100
     8.3 @@ -16,6 +16,7 @@ obj-$(CONFIG_XEN_PCIDEV_BACKEND)	+= pcib
     8.4  obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront/
     8.5  obj-$(CONFIG_XEN_FRAMEBUFFER)		+= fbfront/
     8.6  obj-$(CONFIG_XEN_KEYBOARD)		+= fbfront/
     8.7 +obj-$(CONFIG_XEN_SCSI_BACKEND)		+= scsiback/
     8.8  obj-$(CONFIG_XEN_PRIVCMD)	+= privcmd/
     8.9  obj-$(CONFIG_XEN_GRANT_DEV)	+= gntdev/
    8.10  obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL)		+= sfc_netutil/
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/drivers/xen/scsiback/Makefile	Mon Jun 02 09:58:27 2008 +0100
     9.3 @@ -0,0 +1,4 @@
     9.4 +obj-$(CONFIG_XEN_SCSI_BACKEND) := xen-scsibk.o
     9.5 +
     9.6 +xen-scsibk-y	:= interface.o scsiback.o xenbus.o translate.o
     9.7 +
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/drivers/xen/scsiback/common.h	Mon Jun 02 09:58:27 2008 +0100
    10.3 @@ -0,0 +1,181 @@
    10.4 +/*
    10.5 + * Copyright (c) 2008, FUJITSU Limited
    10.6 + *
    10.7 + * Based on the blkback driver code.
    10.8 + *
    10.9 + * This program is free software; you can redistribute it and/or
   10.10 + * modify it under the terms of the GNU General Public License version 2
   10.11 + * as published by the Free Software Foundation; or, when distributed
   10.12 + * separately from the Linux kernel or incorporated into other
   10.13 + * software packages, subject to the following license:
   10.14 + * 
   10.15 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   10.16 + * of this source file (the "Software"), to deal in the Software without
   10.17 + * restriction, including without limitation the rights to use, copy, modify,
   10.18 + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   10.19 + * and to permit persons to whom the Software is furnished to do so, subject to
   10.20 + * the following conditions:
   10.21 + * 
   10.22 + * The above copyright notice and this permission notice shall be included in
   10.23 + * all copies or substantial portions of the Software.
   10.24 + * 
   10.25 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   10.26 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   10.27 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   10.28 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   10.29 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   10.30 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   10.31 + * IN THE SOFTWARE.
   10.32 + */
   10.33 +
   10.34 +#ifndef __SCSIIF__BACKEND__COMMON_H__
   10.35 +#define __SCSIIF__BACKEND__COMMON_H__
   10.36 +
   10.37 +#include <linux/version.h>
   10.38 +#include <linux/module.h>
   10.39 +#include <linux/interrupt.h>
   10.40 +#include <linux/slab.h>
   10.41 +#include <linux/vmalloc.h>
   10.42 +#include <linux/wait.h>
   10.43 +#include <linux/sched.h>
   10.44 +#include <linux/kthread.h>
   10.45 +#include <linux/blkdev.h>
   10.46 +#include <linux/list.h>
   10.47 +#include <linux/kthread.h>
   10.48 +#include <scsi/scsi.h>
   10.49 +#include <scsi/scsi_cmnd.h>
   10.50 +#include <scsi/scsi_host.h>
   10.51 +#include <scsi/scsi_device.h>
   10.52 +#include <scsi/scsi_dbg.h>
   10.53 +#include <scsi/scsi_eh.h>
   10.54 +#include <asm/io.h>
   10.55 +#include <asm/setup.h>
   10.56 +#include <asm/pgalloc.h>
   10.57 +#include <asm/delay.h>
   10.58 +#include <xen/evtchn.h>
   10.59 +#include <asm/hypervisor.h>
   10.60 +#include <xen/gnttab.h>
   10.61 +#include <xen/driver_util.h>
   10.62 +#include <xen/xenbus.h>
   10.63 +#include <xen/interface/io/ring.h>
   10.64 +#include <xen/interface/grant_table.h>
   10.65 +#include <xen/interface/io/vscsiif.h>
   10.66 +
   10.67 +
   10.68 +
   10.69 +#define DPRINTK(_f, _a...)			\
   10.70 +	pr_debug("(file=%s, line=%d) " _f,	\
   10.71 +		 __FILE__ , __LINE__ , ## _a )
   10.72 +
   10.73 +struct ids_tuple {
   10.74 +	unsigned int hst;		/* host    */
   10.75 +	unsigned int chn;		/* channel */
   10.76 +	unsigned int tgt;		/* target  */
   10.77 +	unsigned int lun;		/* LUN     */
   10.78 +};
   10.79 +
   10.80 +struct v2p_entry {
   10.81 +	struct ids_tuple v;		/* translate from */
   10.82 +	struct scsi_device *sdev;	/* translate to   */
   10.83 +	struct list_head l;
   10.84 +};
   10.85 +
   10.86 +struct vscsibk_info {
   10.87 +	struct xenbus_device *dev;
   10.88 +
   10.89 +	domid_t domid;
   10.90 +	unsigned int evtchn;
   10.91 +	unsigned int irq;
   10.92 +
   10.93 +	struct vscsiif_back_ring  ring;
   10.94 +	struct vm_struct *ring_area;
   10.95 +	grant_handle_t shmem_handle;
   10.96 +	grant_ref_t shmem_ref;
   10.97 +
   10.98 +	spinlock_t ring_lock;
   10.99 +	atomic_t refcnt;
  10.100 +
  10.101 +	spinlock_t v2p_lock;
  10.102 +	struct list_head v2p_entry_lists;
  10.103 +
  10.104 +	struct task_struct *kthread;
  10.105 +	wait_queue_head_t waiting_to_free;
  10.106 +	wait_queue_head_t wq;
  10.107 +	unsigned int waiting_reqs;
  10.108 +	struct page **mmap_pages;
  10.109 +
  10.110 +};
  10.111 +
  10.112 +typedef struct {
  10.113 +	unsigned char act;
  10.114 +	struct vscsibk_info *info;
  10.115 +	struct scsi_device *sdev;
  10.116 +
  10.117 +	uint16_t rqid;
  10.118 +	
  10.119 +	vscsiif_request_t *ring_req;
  10.120 +	
  10.121 +	uint8_t nr_segments;
  10.122 +	uint8_t cmnd[VSCSIIF_MAX_COMMAND_SIZE];
  10.123 +	uint8_t cmd_len;
  10.124 +
  10.125 +	uint8_t sc_data_direction;
  10.126 +	uint16_t timeout_per_command;
  10.127 +	
  10.128 +	uint32_t request_bufflen;
  10.129 +	struct scatterlist *sgl;
  10.130 +	grant_ref_t gref[VSCSIIF_SENSE_BUFFERSIZE];
  10.131 +
  10.132 +	int32_t rslt;
  10.133 +	uint8_t sense_buffer[VSCSIIF_SENSE_BUFFERSIZE];
  10.134 +
  10.135 +	struct list_head free_list;
  10.136 +} pending_req_t;
  10.137 +
  10.138 +
  10.139 +
  10.140 +#define scsiback_get(_b) (atomic_inc(&(_b)->refcnt))
  10.141 +#define scsiback_put(_b)				\
  10.142 +	do {						\
  10.143 +		if (atomic_dec_and_test(&(_b)->refcnt))	\
  10.144 +			wake_up(&(_b)->waiting_to_free);\
  10.145 +	} while (0)
  10.146 +
  10.147 +#define VSCSIIF_TIMEOUT		(900*HZ)
  10.148 +
  10.149 +
  10.150 +irqreturn_t scsiback_intr(int, void *, struct pt_regs *);
  10.151 +int scsiback_init_sring(struct vscsibk_info *info,
  10.152 +		unsigned long ring_ref, unsigned int evtchn);
  10.153 +int scsiback_schedule(void *data);
  10.154 +
  10.155 +
  10.156 +struct vscsibk_info *vscsibk_info_alloc(domid_t domid);
  10.157 +void scsiback_free(struct vscsibk_info *info);
  10.158 +void scsiback_disconnect(struct vscsibk_info *info);
  10.159 +int __init scsiback_interface_init(void);
  10.160 +void __exit scsiback_interface_exit(void);
  10.161 +int scsiback_xenbus_init(void);
  10.162 +void scsiback_xenbus_unregister(void);
  10.163 +
  10.164 +void scsiback_init_translation_table(struct vscsibk_info *info);
  10.165 +
  10.166 +int scsiback_add_translation_entry(struct vscsibk_info *info,
  10.167 +			struct scsi_device *sdev, struct ids_tuple *v);
  10.168 +
  10.169 +int scsiback_del_translation_entry(struct vscsibk_info *info,
  10.170 +				struct ids_tuple *v);
  10.171 +struct scsi_device *scsiback_do_translation(struct vscsibk_info *info,
  10.172 +			struct ids_tuple *v);
  10.173 +void scsiback_release_translation_entry(struct vscsibk_info *info);
  10.174 +
  10.175 +
  10.176 +void scsiback_cmd_exec(pending_req_t *pending_req);
  10.177 +
  10.178 +#if 0 /*SAMPLE CODING(tentative)*//*emulation*/
  10.179 +void scsiback_dispatch_emulation_cmdexec(vscsiif_request_t *ring_req,
  10.180 +				pending_req_t *pending_req);
  10.181 +#endif
  10.182 +
  10.183 +
  10.184 +#endif /* __SCSIIF__BACKEND__COMMON_H__ */
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/drivers/xen/scsiback/emulate.c	Mon Jun 02 09:58:27 2008 +0100
    11.3 @@ -0,0 +1,275 @@
    11.4 +/*
    11.5 + * Xen SCSI backend driver
    11.6 + *
    11.7 + * Copyright (c) 2008, FUJITSU Limited
    11.8 + *
    11.9 + * This program is free software; you can redistribute it and/or
   11.10 + * modify it under the terms of the GNU General Public License version 2
   11.11 + * as published by the Free Software Foundation; or, when distributed
   11.12 + * separately from the Linux kernel or incorporated into other
   11.13 + * software packages, subject to the following license:
   11.14 + * 
   11.15 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   11.16 + * of this source file (the "Software"), to deal in the Software without
   11.17 + * restriction, including without limitation the rights to use, copy, modify,
   11.18 + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   11.19 + * and to permit persons to whom the Software is furnished to do so, subject to
   11.20 + * the following conditions:
   11.21 + * 
   11.22 + * The above copyright notice and this permission notice shall be included in
   11.23 + * all copies or substantial portions of the Software.
   11.24 + * 
   11.25 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   11.26 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   11.27 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   11.28 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   11.29 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   11.30 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   11.31 + * IN THE SOFTWARE.
   11.32 + */
   11.33 +
   11.34 +#include <scsi/scsi.h>
   11.35 +#include <scsi/scsi_cmnd.h>
   11.36 +#include <scsi/scsi_device.h>
   11.37 +#include "comback.h"
   11.38 +
   11.39 +/* Following SCSI commands are not defined in scsi/scsi.h */
   11.40 +#define EXTENDED_COPY		0x83	/* EXTENDED COPY command        */
   11.41 +#define REPORT_ALIASES		0xa3	/* REPORT ALIASES command       */
   11.42 +#define CHANGE_ALIASES		0xa4	/* CHANGE ALIASES command       */
   11.43 +#define SET_PRIORITY		0xa4	/* SET PRIORITY command         */
   11.44 +
   11.45 +
   11.46 +/*
   11.47 +  The bitmap in order to control emulation.
   11.48 +  (Bit 3 to 7 are reserved for future use.)
   11.49 +*/
   11.50 +#define VSCSIIF_NEED_CMD_EXEC		0x01	/* If this bit is set, cmd exec	*/
   11.51 +						/* is required.			*/
   11.52 +#define VSCSIIF_NEED_EMULATE_REQBUF	0x02	/* If this bit is set, need	*/
   11.53 +						/* emulation reqest buff before	*/
   11.54 +						/* cmd exec.			*/
   11.55 +#define VSCSIIF_NEED_EMULATE_RSPBUF	0x04	/* If this bit is set, need	*/
   11.56 +						/* emulation resp buff after	*/
   11.57 +						/* cmd exec.			*/
   11.58 +
   11.59 +/* Additional Sense Code (ASC) used */
   11.60 +#define NO_ADDITIONAL_SENSE		0x0
   11.61 +#define LOGICAL_UNIT_NOT_READY		0x4
   11.62 +#define UNRECOVERED_READ_ERR		0x11
   11.63 +#define PARAMETER_LIST_LENGTH_ERR	0x1a
   11.64 +#define INVALID_OPCODE			0x20
   11.65 +#define ADDR_OUT_OF_RANGE		0x21
   11.66 +#define INVALID_FIELD_IN_CDB		0x24
   11.67 +#define INVALID_FIELD_IN_PARAM_LIST	0x26
   11.68 +#define POWERON_RESET			0x29
   11.69 +#define SAVING_PARAMS_UNSUP		0x39
   11.70 +#define THRESHOLD_EXCEEDED		0x5d
   11.71 +#define LOW_POWER_COND_ON		0x5e
   11.72 +
   11.73 +
   11.74 +
   11.75 +/* Number os SCSI op_code	*/
   11.76 +#define VSCSI_MAX_SCSI_OP_CODE		256
   11.77 +static unsigned char bitmap[VSCSI_MAX_SCSI_OP_CODE];
   11.78 +
   11.79 +/*
   11.80 +  Emulation routines for each SCSI op_code.
   11.81 +*/
   11.82 +static void (*pre_function[MAX_SCSI_OP_CODE])(pending_request_t *, void *);
   11.83 +static void (*post_function[MAX_SCSI_OP_CODE])(pending_request_t *, void *);
   11.84 +
   11.85 +
   11.86 +static const int check_condition_result =
   11.87 +		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
   11.88 +
   11.89 +
   11.90 +static int __copy_to_sg(struct scatterlist *sg, unsigned int nr_sg,
   11.91 +	       void *buf, unsigned int buflen)
   11.92 +{
   11.93 +	void *from = buf;
   11.94 +	void *to;
   11.95 +	unsigned int from_rest = buflen;
   11.96 +	unsigned int to_capa;
   11.97 +	unsigned int copy_size;
   11.98 +	unsigned int i;
   11.99 +
  11.100 +	for (i = 0; i < nr_sg; i++) {
  11.101 +		if (sg->page == NULL) {
  11.102 +			printk(KERN_WARN "%s: inconsistent length field in "
  11.103 +			       "scatterlist\n", __FUNCTION__);
  11.104 +			return -1;
  11.105 +		}
  11.106 +
  11.107 +		to_capa  = sg->length;
  11.108 +		copy_size = min_t(to_capa, from_rest);
  11.109 +
  11.110 +		to = page_to_virt(sg->page) + (sg->offset);
  11.111 +		memcpy(to, from, copy_size);
  11.112 +
  11.113 +		from_rest  -= copy_size;
  11.114 +		if (from_rest == 0) {
  11.115 +			return 0;
  11.116 +		}
  11.117 +		
  11.118 +		sg++;
  11.119 +		from += copy_size;
  11.120 +	}
  11.121 +
  11.122 +	printk(KERN_WARN "%s: no space in scatterlist\n",
  11.123 +	       __FUNCTION__);
  11.124 +	return -1;
  11.125 +}
  11.126 +
  11.127 +static int __copy_from_sg(struct scatterlist *sg, unsigned int nr_sg,
  11.128 +		 void *buf, unsigned int buflen)
  11.129 +{
  11.130 +	void *from;
  11.131 +	void *to = buf;
  11.132 +	unsigned int from_rest;
  11.133 +	unsigned int to_capa = buflen;
  11.134 +	unsigned int copy_size;
  11.135 +	unsigned int i;
  11.136 +
  11.137 +	for (i = 0; i < nr_sg; i++) {
  11.138 +		if (sg->page == NULL) {
  11.139 +			printk(KERN_WARN "%s: inconsistent length field in "
  11.140 +			       "scatterlist\n", __FUNCTION__);
  11.141 +			return -1;
  11.142 +		}
  11.143 +
  11.144 +		from_rest = sg->length;
  11.145 +		if ((from_rest > 0) && (to_capa < from_rest)) {
  11.146 +			printk(KERN_WARN
  11.147 +			       "%s: no space in destination buffer\n",
  11.148 +			       __FUNCTION__);
  11.149 +			return -1;
  11.150 +		}
  11.151 +		copy_size = from_rest;
  11.152 +
  11.153 +		from = page_to_virt(sg->page) + (sg->offset);
  11.154 +		memcpy(to, from, copy_size);
  11.155 +
  11.156 +		to_capa  -= copy_size;
  11.157 +		
  11.158 +		sg++;
  11.159 +		to += copy_size;
  11.160 +	}
  11.161 +
  11.162 +	return 0;
  11.163 +}
  11.164 +
  11.165 +
  11.166 +static void scsiback_mk_sense_buffer(uint8_t *date, uint8_t key, uint8_t asc,
  11.167 +				utint_8 asq)
  11.168 +{
  11.169 +	data[0] = 0x70;  /* fixed, current */
  11.170 +	data[2] = key;
  11.171 +	data[7] = 0xa;	  /* implies 18 byte sense buffer */
  11.172 +	data[12] = asc;
  11.173 +	data[13] = asq;
  11.174 +}
  11.175 +
  11.176 +
  11.177 +
  11.178 +/* tuning point*/
  11.179 +#define VSCSIIF_RLUN_ARR_SZ		2048
  11.180 +
  11.181 +/* quoted scsi_debug.c/resp_report_luns() */
  11.182 +static void __report_luns(pending_request_t *pending_req, void *data)
  11.183 +{
  11.184 +	struct vscsibk_info *info   = pending_req->info;
  11.185 +	unsigned int        channel = pending_req->sdev->channel;
  11.186 +	unsigned int        target  = pending_req->sdev->id;
  11.187 +	unsigned char *cmd = (unsigned char *)pending_req->cmnd;
  11.188 +	
  11.189 +	unsigned char rq_buff[VSCSIIF_RLUN_ARR_SZ];
  11.190 +	unsigned char *sense_buf = pending_req->sense_buffer;
  11.191 +	unsigned char alloc_len;
  11.192 +	int select_report = (int)cmd[2];
  11.193 +	int lun_cnt = 0;
  11.194 +	
  11.195 +	struct v2p_entry *entry;
  11.196 +	struct list_head *head = &(info->v2p_entry_lists);
  11.197 +	unsigned long flags;
  11.198 +	
  11.199 +	struct scsi_lun *one_lun;
  11.200 +
  11.201 +	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
  11.202 +	if ((alloc_len < 4) || (select_report != 0)) {
  11.203 +		scsiback_mk_sense_buffer(pending_req->sense_buffer, ILLEGAL_REQUEST,
  11.204 +			INVALID_FIELD_IN_CDB, 0);
  11.205 +		pending_req->rslt = check_condition_result;
  11.206 +		return;
  11.207 +	}
  11.208 +
  11.209 +	memset(rq_buff, 0, VSCSIIF_RLUN_ARR_SZ);
  11.210 +	__copy_from_sg(pending_req->sgl, pending_req->nr_segments,
  11.211 +		rq_buff, VSCSIIF_RLUN_ARR_SZ);
  11.212 +
  11.213 +
  11.214 +	rq_buff[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
  11.215 +	rq_buff[3] = (sizeof(struct scsi_lun) * num) & 0xff;
  11.216 +
  11.217 +
  11.218 +	one_lun = (struct scsi_lun *) &rq_buff[8];
  11.219 +	spin_lock_irqsave(&info->v2p_lock, flags);
  11.220 +	list_for_each_entry(entry, head, l) {
  11.221 +		if ((entry->v.chn == channel) &&
  11.222 +		    (entry->v.tgt == target) {
  11.223 +			lun = entry->v.lun;
  11.224 +			upper = (lun >> 8) & 0x3f;
  11.225 +			if (upper)
  11.226 +				one_lun[lun_cnt].scsi_lun[0] = upper;
  11.227 +			one_lun[lun_cnt].scsi_lun[1] = lun & 0xff;
  11.228 +			lun_cnt++;
  11.229 +		}
  11.230 +	}
  11.231 +	spin_unlock_irqrestore(&info->v2p_lock, flags);
  11.232 +
  11.233 +
  11.234 +	lun_alloc = (unsigned char *)(one_lun + lun_cnt) - rq_buff;
  11.235 +	
  11.236 +	return fill_from_dev_buffer(scp, rq_buff,
  11.237 +				    min((int)alloc_len, lun_alloc));
  11.238 +}
  11.239 +
  11.240 +
  11.241 +
  11.242 +int __pre_do_emulation(pending_request_t *pending_req, void *data)
  11.243 +{
  11.244 +	uint8_t op_code = pending_req->cmnd[0];
  11.245 +
  11.246 +	if ((bitmap[op_code] & VSCSIIF_NEED_EMULATE_REQBUF) &&
  11.247 +	    pre_function[op_code] != NULL) {
  11.248 +		pre_function[op_code](pending_req, data);
  11.249 +	}
  11.250 +
  11.251 +	/*
  11.252 +	    0: no need for native driver call, so should return immediately.
  11.253 +	    1: non emulation or should call native driver 
  11.254 +	       after modifing the request buffer.
  11.255 +	*/
  11.256 +	return (bitmap[op_code] & VSCSIIF_NEED_CMD_EXEC);
  11.257 +}
  11.258 +
  11.259 +void scsiback_rsp_emulation(pending_request_t *pending_req)
  11.260 +{
  11.261 +	uint8_t op_code = pending_req->cdb[0];
  11.262 +
  11.263 +	if ((bitmap[op_code] & VSCSIIF_NEED_EMULATE_RSPBUF) &&
  11.264 +	    post_function[op_code] != NULL) {
  11.265 +		post_function[op_code](pending_req, NULL);
  11.266 +	}
  11.267 +
  11.268 +	return;
  11.269 +}
  11.270 +
  11.271 +
  11.272 +void scsiback_req_emulation_or_cmdexec(pending_req_t *pending_req)
  11.273 +{
  11.274 +	if (__pre_do_emulation(pending_req, NULL))
  11.275 +		scsiback_cmd_exec(pending_req);
  11.276 +	else 
  11.277 +		scsiback_do_resp_with_sense(pending_req);
  11.278 +}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/drivers/xen/scsiback/interface.c	Mon Jun 02 09:58:27 2008 +0100
    12.3 @@ -0,0 +1,184 @@
    12.4 +/*
    12.5 + * interface management.
    12.6 + *
    12.7 + * Copyright (c) 2008, FUJITSU Limited
    12.8 + *
    12.9 + * Based on the blkback driver code.
   12.10 + *
   12.11 + * This program is free software; you can redistribute it and/or
   12.12 + * modify it under the terms of the GNU General Public License version 2
   12.13 + * as published by the Free Software Foundation; or, when distributed
   12.14 + * separately from the Linux kernel or incorporated into other
   12.15 + * software packages, subject to the following license:
   12.16 + * 
   12.17 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   12.18 + * of this source file (the "Software"), to deal in the Software without
   12.19 + * restriction, including without limitation the rights to use, copy, modify,
   12.20 + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   12.21 + * and to permit persons to whom the Software is furnished to do so, subject to
   12.22 + * the following conditions:
   12.23 + * 
   12.24 + * The above copyright notice and this permission notice shall be included in
   12.25 + * all copies or substantial portions of the Software.
   12.26 + * 
   12.27 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   12.28 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   12.29 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   12.30 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   12.31 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   12.32 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   12.33 + * IN THE SOFTWARE.
   12.34 + */
   12.35 +
   12.36 +#include <scsi/scsi.h>
   12.37 +#include <scsi/scsi_host.h>
   12.38 +#include <scsi/scsi_device.h>
   12.39 +#include "common.h"
   12.40 +
   12.41 +#include <xen/evtchn.h>
   12.42 +#include <linux/kthread.h>
   12.43 +
   12.44 +
   12.45 +static kmem_cache_t *scsiback_cachep;
   12.46 +
   12.47 +struct vscsibk_info *vscsibk_info_alloc(domid_t domid)
   12.48 +{
   12.49 +	struct vscsibk_info *info;
   12.50 +
   12.51 +	info = kmem_cache_alloc(scsiback_cachep, GFP_KERNEL);
   12.52 +	if (!info)
   12.53 +		return ERR_PTR(-ENOMEM);
   12.54 +
   12.55 +	memset(info, 0, sizeof(*info));
   12.56 +	info->domid = domid;
   12.57 +	spin_lock_init(&info->ring_lock);
   12.58 +	atomic_set(&info->refcnt, 1);
   12.59 +	init_waitqueue_head(&info->wq);
   12.60 +	init_waitqueue_head(&info->waiting_to_free);
   12.61 +
   12.62 +	return info;
   12.63 +}
   12.64 +
   12.65 +static int map_frontend_page( struct vscsibk_info *info,
   12.66 +				unsigned long ring_ref)
   12.67 +{
   12.68 +	struct gnttab_map_grant_ref op;
   12.69 +	int err;
   12.70 +
   12.71 +	gnttab_set_map_op(&op, (unsigned long)info->ring_area->addr,
   12.72 +				GNTMAP_host_map, ring_ref,
   12.73 +				info->domid);
   12.74 +
   12.75 +	err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
   12.76 +	BUG_ON(err);
   12.77 +
   12.78 +	if (op.status) {
   12.79 +		printk(KERN_ERR "scsiback: Grant table operation failure !\n");
   12.80 +		return op.status;
   12.81 +	}
   12.82 +
   12.83 +	info->shmem_ref    = ring_ref;
   12.84 +	info->shmem_handle = op.handle;
   12.85 +
   12.86 +	return 0;
   12.87 +}
   12.88 +
   12.89 +static void unmap_frontend_page(struct vscsibk_info *info)
   12.90 +{
   12.91 +	struct gnttab_unmap_grant_ref op;
   12.92 +	int err;
   12.93 +
   12.94 +	gnttab_set_unmap_op(&op, (unsigned long)info->ring_area->addr,
   12.95 +				GNTMAP_host_map, info->shmem_handle);
   12.96 +
   12.97 +	err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
   12.98 +	BUG_ON(err);
   12.99 +
  12.100 +}
  12.101 +
  12.102 +int scsiback_init_sring(struct vscsibk_info *info,
  12.103 +		unsigned long ring_ref, unsigned int evtchn)
  12.104 +{
  12.105 +	struct vscsiif_sring *sring;
  12.106 +	int err;
  12.107 +
  12.108 +	if (info->irq) {
  12.109 +		printk(KERN_ERR "scsiback: Already connected through?\n");
  12.110 +		return 0;
  12.111 +	}
  12.112 +
  12.113 +	info->ring_area = alloc_vm_area(PAGE_SIZE);
  12.114 +	if (!info)
  12.115 +		return -ENOMEM;
  12.116 +
  12.117 +	err = map_frontend_page(info, ring_ref);
  12.118 +	if (err)
  12.119 +		goto free_vm;
  12.120 +
  12.121 +	sring = (struct vscsiif_sring *) info->ring_area->addr;
  12.122 +	BACK_RING_INIT(&info->ring, sring, PAGE_SIZE);
  12.123 +
  12.124 +	err = bind_interdomain_evtchn_to_irqhandler(
  12.125 +			info->domid, evtchn,
  12.126 +			scsiback_intr, 0, "vscsiif-backend", info);
  12.127 +
  12.128 +	if (err < 0)
  12.129 +		goto unmap_page;
  12.130 +		
  12.131 +	info->irq = err;
  12.132 +	
  12.133 +	return 0;
  12.134 +
  12.135 +unmap_page:
  12.136 +	unmap_frontend_page(info);
  12.137 +free_vm:
  12.138 +	free_vm_area(info->ring_area);
  12.139 +
  12.140 +	return err;
  12.141 +}
  12.142 +
  12.143 +void scsiback_disconnect(struct vscsibk_info *info)
  12.144 +{
  12.145 +	if (info->kthread) {
  12.146 +		kthread_stop(info->kthread);
  12.147 +		info->kthread = NULL;
  12.148 +	}
  12.149 +
  12.150 +	atomic_dec(&info->refcnt);
  12.151 +	wait_event(info->waiting_to_free, atomic_read(&info->refcnt) == 0);
  12.152 +	atomic_inc(&info->refcnt);
  12.153 +
  12.154 +	if (info->irq) {
  12.155 +		unbind_from_irqhandler(info->irq, info);
  12.156 +		info->irq = 0;
  12.157 +	}
  12.158 +
  12.159 +	if (info->ring.sring) {
  12.160 +		unmap_frontend_page(info);
  12.161 +		free_vm_area(info->ring_area);
  12.162 +		info->ring.sring = NULL;
  12.163 +	}
  12.164 +}
  12.165 +
  12.166 +void scsiback_free(struct vscsibk_info *info)
  12.167 +{
  12.168 +	if (atomic_dec_and_test(&info->refcnt))
  12.169 +		kmem_cache_free(scsiback_cachep, info);
  12.170 +}
  12.171 +
  12.172 +int __init scsiback_interface_init(void)
  12.173 +{
  12.174 +	scsiback_cachep = kmem_cache_create("vscsiif_cache",
  12.175 +		sizeof(struct vscsibk_info), 0, 0, NULL, NULL);
  12.176 +	if (!scsiback_cachep) {
  12.177 +		printk(KERN_ERR "scsiback: can't init scsi cache\n");
  12.178 +		return -ENOMEM;
  12.179 +	}
  12.180 +	
  12.181 +	return 0;
  12.182 +}
  12.183 +
  12.184 +void __exit scsiback_interface_exit(void)
  12.185 +{
  12.186 +	kmem_cache_destroy(scsiback_cachep);
  12.187 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/drivers/xen/scsiback/scsiback.c	Mon Jun 02 09:58:27 2008 +0100
    13.3 @@ -0,0 +1,734 @@
    13.4 +/*
    13.5 + * Xen SCSI backend driver
    13.6 + *
    13.7 + * Copyright (c) 2008, FUJITSU Limited
    13.8 + *
    13.9 + * Based on the blkback driver code.
   13.10 + *
   13.11 + * This program is free software; you can redistribute it and/or
   13.12 + * modify it under the terms of the GNU General Public License version 2
   13.13 + * as published by the Free Software Foundation; or, when distributed
   13.14 + * separately from the Linux kernel or incorporated into other
   13.15 + * software packages, subject to the following license:
   13.16 + * 
   13.17 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   13.18 + * of this source file (the "Software"), to deal in the Software without
   13.19 + * restriction, including without limitation the rights to use, copy, modify,
   13.20 + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   13.21 + * and to permit persons to whom the Software is furnished to do so, subject to
   13.22 + * the following conditions:
   13.23 + * 
   13.24 + * The above copyright notice and this permission notice shall be included in
   13.25 + * all copies or substantial portions of the Software.
   13.26 + * 
   13.27 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   13.28 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   13.29 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   13.30 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   13.31 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   13.32 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   13.33 + * IN THE SOFTWARE.
   13.34 + */
   13.35 +
   13.36 +#include <linux/spinlock.h>
   13.37 +#include <linux/kthread.h>
   13.38 +#include <linux/list.h>
   13.39 +#include <linux/delay.h>
   13.40 +#include <xen/balloon.h>
   13.41 +#include <asm/hypervisor.h>
   13.42 +#include <scsi/scsi.h>
   13.43 +#include <scsi/scsi_cmnd.h>
   13.44 +#include <scsi/scsi_host.h>
   13.45 +#include <scsi/scsi_device.h>
   13.46 +#include <scsi/scsi_dbg.h>
   13.47 +#include <scsi/scsi_eh.h>
   13.48 +
   13.49 +#include "common.h"
   13.50 +
   13.51 +
   13.52 +#define  NO_ASYNC  1 /*!aync*/
   13.53 +
   13.54 +struct list_head pending_free;
   13.55 +DEFINE_SPINLOCK(pending_free_lock);
   13.56 +DECLARE_WAIT_QUEUE_HEAD(pending_free_wq);
   13.57 +
   13.58 +int vscsiif_reqs = VSCSIIF_BACK_MAX_PENDING_REQS;
   13.59 +module_param_named(reqs, vscsiif_reqs, int, 0);
   13.60 +MODULE_PARM_DESC(reqs, "Number of scsiback requests to allocate");
   13.61 +
   13.62 +
   13.63 +#define SCSIBACK_INVALID_HANDLE (~0)
   13.64 +
   13.65 +static pending_req_t *pending_reqs;
   13.66 +static struct page **pending_pages;
   13.67 +static grant_handle_t *pending_grant_handles;
   13.68 +
   13.69 +static int vaddr_pagenr(pending_req_t *req, int seg)
   13.70 +{
   13.71 +	return (req - pending_reqs) * VSCSIIF_SG_TABLESIZE + seg;
   13.72 +}
   13.73 +
   13.74 +static unsigned long vaddr(pending_req_t *req, int seg)
   13.75 +{
   13.76 +	unsigned long pfn = page_to_pfn(pending_pages[vaddr_pagenr(req, seg)]);
   13.77 +	return (unsigned long)pfn_to_kaddr(pfn);
   13.78 +}
   13.79 +
   13.80 +#define pending_handle(_req, _seg) \
   13.81 +	(pending_grant_handles[vaddr_pagenr(_req, _seg)])
   13.82 +
   13.83 +
   13.84 +static void fast_flush_area(pending_req_t *req)
   13.85 +{
   13.86 +	struct gnttab_unmap_grant_ref unmap[VSCSIIF_SG_TABLESIZE];
   13.87 +	unsigned int i, invcount = 0;
   13.88 +	grant_handle_t handle;
   13.89 +	int err;
   13.90 +
   13.91 +	if (req->nr_segments) {
   13.92 +		for (i = 0; i < req->nr_segments; i++) {
   13.93 +			handle = pending_handle(req, i);
   13.94 +			if (handle == SCSIBACK_INVALID_HANDLE)
   13.95 +				continue;
   13.96 +			gnttab_set_unmap_op(&unmap[i], vaddr(req, i),
   13.97 +						GNTMAP_host_map, handle);
   13.98 +			pending_handle(req, i) = SCSIBACK_INVALID_HANDLE;
   13.99 +			invcount++;
  13.100 +		}
  13.101 +
  13.102 +		err = HYPERVISOR_grant_table_op(
  13.103 +			GNTTABOP_unmap_grant_ref, unmap, invcount);
  13.104 +		BUG_ON(err);
  13.105 +		kfree(req->sgl);
  13.106 +	}
  13.107 +
  13.108 +	return;
  13.109 +}
  13.110 +
  13.111 +
  13.112 +static pending_req_t * alloc_req(struct vscsibk_info *info)
  13.113 +{
  13.114 +	pending_req_t *req = NULL;
  13.115 +	unsigned long flags;
  13.116 +
  13.117 +	spin_lock_irqsave(&pending_free_lock, flags);
  13.118 +	if (!list_empty(&pending_free)) {
  13.119 +		req = list_entry(pending_free.next, pending_req_t, free_list);
  13.120 +		list_del(&req->free_list);
  13.121 +	}
  13.122 +	spin_unlock_irqrestore(&pending_free_lock, flags);
  13.123 +	return req;
  13.124 +}
  13.125 +
  13.126 +
  13.127 +static void free_req(pending_req_t *req)
  13.128 +{
  13.129 +	unsigned long flags;
  13.130 +	int was_empty;
  13.131 +
  13.132 +	spin_lock_irqsave(&pending_free_lock, flags);
  13.133 +	was_empty = list_empty(&pending_free);
  13.134 +	list_add(&req->free_list, &pending_free);
  13.135 +	spin_unlock_irqrestore(&pending_free_lock, flags);
  13.136 +	if (was_empty)
  13.137 +		wake_up(&pending_free_wq);
  13.138 +}
  13.139 +
  13.140 +
  13.141 +static void scsiback_notify_work(struct vscsibk_info *info)
  13.142 +{
  13.143 +	info->waiting_reqs = 1;
  13.144 +	wake_up(&info->wq);
  13.145 +}
  13.146 +
  13.147 +static void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result,
  13.148 +				pending_req_t *pending_req)
  13.149 +{
  13.150 +	vscsiif_response_t *ring_res;
  13.151 +	struct vscsibk_info *info = pending_req->info;
  13.152 +	int notify;
  13.153 +	int more_to_do = 1;
  13.154 +	unsigned long flags;
  13.155 +
  13.156 +	DPRINTK("%s\n",__FUNCTION__);
  13.157 +
  13.158 +	spin_lock_irqsave(&info->ring_lock, flags);
  13.159 +
  13.160 +	rmb();
  13.161 +	ring_res = RING_GET_RESPONSE(&info->ring, info->ring.rsp_prod_pvt);
  13.162 +	info->ring.rsp_prod_pvt++;
  13.163 +
  13.164 +	ring_res->rslt   = result;
  13.165 +	ring_res->rqid   = pending_req->rqid;
  13.166 +
  13.167 +	if (sense_buffer != NULL) {
  13.168 +		memcpy(ring_res->sense_buffer, sense_buffer,
  13.169 +				VSCSIIF_SENSE_BUFFERSIZE);
  13.170 +		ring_res->sense_len = VSCSIIF_SENSE_BUFFERSIZE;
  13.171 +	} else {
  13.172 +		ring_res->sense_len = 0;
  13.173 +	}
  13.174 +
  13.175 +	RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&info->ring, notify);
  13.176 +	if (info->ring.rsp_prod_pvt == info->ring.req_cons) {
  13.177 +		RING_FINAL_CHECK_FOR_REQUESTS(&info->ring, more_to_do);
  13.178 +	} else if (RING_HAS_UNCONSUMED_REQUESTS(&info->ring)) {
  13.179 +		more_to_do = 1;
  13.180 +	}
  13.181 +	
  13.182 +	spin_unlock_irqrestore(&info->ring_lock, flags);
  13.183 +
  13.184 +	if (more_to_do)
  13.185 +		scsiback_notify_work(info);
  13.186 +
  13.187 +	if (notify)
  13.188 +		notify_remote_via_irq(info->irq);
  13.189 +
  13.190 +	scsiback_put(pending_req->info);
  13.191 +	free_req(pending_req);
  13.192 +}
  13.193 +
  13.194 +#ifdef NO_ASYNC /*!async*/
  13.195 +static void scsiback_cmd_done(struct request *req, int errors)
  13.196 +{
  13.197 +	pending_req_t *pending_req = req->end_io_data;
  13.198 +	struct scsi_device *sdev = pending_req->sdev;
  13.199 +	unsigned char *sense_buffer;
  13.200 +
  13.201 +	sense_buffer = req->sense;
  13.202 +
  13.203 +#else
  13.204 +static void scsiback_cmd_done(void *data, char *sense_buffer,
  13.205 +				int errors, int resid)
  13.206 +{
  13.207 +	pending_req_t *pending_req = data;
  13.208 +	struct scsi_device *sdev = pending_req->sdev;
  13.209 +
  13.210 +	DPRINTK("%s\n",__FUNCTION__);
  13.211 +#endif
  13.212 +
  13.213 +	if ((errors != 0) && (pending_req->cmnd[0] != TEST_UNIT_READY)) {
  13.214 +
  13.215 +		printk(KERN_ERR "scsiback: %d:%d:%d:%d ",sdev->host->host_no,
  13.216 +				sdev->channel, sdev->id, sdev->lun);
  13.217 +		printk(KERN_ERR "status = 0x%02x, message = 0x%02x, host = 0x%02x, driver = 0x%02x\n",
  13.218 +				status_byte(errors), msg_byte(errors),
  13.219 +				host_byte(errors), driver_byte(errors));
  13.220 +
  13.221 +		printk(KERN_ERR "scsiback: cmnd[0]=0x%02X nr_segments=%d\n",
  13.222 +				pending_req->cmnd[0],
  13.223 +				pending_req->nr_segments);
  13.224 +
  13.225 +		if (CHECK_CONDITION & status_byte(errors))
  13.226 +			__scsi_print_sense("scsiback", sense_buffer, SCSI_SENSE_BUFFERSIZE);
  13.227 +	}
  13.228 +
  13.229 +#if 0 /*SAMPLE CODING(tentative)*//*emulation*/
  13.230 +	scsiback_rsp_emulation(pending_req);
  13.231 +#endif
  13.232 +	fast_flush_area(pending_req);
  13.233 +	scsiback_do_resp_with_sense(sense_buffer, errors, pending_req);
  13.234 +
  13.235 +
  13.236 +#ifdef NO_ASYNC /*!async*/
  13.237 +	__blk_put_request(req->q, req);
  13.238 +#endif
  13.239 +}
  13.240 +
  13.241 +
  13.242 +static int scsiback_gnttab_data_map(vscsiif_request_t *ring_req,
  13.243 +					pending_req_t *pending_req)
  13.244 +{
  13.245 +	u32 flags;
  13.246 +	int write;
  13.247 +	int i, err = 0;
  13.248 +	unsigned int data_len = 0;
  13.249 +	struct gnttab_map_grant_ref map[VSCSIIF_SG_TABLESIZE];
  13.250 +	struct vscsibk_info *info   = pending_req->info;
  13.251 +
  13.252 +	int data_dir = (int)pending_req->sc_data_direction;
  13.253 +	unsigned int nr_segments = (unsigned int)pending_req->nr_segments;
  13.254 +
  13.255 +	write = (data_dir == DMA_TO_DEVICE);
  13.256 +
  13.257 +	if (nr_segments) {
  13.258 +		/* free of (sgl) in fast_flush_area()*/
  13.259 +		pending_req->sgl = kmalloc(sizeof(struct scatterlist) * nr_segments,
  13.260 +						GFP_KERNEL);
  13.261 +		if (!pending_req->sgl) {
  13.262 +			printk(KERN_ERR "scsiback: %s: kmalloc() error.\n", __FUNCTION__);
  13.263 +			return -ENOMEM;
  13.264 +		}
  13.265 +
  13.266 +		for (i = 0; i < nr_segments; i++) {
  13.267 +			flags = GNTMAP_host_map;
  13.268 +			if (write)
  13.269 +				flags |= GNTMAP_readonly;
  13.270 +			gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags,
  13.271 +						ring_req->seg[i].gref,
  13.272 +						info->domid);
  13.273 +		}
  13.274 +
  13.275 +		err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nr_segments);
  13.276 +		BUG_ON(err);
  13.277 +
  13.278 +		for (i = 0; i < nr_segments; i++) {
  13.279 +			if (unlikely(map[i].status != 0)) {
  13.280 +				printk(KERN_ERR "scsiback: invalid buffer -- could not remap it\n");
  13.281 +				map[i].handle = SCSIBACK_INVALID_HANDLE;
  13.282 +				err |= 1;
  13.283 +			}
  13.284 +
  13.285 +			pending_handle(pending_req, i) = map[i].handle;
  13.286 +
  13.287 +			if (err)
  13.288 +				continue;
  13.289 +
  13.290 +			set_phys_to_machine(__pa(vaddr(
  13.291 +				pending_req, i)) >> PAGE_SHIFT,
  13.292 +				FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT));
  13.293 +
  13.294 +			pending_req->sgl[i].page   = virt_to_page(vaddr(pending_req, i));
  13.295 +			pending_req->sgl[i].offset = ring_req->seg[i].offset;
  13.296 +			pending_req->sgl[i].length = ring_req->seg[i].length;
  13.297 +			data_len += pending_req->sgl[i].length;
  13.298 +		}
  13.299 +
  13.300 +		if (err)
  13.301 +			goto fail_flush;
  13.302 +	}
  13.303 +	
  13.304 +	pending_req->request_bufflen = data_len;
  13.305 +	
  13.306 +	return 0;
  13.307 +	
  13.308 +fail_flush:
  13.309 +	fast_flush_area(pending_req);
  13.310 +	return -ENOMEM;
  13.311 +}
  13.312 +
  13.313 +
  13.314 +#ifdef NO_ASYNC /*!async*/
  13.315 +
  13.316 +/* quoted scsi_lib.c/scsi_merge_bio */
  13.317 +static int scsiback_merge_bio(struct request *rq, struct bio *bio)
  13.318 +{
  13.319 +	struct request_queue *q = rq->q;
  13.320 +
  13.321 +	bio->bi_flags &= ~(1 << BIO_SEG_VALID);
  13.322 +	if (rq_data_dir(rq) == WRITE)
  13.323 +		bio->bi_rw |= (1 << BIO_RW);
  13.324 +
  13.325 +	blk_queue_bounce(q, &bio);
  13.326 +
  13.327 +	if (!rq->bio)
  13.328 +		blk_rq_bio_prep(q, rq, bio);
  13.329 +	else if (!q->back_merge_fn(q, rq, bio))
  13.330 +		return -EINVAL;
  13.331 +	else {
  13.332 +		rq->biotail->bi_next = bio;
  13.333 +		rq->biotail          = bio;
  13.334 +		rq->hard_nr_sectors += bio_sectors(bio);
  13.335 +		rq->nr_sectors       = rq->hard_nr_sectors;
  13.336 +	}
  13.337 +
  13.338 +	return 0;
  13.339 +}
  13.340 +
  13.341 +
  13.342 +/* quoted scsi_lib.c/scsi_bi_endio */
  13.343 +static int scsiback_bi_endio(struct bio *bio, unsigned int bytes_done, int error)
  13.344 +{
  13.345 +	if (bio->bi_size)
  13.346 +		return 1;
  13.347 +
  13.348 +	bio_put(bio);
  13.349 +	return 0;
  13.350 +}
  13.351 +
  13.352 +
  13.353 +
  13.354 +/* quoted scsi_lib.c/scsi_req_map_sg . */
  13.355 +static int requset_map_sg(struct request *rq, pending_req_t *pending_req, unsigned int count)
  13.356 +{
  13.357 +	struct request_queue *q = rq->q;
  13.358 +	int nr_pages;
  13.359 +	unsigned int nsegs = count;
  13.360 +
  13.361 +	unsigned int data_len = 0, len, bytes, off;
  13.362 +	struct page *page;
  13.363 +	struct bio *bio = NULL;
  13.364 +	int i, err, nr_vecs = 0;
  13.365 +
  13.366 +	for (i = 0; i < nsegs; i++) {
  13.367 +		page = pending_req->sgl[i].page;
  13.368 +		off = (unsigned int)pending_req->sgl[i].offset;
  13.369 +		len = (unsigned int)pending_req->sgl[i].length;
  13.370 +		data_len += len;
  13.371 +
  13.372 +		nr_pages = (len + off + PAGE_SIZE - 1) >> PAGE_SHIFT;
  13.373 +		while (len > 0) {
  13.374 +			bytes = min_t(unsigned int, len, PAGE_SIZE - off);
  13.375 +
  13.376 +			if (!bio) {
  13.377 +				nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages);
  13.378 +				nr_pages -= nr_vecs;
  13.379 +				bio = bio_alloc(GFP_KERNEL, nr_vecs);
  13.380 +				if (!bio) {
  13.381 +					err = -ENOMEM;
  13.382 +					goto free_bios;
  13.383 +				}
  13.384 +				bio->bi_end_io = scsiback_bi_endio;
  13.385 +			}
  13.386 +
  13.387 +			if (bio_add_pc_page(q, bio, page, bytes, off) !=
  13.388 +						bytes) {
  13.389 +				bio_put(bio);
  13.390 +				err = -EINVAL;
  13.391 +				goto free_bios;
  13.392 +			}
  13.393 +
  13.394 +			if (bio->bi_vcnt >= nr_vecs) {
  13.395 +				err = scsiback_merge_bio(rq, bio);
  13.396 +				if (err) {
  13.397 +					bio_endio(bio, bio->bi_size, 0);
  13.398 +					goto free_bios;
  13.399 +				}
  13.400 +				bio = NULL;
  13.401 +			}
  13.402 +
  13.403 +			page++;
  13.404 +			len -= bytes;
  13.405 +			off = 0;
  13.406 +		}
  13.407 +	}
  13.408 +
  13.409 +	rq->buffer   = rq->data = NULL;
  13.410 +	rq->data_len = data_len;
  13.411 +
  13.412 +	return 0;
  13.413 +
  13.414 +free_bios:
  13.415 +	while ((bio = rq->bio) != NULL) {
  13.416 +		rq->bio = bio->bi_next;
  13.417 +		/*
  13.418 +		 * call endio instead of bio_put incase it was bounced
  13.419 +		 */
  13.420 +		bio_endio(bio, bio->bi_size, 0);
  13.421 +	}
  13.422 +
  13.423 +	return err;
  13.424 +}
  13.425 +
  13.426 +#endif
  13.427 +
  13.428 +void scsiback_cmd_exec(pending_req_t *pending_req)
  13.429 +{
  13.430 +	int err;
  13.431 +
  13.432 +	int cmd_len  = (int)pending_req->cmd_len;
  13.433 +	int data_dir = (int)pending_req->sc_data_direction;
  13.434 +	unsigned int nr_segments = (unsigned int)pending_req->nr_segments;
  13.435 +	unsigned int timeout;
  13.436 +#ifdef NO_ASYNC /*!async*/
  13.437 +	struct request *rq;
  13.438 +	int write;
  13.439 +#else
  13.440 +	unsigned int data_len = pending_req->request_bufflen;
  13.441 +#endif
  13.442 +
  13.443 +	DPRINTK("%s\n",__FUNCTION__);
  13.444 +
  13.445 +	/* because it doesn't timeout backend earlier than frontend.*/
  13.446 +	if (pending_req->timeout_per_command)
  13.447 +		timeout = (pending_req->timeout_per_command * HZ * 2);
  13.448 +	else
  13.449 +		timeout = VSCSIIF_TIMEOUT;
  13.450 +
  13.451 +#ifdef NO_ASYNC /*!async*/
  13.452 +	err = 0;
  13.453 +	write = (data_dir == DMA_TO_DEVICE);
  13.454 +	rq = blk_get_request(pending_req->sdev->request_queue, write, GFP_KERNEL);
  13.455 +
  13.456 +	rq->flags  |= REQ_BLOCK_PC;
  13.457 +	rq->cmd_len = cmd_len;
  13.458 +	memcpy(rq->cmd, pending_req->cmnd, cmd_len);
  13.459 +
  13.460 +	memset(pending_req->sense_buffer, 0, VSCSIIF_SENSE_BUFFERSIZE);
  13.461 +	rq->sense       = pending_req->sense_buffer;
  13.462 +	rq->sense_len = 0;
  13.463 +
  13.464 +	rq->retries   = 0;
  13.465 +	rq->timeout   = timeout;
  13.466 +	rq->end_io_data = pending_req;
  13.467 +
  13.468 +	if (nr_segments) {
  13.469 +
  13.470 +		if (requset_map_sg(rq, pending_req, nr_segments)) {
  13.471 +			printk(KERN_ERR "scsiback: SG Request Map Error\n");
  13.472 +			return;
  13.473 +		}
  13.474 +	}
  13.475 +
  13.476 +	blk_execute_rq_nowait(rq->q, NULL, rq, 1, scsiback_cmd_done);
  13.477 +
  13.478 +#else   /*async*/
  13.479 +	/* not allowed to retry in backend.                   */
  13.480 +	/* timeout of backend is longer than that of brontend.*/
  13.481 +	err = scsi_execute_async(pending_req->sdev, &(pending_req->cmnd[0]),
  13.482 +		cmd_len, data_dir, &(pending_req->sgl[0]), data_len, nr_segments, timeout, 0,
  13.483 +		pending_req, scsiback_cmd_done, GFP_ATOMIC);
  13.484 +		
  13.485 +#endif /*!async*/
  13.486 +
  13.487 +	if (err) 
  13.488 +		scsiback_do_resp_with_sense(NULL, (DRIVER_ERROR << 24), pending_req);
  13.489 +
  13.490 +	return ;
  13.491 +}
  13.492 +
  13.493 +
  13.494 +static void scsiback_device_reset_exec(pending_req_t *pending_req)
  13.495 +{
  13.496 +	struct vscsibk_info *info = pending_req->info;
  13.497 +	int err;
  13.498 +	struct scsi_device *sdev = pending_req->sdev;
  13.499 +
  13.500 +	scsiback_get(info);
  13.501 +
  13.502 +	err = scsi_reset_provider(sdev, SCSI_TRY_RESET_DEVICE);
  13.503 +
  13.504 +	scsiback_do_resp_with_sense(NULL, err, pending_req);
  13.505 +
  13.506 +	notify_remote_via_irq(info->irq);
  13.507 +	return;
  13.508 +}
  13.509 +
  13.510 +
  13.511 +irqreturn_t scsiback_intr(int irq, void *dev_id, struct pt_regs *regs)
  13.512 +{
  13.513 +	scsiback_notify_work((struct vscsibk_info *)dev_id);
  13.514 +	return IRQ_HANDLED;
  13.515 +}
  13.516 +
  13.517 +static int prepare_pending_reqs(struct vscsibk_info *info,
  13.518 +		vscsiif_request_t *ring_req, pending_req_t *pending_req)
  13.519 +{
  13.520 +	struct scsi_device *sdev;
  13.521 +	struct ids_tuple vir;
  13.522 +	int err = -EINVAL;
  13.523 +
  13.524 +	DPRINTK("%s\n",__FUNCTION__);
  13.525 +
  13.526 +	pending_req->rqid       = ring_req->rqid;
  13.527 +	pending_req->act        = ring_req->act;
  13.528 +
  13.529 +	pending_req->info       = info;
  13.530 +
  13.531 +	vir.chn = ring_req->channel;
  13.532 +	vir.tgt = ring_req->id;
  13.533 +	vir.lun = ring_req->lun;
  13.534 +
  13.535 +	sdev = scsiback_do_translation(info, &vir);
  13.536 +	if (!sdev) {
  13.537 +		pending_req->sdev = NULL;
  13.538 +		printk(KERN_ERR "scsiback: doesn't exist.\n");
  13.539 +		err = -ENODEV;
  13.540 +		goto invald_value;
  13.541 +	}
  13.542 +	pending_req->sdev = sdev;
  13.543 +
  13.544 +	/* request range check from frontend */
  13.545 +	if ((ring_req->sc_data_direction != DMA_BIDIRECTIONAL) &&
  13.546 +		(ring_req->sc_data_direction != DMA_TO_DEVICE) &&
  13.547 +		(ring_req->sc_data_direction != DMA_FROM_DEVICE) &&
  13.548 +		(ring_req->sc_data_direction != DMA_NONE)) {
  13.549 +		printk(KERN_ERR "scsiback: invalid parameter data_dir = %d\n",
  13.550 +			ring_req->sc_data_direction);
  13.551 +		err = -EINVAL;
  13.552 +		goto invald_value;
  13.553 +	}
  13.554 +
  13.555 +	if (ring_req->nr_segments > VSCSIIF_SG_TABLESIZE) {
  13.556 +		printk(KERN_ERR "scsiback: invalid parameter nr_seg = %d\n",
  13.557 +			ring_req->nr_segments);
  13.558 +		err = -EINVAL;
  13.559 +		goto invald_value;
  13.560 +	}
  13.561 +	pending_req->nr_segments = ring_req->nr_segments;
  13.562 +
  13.563 +	if (ring_req->cmd_len > VSCSIIF_MAX_COMMAND_SIZE) {
  13.564 +		printk(KERN_ERR "scsiback: invalid parameter cmd_len = %d\n",
  13.565 +			ring_req->cmd_len);
  13.566 +		err = -EINVAL;
  13.567 +		goto invald_value;
  13.568 +	}
  13.569 +	memcpy(pending_req->cmnd, ring_req->cmnd, ring_req->cmd_len);
  13.570 +	pending_req->cmd_len = ring_req->cmd_len;
  13.571 +	
  13.572 +	pending_req->sc_data_direction = ring_req->sc_data_direction;
  13.573 +	pending_req->timeout_per_command = ring_req->timeout_per_command;
  13.574 +
  13.575 +	if(scsiback_gnttab_data_map(ring_req, pending_req)) {
  13.576 +		printk(KERN_ERR "scsiback: invalid buffer\n");
  13.577 +		err = -EINVAL;
  13.578 +		goto invald_value;
  13.579 +	}
  13.580 +
  13.581 +	return 0;
  13.582 +
  13.583 +invald_value:
  13.584 +	return err;
  13.585 +}
  13.586 +
  13.587 +
  13.588 +static int scsiback_do_cmd_fn(struct vscsibk_info *info)
  13.589 +{
  13.590 +	struct vscsiif_back_ring *ring = &info->ring;
  13.591 +	vscsiif_request_t  *ring_req;
  13.592 +
  13.593 +	pending_req_t *pending_req;
  13.594 +	RING_IDX rc, rp;
  13.595 +	int err, more_to_do = 0;
  13.596 +
  13.597 +	DPRINTK("%s\n",__FUNCTION__);
  13.598 +
  13.599 +	rc = ring->req_cons;
  13.600 +	rp = ring->sring->req_prod;
  13.601 +	rmb();
  13.602 +
  13.603 +	while ((rc != rp)) {
  13.604 +		if (RING_REQUEST_CONS_OVERFLOW(ring, rc))
  13.605 +			break;
  13.606 +		pending_req = alloc_req(info);
  13.607 +		if (NULL == pending_req) {
  13.608 +			more_to_do = 1;
  13.609 +			break;
  13.610 +		}
  13.611 +
  13.612 +		ring_req = RING_GET_REQUEST(ring, rc);
  13.613 +		ring->req_cons = ++rc;
  13.614 +
  13.615 +		scsiback_get(info);
  13.616 +		err = prepare_pending_reqs(info, ring_req,
  13.617 +						pending_req);
  13.618 +		if (err == -EINVAL) {
  13.619 +			scsiback_do_resp_with_sense(NULL, (DRIVER_ERROR << 24),
  13.620 +				pending_req);
  13.621 +			continue;
  13.622 +		} else if (err == -ENODEV) {
  13.623 +			scsiback_do_resp_with_sense(NULL, (DID_NO_CONNECT << 16),
  13.624 +				pending_req);			
  13.625 +		}
  13.626 +
  13.627 +		if (pending_req->act == VSCSIIF_ACT_SCSI_CDB) {
  13.628 +#if 0 /*SAMPLE CODING(tentative)*//*emulation*/
  13.629 +			scsiback_req_emulation_or_through(pending_req);
  13.630 +#else
  13.631 +			scsiback_cmd_exec(pending_req);
  13.632 +#endif
  13.633 +		} else if (pending_req->act == VSCSIIF_ACT_SCSI_RESET) {
  13.634 +			scsiback_device_reset_exec(pending_req);
  13.635 +		} else {
  13.636 +			printk(KERN_ERR "scsiback: invalid parameter for request\n");
  13.637 +			scsiback_do_resp_with_sense(NULL, (DRIVER_ERROR << 24),
  13.638 +				pending_req);
  13.639 +			continue;
  13.640 +		}
  13.641 +	}
  13.642 +
  13.643 +	if (RING_HAS_UNCONSUMED_REQUESTS(ring))
  13.644 +		more_to_do = 1;
  13.645 +
  13.646 +	return more_to_do;
  13.647 +}
  13.648 +
  13.649 +
  13.650 +int scsiback_schedule(void *data)
  13.651 +{
  13.652 +	struct vscsibk_info *info = (struct vscsibk_info *)data;
  13.653 +
  13.654 +	DPRINTK("%s\n",__FUNCTION__);
  13.655 +
  13.656 +	scsiback_get(info);
  13.657 +
  13.658 +	while (!kthread_should_stop()) {
  13.659 +		wait_event_interruptible(
  13.660 +			info->wq,
  13.661 +			info->waiting_reqs || kthread_should_stop());
  13.662 +		wait_event_interruptible(
  13.663 +			pending_free_wq,
  13.664 +			!list_empty(&pending_free) || kthread_should_stop());
  13.665 +
  13.666 +		info->waiting_reqs = 0;
  13.667 +		smp_mb();
  13.668 +
  13.669 +		if (scsiback_do_cmd_fn(info))
  13.670 +			info->waiting_reqs = 1;
  13.671 +	}
  13.672 +
  13.673 +	info->kthread = NULL;
  13.674 +	scsiback_put(info);
  13.675 +
  13.676 +	return 0;
  13.677 +}
  13.678 +
  13.679 +
  13.680 +static int __init scsiback_init(void)
  13.681 +{
  13.682 +	int i, mmap_pages;
  13.683 +
  13.684 +	if (!is_running_on_xen())
  13.685 +		return -ENODEV;
  13.686 +
  13.687 +	mmap_pages = vscsiif_reqs * VSCSIIF_SG_TABLESIZE;
  13.688 +
  13.689 +	pending_reqs          = kmalloc(sizeof(pending_reqs[0]) *
  13.690 +					vscsiif_reqs, GFP_KERNEL);
  13.691 +	pending_grant_handles = kmalloc(sizeof(pending_grant_handles[0]) *
  13.692 +					mmap_pages, GFP_KERNEL);
  13.693 +	pending_pages         = alloc_empty_pages_and_pagevec(mmap_pages);
  13.694 +
  13.695 +	if (!pending_reqs || !pending_grant_handles || !pending_pages)
  13.696 +		goto out_of_memory;
  13.697 +
  13.698 +	for (i = 0; i < mmap_pages; i++)
  13.699 +		pending_grant_handles[i] = SCSIBACK_INVALID_HANDLE;
  13.700 +
  13.701 +	if (scsiback_interface_init() < 0)
  13.702 +		goto out_of_memory;
  13.703 +
  13.704 +	memset(pending_reqs, 0, sizeof(pending_reqs));
  13.705 +	INIT_LIST_HEAD(&pending_free);
  13.706 +
  13.707 +	for (i = 0; i < vscsiif_reqs; i++)
  13.708 +		list_add_tail(&pending_reqs[i].free_list, &pending_free);
  13.709 +
  13.710 +	if (scsiback_xenbus_init())
  13.711 +		goto out_of_memory;
  13.712 +
  13.713 +	return 0;
  13.714 +
  13.715 +out_of_memory:
  13.716 +	kfree(pending_reqs);
  13.717 +	kfree(pending_grant_handles);
  13.718 +	free_empty_pages_and_pagevec(pending_pages, mmap_pages);
  13.719 +	printk(KERN_ERR "scsiback: %s: out of memory\n", __FUNCTION__);
  13.720 +	return -ENOMEM;
  13.721 +}
  13.722 +
  13.723 +static void __exit scsiback_exit(void)
  13.724 +{
  13.725 +	scsiback_xenbus_unregister();
  13.726 +	scsiback_interface_exit();
  13.727 +	kfree(pending_reqs);
  13.728 +	kfree(pending_grant_handles);
  13.729 +	free_empty_pages_and_pagevec(pending_pages, (vscsiif_reqs * VSCSIIF_SG_TABLESIZE));
  13.730 +
  13.731 +}
  13.732 +
  13.733 +module_init(scsiback_init);
  13.734 +module_exit(scsiback_exit);
  13.735 +
  13.736 +MODULE_DESCRIPTION("Xen SCSI backend driver");
  13.737 +MODULE_LICENSE("Dual BSD/GPL");
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/drivers/xen/scsiback/translate.c	Mon Jun 02 09:58:27 2008 +0100
    14.3 @@ -0,0 +1,166 @@
    14.4 +/*
    14.5 + * Xen SCSI backend 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 +#include <linux/list.h>
   14.35 +#include <linux/gfp.h>
   14.36 +
   14.37 +#include "common.h"
   14.38 +
   14.39 +/*
   14.40 +  Initialize the translation entry list
   14.41 +*/
   14.42 +void scsiback_init_translation_table(struct vscsibk_info *info)
   14.43 +{
   14.44 +	INIT_LIST_HEAD(&info->v2p_entry_lists);
   14.45 +	spin_lock_init(&info->v2p_lock);
   14.46 +}
   14.47 +
   14.48 +
   14.49 +/*
   14.50 +  Add a new translation entry
   14.51 +*/
   14.52 +int scsiback_add_translation_entry(struct vscsibk_info *info,
   14.53 +			struct scsi_device *sdev, struct ids_tuple *v)
   14.54 +{
   14.55 +	int err = 0;
   14.56 +	struct v2p_entry *entry;
   14.57 +	struct v2p_entry *new;
   14.58 +	struct list_head *head = &(info->v2p_entry_lists);
   14.59 +	unsigned long flags;
   14.60 +	
   14.61 +	spin_lock_irqsave(&info->v2p_lock, flags);
   14.62 +
   14.63 +	/* Check double assignment to identical virtual ID */
   14.64 +	list_for_each_entry(entry, head, l) {
   14.65 +		if ((entry->v.chn == v->chn) &&
   14.66 +		    (entry->v.tgt == v->tgt) &&
   14.67 +		    (entry->v.lun == v->lun)) {
   14.68 +			printk(KERN_WARNING "scsiback: Virtual ID is already used. "
   14.69 +			       "Assignment was not performed.\n");
   14.70 +			err = -EEXIST;
   14.71 +			goto out;
   14.72 +		}
   14.73 +
   14.74 +	}
   14.75 +
   14.76 +	/* Create a new translation entry and add to the list */
   14.77 +	if ((new = kmalloc(sizeof(struct v2p_entry), GFP_KERNEL)) == NULL) {
   14.78 +		printk(KERN_ERR "scsiback: %s: kmalloc() error.\n", __FUNCTION__);
   14.79 +		err = -ENOMEM;
   14.80 +		goto out;
   14.81 +	}
   14.82 +	new->v = *v;
   14.83 +	new->sdev = sdev;
   14.84 +	list_add(&new->l, head);
   14.85 +
   14.86 +out:	
   14.87 +	spin_unlock_irqrestore(&info->v2p_lock, flags);
   14.88 +	return err;
   14.89 +}
   14.90 +
   14.91 +
   14.92 +/*
   14.93 +  Delete the translation entry specfied
   14.94 +*/
   14.95 +int scsiback_del_translation_entry(struct vscsibk_info *info,
   14.96 +				struct ids_tuple *v)
   14.97 +{
   14.98 +	struct v2p_entry *entry;
   14.99 +	struct list_head *head = &(info->v2p_entry_lists);
  14.100 +	unsigned long flags;
  14.101 +
  14.102 +	spin_lock_irqsave(&info->v2p_lock, flags);
  14.103 +	/* Find out the translation entry specified */
  14.104 +	list_for_each_entry(entry, head, l) {
  14.105 +		if ((entry->v.chn == v->chn) &&
  14.106 +		    (entry->v.tgt == v->tgt) &&
  14.107 +		    (entry->v.lun == v->lun)) {
  14.108 +			goto found;
  14.109 +		}
  14.110 +	}
  14.111 +
  14.112 +	spin_unlock_irqrestore(&info->v2p_lock, flags);
  14.113 +	return 0;
  14.114 +
  14.115 +found:
  14.116 +	/* Delete the translation entry specfied */
  14.117 +	list_del(&entry->l);
  14.118 +	kfree(entry);
  14.119 +
  14.120 +	spin_unlock_irqrestore(&info->v2p_lock, flags);
  14.121 +	return 0;
  14.122 +}
  14.123 +
  14.124 +
  14.125 +/*
  14.126 +  Perform virtual to physical translation
  14.127 +*/
  14.128 +struct scsi_device *scsiback_do_translation(struct vscsibk_info *info,
  14.129 +			struct ids_tuple *v)
  14.130 +{
  14.131 +	struct v2p_entry *entry;
  14.132 +	struct list_head *head = &(info->v2p_entry_lists);
  14.133 +	struct scsi_device *sdev = NULL;
  14.134 +	unsigned long flags;
  14.135 +
  14.136 +	spin_lock_irqsave(&info->v2p_lock, flags);
  14.137 +	list_for_each_entry(entry, head, l) {
  14.138 +		if ((entry->v.chn == v->chn) &&
  14.139 +		    (entry->v.tgt == v->tgt) &&
  14.140 +		    (entry->v.lun == v->lun)) {
  14.141 +			sdev = entry->sdev;
  14.142 +			goto out;
  14.143 +		}
  14.144 +	}
  14.145 +out:
  14.146 +	spin_unlock_irqrestore(&info->v2p_lock, flags);
  14.147 +	return sdev;
  14.148 +}
  14.149 +
  14.150 +
  14.151 +/*
  14.152 +  Release the translation entry specfied
  14.153 +*/
  14.154 +void scsiback_release_translation_entry(struct vscsibk_info *info)
  14.155 +{
  14.156 +	struct v2p_entry *entry, *tmp;
  14.157 +	struct list_head *head = &(info->v2p_entry_lists);
  14.158 +	unsigned long flags;
  14.159 +
  14.160 +	spin_lock_irqsave(&info->v2p_lock, flags);
  14.161 +	list_for_each_entry_safe(entry, tmp, head, l) {
  14.162 +		list_del(&entry->l);
  14.163 +		kfree(entry);
  14.164 +	}
  14.165 +
  14.166 +	spin_unlock_irqrestore(&info->v2p_lock, flags);
  14.167 +	return;
  14.168 +
  14.169 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/drivers/xen/scsiback/xenbus.c	Mon Jun 02 09:58:27 2008 +0100
    15.3 @@ -0,0 +1,365 @@
    15.4 +/*
    15.5 + * Xen SCSI backend driver
    15.6 + *
    15.7 + * Copyright (c) 2008, FUJITSU Limited
    15.8 + *
    15.9 + * Based on the blkback driver code.
   15.10 + *
   15.11 + * This program is free software; you can redistribute it and/or
   15.12 + * modify it under the terms of the GNU General Public License version 2
   15.13 + * as published by the Free Software Foundation; or, when distributed
   15.14 + * separately from the Linux kernel or incorporated into other
   15.15 + * software packages, subject to the following license:
   15.16 + * 
   15.17 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   15.18 + * of this source file (the "Software"), to deal in the Software without
   15.19 + * restriction, including without limitation the rights to use, copy, modify,
   15.20 + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   15.21 + * and to permit persons to whom the Software is furnished to do so, subject to
   15.22 + * the following conditions:
   15.23 + * 
   15.24 + * The above copyright notice and this permission notice shall be included in
   15.25 + * all copies or substantial portions of the Software.
   15.26 + * 
   15.27 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   15.28 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   15.29 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   15.30 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   15.31 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   15.32 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   15.33 + * IN THE SOFTWARE.
   15.34 + */
   15.35 +
   15.36 +#include <stdarg.h>
   15.37 +#include <linux/module.h>
   15.38 +#include <linux/kthread.h>
   15.39 +#include <scsi/scsi.h>
   15.40 +#include <scsi/scsi_host.h>
   15.41 +#include <scsi/scsi_device.h>
   15.42 +
   15.43 +#include "common.h"
   15.44 +
   15.45 +struct backend_info
   15.46 +{
   15.47 +	struct xenbus_device *dev;
   15.48 +	struct vscsibk_info *info;
   15.49 +};
   15.50 +
   15.51 +
   15.52 +static int __vscsiif_name(struct backend_info *be, char *buf)
   15.53 +{
   15.54 +	struct xenbus_device *dev = be->dev;
   15.55 +	unsigned int domid, id;
   15.56 +
   15.57 +	sscanf(dev->nodename, "backend/vscsi/%u/%u", &domid, &id);
   15.58 +	snprintf(buf, TASK_COMM_LEN, "vscsi.%u.%u", be->info->domid, id);
   15.59 +
   15.60 +	return 0;
   15.61 +}
   15.62 +
   15.63 +static int scsiback_map(struct backend_info *be)
   15.64 +{
   15.65 +	struct xenbus_device *dev = be->dev;
   15.66 +	unsigned long ring_ref;
   15.67 +	unsigned int evtchn;
   15.68 +	int err;
   15.69 +	char name[TASK_COMM_LEN];
   15.70 +
   15.71 +	err = xenbus_gather(XBT_NIL, dev->otherend,
   15.72 +			"ring-ref", "%lu", &ring_ref,
   15.73 +			"event-channel", "%u", &evtchn, NULL);
   15.74 +	if (err) {
   15.75 +		xenbus_dev_fatal(dev, err, "reading %s ring", dev->otherend);
   15.76 +		return err;
   15.77 +	}
   15.78 +
   15.79 +	err = scsiback_init_sring(be->info, ring_ref, evtchn);
   15.80 +	if (err)
   15.81 +		return err;
   15.82 +
   15.83 +	err = __vscsiif_name(be, name);
   15.84 +	if (err) {
   15.85 +		xenbus_dev_error(dev, err, "get scsiback dev name");
   15.86 +		return err;
   15.87 +	}
   15.88 +
   15.89 +	be->info->kthread = kthread_run(scsiback_schedule, be->info, name);
   15.90 +	if (IS_ERR(be->info->kthread)) {
   15.91 +		err = PTR_ERR(be->info->kthread);
   15.92 +		be->info->kthread = NULL;
   15.93 +		xenbus_dev_error(be->dev, err, "start vscsiif");
   15.94 +		return err;
   15.95 +	}
   15.96 +
   15.97 +	return 0;
   15.98 +}
   15.99 +
  15.100 +
  15.101 +struct scsi_device *scsiback_get_scsi_device(struct ids_tuple *phy)
  15.102 +{
  15.103 +	struct Scsi_Host *shost;
  15.104 +	struct scsi_device *sdev = NULL;
  15.105 +
  15.106 +	shost = scsi_host_lookup(phy->hst);
  15.107 +	if (IS_ERR(shost)) {
  15.108 +		printk(KERN_ERR "scsiback: host%d doesn't exist.\n",
  15.109 +			phy->hst);
  15.110 +		goto invald_value;
  15.111 +	}
  15.112 +	sdev   = scsi_device_lookup(shost, phy->chn, phy->tgt, phy->lun);
  15.113 +	if (!sdev) {
  15.114 +		printk(KERN_ERR "scsiback: %d:%d:%d:%d doesn't exist.\n",
  15.115 +			phy->hst, phy->chn, phy->tgt, phy->lun);
  15.116 +		goto invald_value;
  15.117 +	}
  15.118 +
  15.119 +invald_value:
  15.120 +	return (sdev);
  15.121 +}
  15.122 +
  15.123 +#define VSCSIBACK_OP_ADD_OR_DEL_LUN	1
  15.124 +
  15.125 +static void scsiback_do_lun_hotplug(struct backend_info *be, int op)
  15.126 +{
  15.127 +	int i, err = 0;
  15.128 +	struct ids_tuple phy, vir;
  15.129 +	int device_state;
  15.130 +	char str[64], state_str[64];
  15.131 +	char **dir;
  15.132 +	unsigned int dir_n = 0;
  15.133 +	struct xenbus_device *dev = be->dev;
  15.134 +	struct scsi_device *sdev;
  15.135 +	struct xenbus_transaction xbt;
  15.136 +
  15.137 +
  15.138 +	err = xenbus_transaction_start(&xbt);
  15.139 +	if (err) {
  15.140 +		xenbus_dev_fatal(dev, err, "starting transaction");
  15.141 +	}
  15.142 +
  15.143 +	dir = xenbus_directory(xbt, dev->nodename, "vscsi-devs", &dir_n);
  15.144 +	if (IS_ERR(dir))
  15.145 +		return;
  15.146 +
  15.147 +	for (i = 0; i < dir_n; i++) {
  15.148 +		
  15.149 +		/* read status */
  15.150 +		snprintf(state_str, sizeof(state_str), "vscsi-devs/%s/state", dir[i]);
  15.151 +		err = xenbus_scanf(xbt, dev->nodename, state_str, "%u",
  15.152 +			&device_state);
  15.153 +		if (XENBUS_EXIST_ERR(err))
  15.154 +			continue;
  15.155 +
  15.156 +		/* physical SCSI device */
  15.157 +		snprintf(str, sizeof(str), "vscsi-devs/%s/p-dev", dir[i]);
  15.158 +		err = xenbus_scanf(xbt, dev->nodename, str,
  15.159 +			"%u:%u:%u:%u", &phy.hst, &phy.chn, &phy.tgt, &phy.lun);
  15.160 +		if (XENBUS_EXIST_ERR(err)) {
  15.161 +			xenbus_printf(xbt, dev->nodename, state_str,
  15.162 +					"%d", XenbusStateClosing);
  15.163 +			continue;
  15.164 +		}
  15.165 +
  15.166 +		/* virtual SCSI device */
  15.167 +		snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", dir[i]);
  15.168 +		err = xenbus_scanf(xbt, dev->nodename, str,
  15.169 +			"%u:%u:%u:%u", &vir.hst, &vir.chn, &vir.tgt, &vir.lun);
  15.170 +		if (XENBUS_EXIST_ERR(err)) {
  15.171 +			xenbus_printf(xbt, dev->nodename, state_str,
  15.172 +					"%d", XenbusStateClosing);
  15.173 +			continue;
  15.174 +		}
  15.175 +
  15.176 +		switch (op) {
  15.177 +		case VSCSIBACK_OP_ADD_OR_DEL_LUN:
  15.178 +			if (device_state == XenbusStateInitialising) {
  15.179 +				sdev = scsiback_get_scsi_device(&phy);
  15.180 +				if (!sdev) {
  15.181 +					xenbus_printf(xbt, dev->nodename, state_str,
  15.182 +							"%d", XenbusStateClosing);
  15.183 +				} else {
  15.184 +					err = scsiback_add_translation_entry(be->info, sdev, &vir);
  15.185 +					if (!err) {
  15.186 +						xenbus_printf(xbt, dev->nodename, state_str,
  15.187 +							"%d", XenbusStateInitialised);
  15.188 +					} else {
  15.189 +						xenbus_printf(xbt, dev->nodename, state_str,
  15.190 +							"%d", XenbusStateClosing);						
  15.191 +					}
  15.192 +				}
  15.193 +			}
  15.194 +
  15.195 +			if (device_state == XenbusStateClosing) {
  15.196 +				err = scsiback_del_translation_entry(be->info, &vir);
  15.197 +				if (err)
  15.198 +					goto fail;
  15.199 +				else {
  15.200 +					xenbus_printf(xbt, dev->nodename, state_str,
  15.201 +						"%d", XenbusStateClosed);						
  15.202 +				}
  15.203 +			}
  15.204 +
  15.205 +			break;
  15.206 +		/*When it is necessary, processing is added here.*/
  15.207 +		default:
  15.208 +			break;
  15.209 +		}
  15.210 +	}
  15.211 +
  15.212 +	xenbus_transaction_end(xbt, 0);
  15.213 +	kfree(dir);
  15.214 +	return ;
  15.215 +fail :
  15.216 +	xenbus_transaction_end(xbt, 1);
  15.217 +	kfree(dir);
  15.218 +	xenbus_dev_fatal(dev, err, "read or write %s ", str);
  15.219 +	return;
  15.220 +}
  15.221 +
  15.222 +
  15.223 +static void scsiback_frontend_changed(struct xenbus_device *dev,
  15.224 +					enum xenbus_state frontend_state)
  15.225 +{
  15.226 +	struct backend_info *be = dev->dev.driver_data;
  15.227 +	int err;
  15.228 +
  15.229 +	switch (frontend_state) {
  15.230 +	case XenbusStateInitialising:
  15.231 +		break;
  15.232 +	case XenbusStateInitialised:
  15.233 +		err = scsiback_map(be);
  15.234 +		if (err)
  15.235 +			break;
  15.236 +
  15.237 +		scsiback_do_lun_hotplug(be, VSCSIBACK_OP_ADD_OR_DEL_LUN);
  15.238 +		err = xenbus_switch_state(dev, XenbusStateConnected);
  15.239 +		if (err)
  15.240 +			xenbus_dev_fatal(dev, err, "switching to Connected state",
  15.241 +					dev->nodename);
  15.242 +		break;
  15.243 +	case XenbusStateConnected:
  15.244 +		if (dev->state == XenbusStateConnected)
  15.245 +			break;
  15.246 +			
  15.247 +		err = xenbus_switch_state(dev, XenbusStateConnected);
  15.248 +		if (err)
  15.249 +			xenbus_dev_fatal(dev, err, "switching to Connected state",
  15.250 +					dev->nodename);
  15.251 +		break;
  15.252 +
  15.253 +	case XenbusStateClosing:
  15.254 +		scsiback_disconnect(be->info);
  15.255 +		xenbus_switch_state(dev, XenbusStateClosing);
  15.256 +		break;
  15.257 +
  15.258 +	case XenbusStateClosed:
  15.259 +		xenbus_switch_state(dev, XenbusStateClosed);
  15.260 +		if (xenbus_dev_is_online(dev))
  15.261 +			break;
  15.262 +
  15.263 +	case XenbusStateReconfiguring:
  15.264 +		scsiback_do_lun_hotplug(be, VSCSIBACK_OP_ADD_OR_DEL_LUN);
  15.265 +		err = xenbus_switch_state(dev, XenbusStateReconfigured);
  15.266 +		if (err)
  15.267 +			xenbus_dev_fatal(dev, err, "switching to Reconfigured state",
  15.268 +					dev->nodename);
  15.269 +		break;
  15.270 +
  15.271 +	case XenbusStateUnknown:
  15.272 +		device_unregister(&dev->dev);
  15.273 +		break;
  15.274 +	default:
  15.275 +		xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
  15.276 +					frontend_state);
  15.277 +		break;
  15.278 +	}
  15.279 +}
  15.280 +
  15.281 +
  15.282 +static int scsiback_remove(struct xenbus_device *dev)
  15.283 +{
  15.284 +	struct backend_info *be = dev->dev.driver_data;
  15.285 +
  15.286 +	if (be->info) {
  15.287 +		scsiback_disconnect(be->info);
  15.288 +		scsiback_release_translation_entry(be->info);
  15.289 +		scsiback_free(be->info);
  15.290 +		be->info = NULL;
  15.291 +	}
  15.292 +
  15.293 +	kfree(be);
  15.294 +	dev->dev.driver_data = NULL;
  15.295 +
  15.296 +	return 0;
  15.297 +}
  15.298 +
  15.299 +
  15.300 +static int scsiback_probe(struct xenbus_device *dev,
  15.301 +			   const struct xenbus_device_id *id)
  15.302 +{
  15.303 +	int err;
  15.304 +
  15.305 +	struct backend_info *be = kzalloc(sizeof(struct backend_info),
  15.306 +					  GFP_KERNEL);
  15.307 +
  15.308 +	DPRINTK("%p %d\n", dev, dev->otherend_id);
  15.309 +
  15.310 +	if (!be) {
  15.311 +		xenbus_dev_fatal(dev, -ENOMEM,
  15.312 +				 "allocating backend structure");
  15.313 +		return -ENOMEM;
  15.314 +	}
  15.315 +	be->dev = dev;
  15.316 +	dev->dev.driver_data = be;
  15.317 +
  15.318 +	be->info = vscsibk_info_alloc(dev->otherend_id);
  15.319 +	if (IS_ERR(be->info)) {
  15.320 +		err = PTR_ERR(be->info);
  15.321 +		be->info = NULL;
  15.322 +		xenbus_dev_fatal(dev, err, "creating scsihost interface");
  15.323 +		goto fail;
  15.324 +	}
  15.325 +
  15.326 +	be->info->dev = dev;
  15.327 +	be->info->irq = 0;
  15.328 +
  15.329 +	scsiback_init_translation_table(be->info);
  15.330 +
  15.331 +	err = xenbus_switch_state(dev, XenbusStateInitWait);
  15.332 +	if (err)
  15.333 +		goto fail;
  15.334 +
  15.335 +	return 0;
  15.336 +
  15.337 +
  15.338 +fail:
  15.339 +	printk(KERN_WARNING "scsiback: %s failed\n",__FUNCTION__);
  15.340 +	scsiback_remove(dev);
  15.341 +
  15.342 +	return err;
  15.343 +}
  15.344 +
  15.345 +
  15.346 +static struct xenbus_device_id scsiback_ids[] = {
  15.347 +	{ "vscsi" },
  15.348 +	{ "" }
  15.349 +};
  15.350 +
  15.351 +static struct xenbus_driver scsiback = {
  15.352 +	.name			= "vscsi",
  15.353 +	.owner			= THIS_MODULE,
  15.354 +	.ids			= scsiback_ids,
  15.355 +	.probe			= scsiback_probe,
  15.356 +	.remove			= scsiback_remove,
  15.357 +	.otherend_changed	= scsiback_frontend_changed
  15.358 +};
  15.359 +
  15.360 +int scsiback_xenbus_init(void)
  15.361 +{
  15.362 +	return xenbus_register_backend(&scsiback);
  15.363 +}
  15.364 +
  15.365 +void scsiback_xenbus_unregister(void)
  15.366 +{
  15.367 +	xenbus_unregister_driver(&scsiback);
  15.368 +}