ia64/linux-2.6.18-xen.hg

changeset 569:3b045d92c4c0

pvscsi: Enable REPORT_LUN command emulation.

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 Thu Jun 05 10:40:54 2008 +0100 (2008-06-05)
parents ee72fd7d22c8
children 4f29b009b8b4
files drivers/xen/scsiback/common.h drivers/xen/scsiback/emulate.c drivers/xen/scsiback/scsiback.c
line diff
     1.1 --- a/drivers/xen/scsiback/common.h	Thu Jun 05 10:40:33 2008 +0100
     1.2 +++ b/drivers/xen/scsiback/common.h	Thu Jun 05 10:40:54 2008 +0100
     1.3 @@ -62,7 +62,6 @@
     1.4  #include <xen/interface/io/vscsiif.h>
     1.5  
     1.6  
     1.7 -
     1.8  #define DPRINTK(_f, _a...)			\
     1.9  	pr_debug("(file=%s, line=%d) " _f,	\
    1.10  		 __FILE__ , __LINE__ , ## _a )
    1.11 @@ -171,11 +170,13 @@ void scsiback_release_translation_entry(
    1.12  
    1.13  
    1.14  void scsiback_cmd_exec(pending_req_t *pending_req);
    1.15 +void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result,
    1.16 +				pending_req_t *pending_req);
    1.17 +void scsiback_fast_flush_area(pending_req_t *req);
    1.18  
    1.19 -#if 0 /*SAMPLE CODING(tentative)*//*emulation*/
    1.20 -void scsiback_dispatch_emulation_cmdexec(vscsiif_request_t *ring_req,
    1.21 -				pending_req_t *pending_req);
    1.22 -#endif
    1.23 +void scsiback_rsp_emulation(pending_req_t *pending_req);
    1.24 +void scsiback_req_emulation_or_cmdexec(pending_req_t *pending_req);
    1.25 +void scsiback_emulation_init(void);
    1.26  
    1.27  
    1.28  #endif /* __SCSIIF__BACKEND__COMMON_H__ */
     2.1 --- a/drivers/xen/scsiback/emulate.c	Thu Jun 05 10:40:33 2008 +0100
     2.2 +++ b/drivers/xen/scsiback/emulate.c	Thu Jun 05 10:40:54 2008 +0100
     2.3 @@ -31,7 +31,7 @@
     2.4  #include <scsi/scsi.h>
     2.5  #include <scsi/scsi_cmnd.h>
     2.6  #include <scsi/scsi_device.h>
     2.7 -#include "comback.h"
     2.8 +#include "common.h"
     2.9  
    2.10  /* Following SCSI commands are not defined in scsi/scsi.h */
    2.11  #define EXTENDED_COPY		0x83	/* EXTENDED COPY command        */
    2.12 @@ -76,13 +76,30 @@ static unsigned char bitmap[VSCSI_MAX_SC
    2.13  /*
    2.14    Emulation routines for each SCSI op_code.
    2.15  */
    2.16 -static void (*pre_function[MAX_SCSI_OP_CODE])(pending_request_t *, void *);
    2.17 -static void (*post_function[MAX_SCSI_OP_CODE])(pending_request_t *, void *);
    2.18 +static void (*pre_function[VSCSI_MAX_SCSI_OP_CODE])(pending_req_t *, void *);
    2.19 +static void (*post_function[VSCSI_MAX_SCSI_OP_CODE])(pending_req_t *, void *);
    2.20  
    2.21  
    2.22  static const int check_condition_result =
    2.23  		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
    2.24  
    2.25 +static void scsiback_mk_sense_buffer(uint8_t *data, uint8_t key,
    2.26 +			uint8_t asc, uint8_t asq)
    2.27 +{
    2.28 +	data[0] = 0x70;  /* fixed, current */
    2.29 +	data[2] = key;
    2.30 +	data[7] = 0xa;	  /* implies 18 byte sense buffer */
    2.31 +	data[12] = asc;
    2.32 +	data[13] = asq;
    2.33 +}
    2.34 +
    2.35 +static void resp_not_supported_cmd(pending_req_t *pending_req)
    2.36 +{
    2.37 +	scsiback_mk_sense_buffer(pending_req->sense_buffer, ILLEGAL_REQUEST,
    2.38 +		INVALID_OPCODE, 0);
    2.39 +	pending_req->rslt = check_condition_result;
    2.40 +}
    2.41 +
    2.42  
    2.43  static int __copy_to_sg(struct scatterlist *sg, unsigned int nr_sg,
    2.44  	       void *buf, unsigned int buflen)
    2.45 @@ -91,20 +108,22 @@ static int __copy_to_sg(struct scatterli
    2.46  	void *to;
    2.47  	unsigned int from_rest = buflen;
    2.48  	unsigned int to_capa;
    2.49 -	unsigned int copy_size;
    2.50 +	unsigned int copy_size = 0;
    2.51  	unsigned int i;
    2.52 +	unsigned long pfn;
    2.53  
    2.54  	for (i = 0; i < nr_sg; i++) {
    2.55  		if (sg->page == NULL) {
    2.56 -			printk(KERN_WARN "%s: inconsistent length field in "
    2.57 +			printk(KERN_WARNING "%s: inconsistent length field in "
    2.58  			       "scatterlist\n", __FUNCTION__);
    2.59 -			return -1;
    2.60 +			return -ENOMEM;
    2.61  		}
    2.62  
    2.63  		to_capa  = sg->length;
    2.64 -		copy_size = min_t(to_capa, from_rest);
    2.65 +		copy_size = min_t(unsigned int, to_capa, from_rest);
    2.66  
    2.67 -		to = page_to_virt(sg->page) + (sg->offset);
    2.68 +		pfn = page_to_pfn(sg->page);
    2.69 +		to = pfn_to_kaddr(pfn) + (sg->offset);
    2.70  		memcpy(to, from, copy_size);
    2.71  
    2.72  		from_rest  -= copy_size;
    2.73 @@ -116,9 +135,9 @@ static int __copy_to_sg(struct scatterli
    2.74  		from += copy_size;
    2.75  	}
    2.76  
    2.77 -	printk(KERN_WARN "%s: no space in scatterlist\n",
    2.78 +	printk(KERN_WARNING "%s: no space in scatterlist\n",
    2.79  	       __FUNCTION__);
    2.80 -	return -1;
    2.81 +	return -ENOMEM;
    2.82  }
    2.83  
    2.84  static int __copy_from_sg(struct scatterlist *sg, unsigned int nr_sg,
    2.85 @@ -130,24 +149,26 @@ static int __copy_from_sg(struct scatter
    2.86  	unsigned int to_capa = buflen;
    2.87  	unsigned int copy_size;
    2.88  	unsigned int i;
    2.89 +	unsigned long pfn;
    2.90  
    2.91  	for (i = 0; i < nr_sg; i++) {
    2.92  		if (sg->page == NULL) {
    2.93 -			printk(KERN_WARN "%s: inconsistent length field in "
    2.94 +			printk(KERN_WARNING "%s: inconsistent length field in "
    2.95  			       "scatterlist\n", __FUNCTION__);
    2.96 -			return -1;
    2.97 +			return -ENOMEM;
    2.98  		}
    2.99  
   2.100  		from_rest = sg->length;
   2.101  		if ((from_rest > 0) && (to_capa < from_rest)) {
   2.102 -			printk(KERN_WARN
   2.103 +			printk(KERN_WARNING
   2.104  			       "%s: no space in destination buffer\n",
   2.105  			       __FUNCTION__);
   2.106 -			return -1;
   2.107 +			return -ENOMEM;
   2.108  		}
   2.109  		copy_size = from_rest;
   2.110  
   2.111 -		from = page_to_virt(sg->page) + (sg->offset);
   2.112 +		pfn = page_to_pfn(sg->page);
   2.113 +		from = pfn_to_kaddr(pfn) + (sg->offset);
   2.114  		memcpy(to, from, copy_size);
   2.115  
   2.116  		to_capa  -= copy_size;
   2.117 @@ -160,34 +181,20 @@ static int __copy_from_sg(struct scatter
   2.118  }
   2.119  
   2.120  
   2.121 -static void scsiback_mk_sense_buffer(uint8_t *date, uint8_t key, uint8_t asc,
   2.122 -				utint_8 asq)
   2.123 -{
   2.124 -	data[0] = 0x70;  /* fixed, current */
   2.125 -	data[2] = key;
   2.126 -	data[7] = 0xa;	  /* implies 18 byte sense buffer */
   2.127 -	data[12] = asc;
   2.128 -	data[13] = asq;
   2.129 -}
   2.130 -
   2.131 -
   2.132 -
   2.133 -/* tuning point*/
   2.134 -#define VSCSIIF_RLUN_ARR_SZ		2048
   2.135 -
   2.136  /* quoted scsi_debug.c/resp_report_luns() */
   2.137 -static void __report_luns(pending_request_t *pending_req, void *data)
   2.138 +static void __report_luns(pending_req_t *pending_req, void *data)
   2.139  {
   2.140  	struct vscsibk_info *info   = pending_req->info;
   2.141  	unsigned int        channel = pending_req->sdev->channel;
   2.142  	unsigned int        target  = pending_req->sdev->id;
   2.143 +	unsigned int        nr_seg  = pending_req->nr_segments;
   2.144  	unsigned char *cmd = (unsigned char *)pending_req->cmnd;
   2.145  	
   2.146 -	unsigned char rq_buff[VSCSIIF_RLUN_ARR_SZ];
   2.147 -	unsigned char *sense_buf = pending_req->sense_buffer;
   2.148 +	unsigned char *rq_buff = NULL;
   2.149  	unsigned char alloc_len;
   2.150 +	unsigned int buff_len = 0;
   2.151  	int select_report = (int)cmd[2];
   2.152 -	int lun_cnt = 0;
   2.153 +	int i, lun_cnt = 0, lun, upper, err = 0;
   2.154  	
   2.155  	struct v2p_entry *entry;
   2.156  	struct list_head *head = &(info->v2p_entry_lists);
   2.157 @@ -196,27 +203,24 @@ static void __report_luns(pending_reques
   2.158  	struct scsi_lun *one_lun;
   2.159  
   2.160  	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
   2.161 -	if ((alloc_len < 4) || (select_report != 0)) {
   2.162 -		scsiback_mk_sense_buffer(pending_req->sense_buffer, ILLEGAL_REQUEST,
   2.163 -			INVALID_FIELD_IN_CDB, 0);
   2.164 -		pending_req->rslt = check_condition_result;
   2.165 -		return;
   2.166 +	if ((alloc_len < 4) || (select_report != 0))
   2.167 +		goto fail;
   2.168 +	
   2.169 +	for (i = 0; i < nr_seg; i++)
   2.170 +		buff_len += pending_req->sgl[i].length;
   2.171 +
   2.172 +	if ((rq_buff = kmalloc(buff_len, GFP_KERNEL)) == NULL) {
   2.173 +		printk(KERN_ERR "scsiback:%s kmalloc err\n", __FUNCTION__);
   2.174 +		goto fail;
   2.175  	}
   2.176  
   2.177 -	memset(rq_buff, 0, VSCSIIF_RLUN_ARR_SZ);
   2.178 -	__copy_from_sg(pending_req->sgl, pending_req->nr_segments,
   2.179 -		rq_buff, VSCSIIF_RLUN_ARR_SZ);
   2.180 -
   2.181 -
   2.182 -	rq_buff[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
   2.183 -	rq_buff[3] = (sizeof(struct scsi_lun) * num) & 0xff;
   2.184 -
   2.185 +	memset(rq_buff, 0, buff_len);
   2.186  
   2.187  	one_lun = (struct scsi_lun *) &rq_buff[8];
   2.188  	spin_lock_irqsave(&info->v2p_lock, flags);
   2.189  	list_for_each_entry(entry, head, l) {
   2.190  		if ((entry->v.chn == channel) &&
   2.191 -		    (entry->v.tgt == target) {
   2.192 +		    (entry->v.tgt == target)) {
   2.193  			lun = entry->v.lun;
   2.194  			upper = (lun >> 8) & 0x3f;
   2.195  			if (upper)
   2.196 @@ -225,18 +229,34 @@ static void __report_luns(pending_reques
   2.197  			lun_cnt++;
   2.198  		}
   2.199  	}
   2.200 +
   2.201  	spin_unlock_irqrestore(&info->v2p_lock, flags);
   2.202  
   2.203 +	rq_buff[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff;
   2.204 +	rq_buff[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff;
   2.205  
   2.206 -	lun_alloc = (unsigned char *)(one_lun + lun_cnt) - rq_buff;
   2.207 -	
   2.208 -	return fill_from_dev_buffer(scp, rq_buff,
   2.209 -				    min((int)alloc_len, lun_alloc));
   2.210 +	err = __copy_to_sg(pending_req->sgl, nr_seg, rq_buff, buff_len);
   2.211 +	if (err)
   2.212 +		goto fail;
   2.213 +
   2.214 +	memset(pending_req->sense_buffer, 0, VSCSIIF_SENSE_BUFFERSIZE);
   2.215 +	pending_req->rslt = 0x00;
   2.216 +
   2.217 +	kfree(rq_buff);
   2.218 +	return;
   2.219 +
   2.220 +fail:
   2.221 +	scsiback_mk_sense_buffer(pending_req->sense_buffer, ILLEGAL_REQUEST,
   2.222 +		INVALID_FIELD_IN_CDB, 0);
   2.223 +	pending_req->rslt = check_condition_result;
   2.224 +	if (rq_buff)
   2.225 +		kfree(rq_buff);
   2.226 +	return;
   2.227  }
   2.228  
   2.229  
   2.230  
   2.231 -int __pre_do_emulation(pending_request_t *pending_req, void *data)
   2.232 +int __pre_do_emulation(pending_req_t *pending_req, void *data)
   2.233  {
   2.234  	uint8_t op_code = pending_req->cmnd[0];
   2.235  
   2.236 @@ -253,9 +273,9 @@ int __pre_do_emulation(pending_request_t
   2.237  	return (bitmap[op_code] & VSCSIIF_NEED_CMD_EXEC);
   2.238  }
   2.239  
   2.240 -void scsiback_rsp_emulation(pending_request_t *pending_req)
   2.241 +void scsiback_rsp_emulation(pending_req_t *pending_req)
   2.242  {
   2.243 -	uint8_t op_code = pending_req->cdb[0];
   2.244 +	uint8_t op_code = pending_req->cmnd[0];
   2.245  
   2.246  	if ((bitmap[op_code] & VSCSIIF_NEED_EMULATE_RSPBUF) &&
   2.247  	    post_function[op_code] != NULL) {
   2.248 @@ -268,8 +288,46 @@ void scsiback_rsp_emulation(pending_requ
   2.249  
   2.250  void scsiback_req_emulation_or_cmdexec(pending_req_t *pending_req)
   2.251  {
   2.252 -	if (__pre_do_emulation(pending_req, NULL))
   2.253 +	if (__pre_do_emulation(pending_req, NULL)) {
   2.254  		scsiback_cmd_exec(pending_req);
   2.255 -	else 
   2.256 -		scsiback_do_resp_with_sense(pending_req);
   2.257 +	}
   2.258 +	else {
   2.259 +		scsiback_fast_flush_area(pending_req);
   2.260 +		scsiback_do_resp_with_sense(pending_req->sense_buffer,
   2.261 +			pending_req->rslt, pending_req);
   2.262 +	}
   2.263  }
   2.264 +
   2.265 +
   2.266 +/*
   2.267 +  Following are not customizable functions.
   2.268 +*/
   2.269 +void scsiback_emulation_init(void)
   2.270 +{
   2.271 +	int i;
   2.272 +
   2.273 +	/* Initialize to default state */
   2.274 +	for (i = 0; i < VSCSI_MAX_SCSI_OP_CODE; i++) {
   2.275 +		bitmap[i]        = VSCSIIF_NEED_CMD_EXEC;
   2.276 +		pre_function[i]  = NULL;
   2.277 +		post_function[i] = NULL;
   2.278 +		/* means,
   2.279 +		   - no need for pre-emulation
   2.280 +		   - no need for post-emulation
   2.281 +		   - call native driver
   2.282 +
   2.283 +		   (Current setting is black-list bases, white-list
   2.284 +		   bases may be appropriate for security.)
   2.285 +		*/
   2.286 +	}
   2.287 +
   2.288 +	/*
   2.289 +	  Register appropriate functions below as you need.
   2.290 +	  (See scsi/scsi.h for definition of SCSI op_code.)
   2.291 +	*/
   2.292 +	pre_function[REPORT_LUNS] = __report_luns;
   2.293 +	bitmap[REPORT_LUNS] = (VSCSIIF_NEED_EMULATE_REQBUF | 
   2.294 +					VSCSIIF_NEED_EMULATE_RSPBUF);
   2.295 +
   2.296 +	return;
   2.297 +}
     3.1 --- a/drivers/xen/scsiback/scsiback.c	Thu Jun 05 10:40:33 2008 +0100
     3.2 +++ b/drivers/xen/scsiback/scsiback.c	Thu Jun 05 10:40:54 2008 +0100
     3.3 @@ -78,7 +78,7 @@ static unsigned long vaddr(pending_req_t
     3.4  	(pending_grant_handles[vaddr_pagenr(_req, _seg)])
     3.5  
     3.6  
     3.7 -static void fast_flush_area(pending_req_t *req)
     3.8 +void scsiback_fast_flush_area(pending_req_t *req)
     3.9  {
    3.10  	struct gnttab_unmap_grant_ref unmap[VSCSIIF_SG_TABLESIZE];
    3.11  	unsigned int i, invcount = 0;
    3.12 @@ -141,7 +141,7 @@ static void scsiback_notify_work(struct 
    3.13  	wake_up(&info->wq);
    3.14  }
    3.15  
    3.16 -static void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result,
    3.17 +void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result,
    3.18  				pending_req_t *pending_req)
    3.19  {
    3.20  	vscsiif_response_t *ring_res;
    3.21 @@ -223,10 +223,8 @@ static void scsiback_cmd_done(void *data
    3.22  			__scsi_print_sense("scsiback", sense_buffer, SCSI_SENSE_BUFFERSIZE);
    3.23  	}
    3.24  
    3.25 -#if 0 /*SAMPLE CODING(tentative)*//*emulation*/
    3.26  	scsiback_rsp_emulation(pending_req);
    3.27 -#endif
    3.28 -	fast_flush_area(pending_req);
    3.29 +	scsiback_fast_flush_area(pending_req);
    3.30  	scsiback_do_resp_with_sense(sense_buffer, errors, pending_req);
    3.31  
    3.32  
    3.33 @@ -303,7 +301,7 @@ static int scsiback_gnttab_data_map(vscs
    3.34  	return 0;
    3.35  	
    3.36  fail_flush:
    3.37 -	fast_flush_area(pending_req);
    3.38 +	scsiback_fast_flush_area(pending_req);
    3.39  	return -ENOMEM;
    3.40  }
    3.41  
    3.42 @@ -622,11 +620,7 @@ static int scsiback_do_cmd_fn(struct vsc
    3.43  		}
    3.44  
    3.45  		if (pending_req->act == VSCSIIF_ACT_SCSI_CDB) {
    3.46 -#if 0 /*SAMPLE CODING(tentative)*//*emulation*/
    3.47 -			scsiback_req_emulation_or_through(pending_req);
    3.48 -#else
    3.49 -			scsiback_cmd_exec(pending_req);
    3.50 -#endif
    3.51 +			scsiback_req_emulation_or_cmdexec(pending_req);
    3.52  		} else if (pending_req->act == VSCSIIF_ACT_SCSI_RESET) {
    3.53  			scsiback_device_reset_exec(pending_req);
    3.54  		} else {
    3.55 @@ -707,6 +701,8 @@ static int __init scsiback_init(void)
    3.56  	if (scsiback_xenbus_init())
    3.57  		goto out_of_memory;
    3.58  
    3.59 +	scsiback_emulation_init();
    3.60 +
    3.61  	return 0;
    3.62  
    3.63  out_of_memory: