[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [linux-2.6.18-xen] pvscsi: Enable REPORT_LUN command emulation.
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1212658854 -3600 # Node ID 3b045d92c4c0e1e91c717f7810ba7d44a9f46b13 # Parent ee72fd7d22c86326ff5a6880ac744b0a9e9785cc pvscsi: Enable REPORT_LUN command emulation. Signed-off-by: Tomonari Horikoshi <t.horikoshi@xxxxxxxxxxxxxx> Signed-off-by: Jun Kamada <kama@xxxxxxxxxxxxxx> --- drivers/xen/scsiback/common.h | 11 +- drivers/xen/scsiback/emulate.c | 194 +++++++++++++++++++++++++--------------- drivers/xen/scsiback/scsiback.c | 18 +-- 3 files changed, 139 insertions(+), 84 deletions(-) diff -r ee72fd7d22c8 -r 3b045d92c4c0 drivers/xen/scsiback/common.h --- a/drivers/xen/scsiback/common.h Thu Jun 05 10:40:33 2008 +0100 +++ b/drivers/xen/scsiback/common.h Thu Jun 05 10:40:54 2008 +0100 @@ -60,7 +60,6 @@ #include <xen/interface/io/ring.h> #include <xen/interface/grant_table.h> #include <xen/interface/io/vscsiif.h> - #define DPRINTK(_f, _a...) \ @@ -171,11 +170,13 @@ void scsiback_release_translation_entry( void scsiback_cmd_exec(pending_req_t *pending_req); +void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result, + pending_req_t *pending_req); +void scsiback_fast_flush_area(pending_req_t *req); -#if 0 /*SAMPLE CODING(tentative)*//*emulation*/ -void scsiback_dispatch_emulation_cmdexec(vscsiif_request_t *ring_req, - pending_req_t *pending_req); -#endif +void scsiback_rsp_emulation(pending_req_t *pending_req); +void scsiback_req_emulation_or_cmdexec(pending_req_t *pending_req); +void scsiback_emulation_init(void); #endif /* __SCSIIF__BACKEND__COMMON_H__ */ diff -r ee72fd7d22c8 -r 3b045d92c4c0 drivers/xen/scsiback/emulate.c --- a/drivers/xen/scsiback/emulate.c Thu Jun 05 10:40:33 2008 +0100 +++ b/drivers/xen/scsiback/emulate.c Thu Jun 05 10:40:54 2008 +0100 @@ -31,7 +31,7 @@ #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> -#include "comback.h" +#include "common.h" /* Following SCSI commands are not defined in scsi/scsi.h */ #define EXTENDED_COPY 0x83 /* EXTENDED COPY command */ @@ -76,12 +76,29 @@ static unsigned char bitmap[VSCSI_MAX_SC /* Emulation routines for each SCSI op_code. */ -static void (*pre_function[MAX_SCSI_OP_CODE])(pending_request_t *, void *); -static void (*post_function[MAX_SCSI_OP_CODE])(pending_request_t *, void *); +static void (*pre_function[VSCSI_MAX_SCSI_OP_CODE])(pending_req_t *, void *); +static void (*post_function[VSCSI_MAX_SCSI_OP_CODE])(pending_req_t *, void *); static const int check_condition_result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + +static void scsiback_mk_sense_buffer(uint8_t *data, uint8_t key, + uint8_t asc, uint8_t asq) +{ + data[0] = 0x70; /* fixed, current */ + data[2] = key; + data[7] = 0xa; /* implies 18 byte sense buffer */ + data[12] = asc; + data[13] = asq; +} + +static void resp_not_supported_cmd(pending_req_t *pending_req) +{ + scsiback_mk_sense_buffer(pending_req->sense_buffer, ILLEGAL_REQUEST, + INVALID_OPCODE, 0); + pending_req->rslt = check_condition_result; +} static int __copy_to_sg(struct scatterlist *sg, unsigned int nr_sg, @@ -91,20 +108,22 @@ static int __copy_to_sg(struct scatterli void *to; unsigned int from_rest = buflen; unsigned int to_capa; - unsigned int copy_size; + unsigned int copy_size = 0; unsigned int i; + unsigned long pfn; for (i = 0; i < nr_sg; i++) { if (sg->page == NULL) { - printk(KERN_WARN "%s: inconsistent length field in " + printk(KERN_WARNING "%s: inconsistent length field in " "scatterlist\n", __FUNCTION__); - return -1; + return -ENOMEM; } to_capa = sg->length; - copy_size = min_t(to_capa, from_rest); - - to = page_to_virt(sg->page) + (sg->offset); + copy_size = min_t(unsigned int, to_capa, from_rest); + + pfn = page_to_pfn(sg->page); + to = pfn_to_kaddr(pfn) + (sg->offset); memcpy(to, from, copy_size); from_rest -= copy_size; @@ -116,9 +135,9 @@ static int __copy_to_sg(struct scatterli from += copy_size; } - printk(KERN_WARN "%s: no space in scatterlist\n", + printk(KERN_WARNING "%s: no space in scatterlist\n", __FUNCTION__); - return -1; + return -ENOMEM; } static int __copy_from_sg(struct scatterlist *sg, unsigned int nr_sg, @@ -130,24 +149,26 @@ static int __copy_from_sg(struct scatter unsigned int to_capa = buflen; unsigned int copy_size; unsigned int i; + unsigned long pfn; for (i = 0; i < nr_sg; i++) { if (sg->page == NULL) { - printk(KERN_WARN "%s: inconsistent length field in " + printk(KERN_WARNING "%s: inconsistent length field in " "scatterlist\n", __FUNCTION__); - return -1; + return -ENOMEM; } from_rest = sg->length; if ((from_rest > 0) && (to_capa < from_rest)) { - printk(KERN_WARN + printk(KERN_WARNING "%s: no space in destination buffer\n", __FUNCTION__); - return -1; + return -ENOMEM; } copy_size = from_rest; - from = page_to_virt(sg->page) + (sg->offset); + pfn = page_to_pfn(sg->page); + from = pfn_to_kaddr(pfn) + (sg->offset); memcpy(to, from, copy_size); to_capa -= copy_size; @@ -160,34 +181,20 @@ static int __copy_from_sg(struct scatter } -static void scsiback_mk_sense_buffer(uint8_t *date, uint8_t key, uint8_t asc, - utint_8 asq) -{ - data[0] = 0x70; /* fixed, current */ - data[2] = key; - data[7] = 0xa; /* implies 18 byte sense buffer */ - data[12] = asc; - data[13] = asq; -} - - - -/* tuning point*/ -#define VSCSIIF_RLUN_ARR_SZ 2048 - /* quoted scsi_debug.c/resp_report_luns() */ -static void __report_luns(pending_request_t *pending_req, void *data) +static void __report_luns(pending_req_t *pending_req, void *data) { struct vscsibk_info *info = pending_req->info; unsigned int channel = pending_req->sdev->channel; unsigned int target = pending_req->sdev->id; + unsigned int nr_seg = pending_req->nr_segments; unsigned char *cmd = (unsigned char *)pending_req->cmnd; - unsigned char rq_buff[VSCSIIF_RLUN_ARR_SZ]; - unsigned char *sense_buf = pending_req->sense_buffer; + unsigned char *rq_buff = NULL; unsigned char alloc_len; + unsigned int buff_len = 0; int select_report = (int)cmd[2]; - int lun_cnt = 0; + int i, lun_cnt = 0, lun, upper, err = 0; struct v2p_entry *entry; struct list_head *head = &(info->v2p_entry_lists); @@ -196,27 +203,24 @@ static void __report_luns(pending_reques struct scsi_lun *one_lun; alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); - if ((alloc_len < 4) || (select_report != 0)) { - scsiback_mk_sense_buffer(pending_req->sense_buffer, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0); - pending_req->rslt = check_condition_result; - return; - } - - memset(rq_buff, 0, VSCSIIF_RLUN_ARR_SZ); - __copy_from_sg(pending_req->sgl, pending_req->nr_segments, - rq_buff, VSCSIIF_RLUN_ARR_SZ); - - - rq_buff[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff; - rq_buff[3] = (sizeof(struct scsi_lun) * num) & 0xff; - + if ((alloc_len < 4) || (select_report != 0)) + goto fail; + + for (i = 0; i < nr_seg; i++) + buff_len += pending_req->sgl[i].length; + + if ((rq_buff = kmalloc(buff_len, GFP_KERNEL)) == NULL) { + printk(KERN_ERR "scsiback:%s kmalloc err\n", __FUNCTION__); + goto fail; + } + + memset(rq_buff, 0, buff_len); one_lun = (struct scsi_lun *) &rq_buff[8]; spin_lock_irqsave(&info->v2p_lock, flags); list_for_each_entry(entry, head, l) { if ((entry->v.chn == channel) && - (entry->v.tgt == target) { + (entry->v.tgt == target)) { lun = entry->v.lun; upper = (lun >> 8) & 0x3f; if (upper) @@ -225,18 +229,34 @@ static void __report_luns(pending_reques lun_cnt++; } } + spin_unlock_irqrestore(&info->v2p_lock, flags); - - lun_alloc = (unsigned char *)(one_lun + lun_cnt) - rq_buff; - - return fill_from_dev_buffer(scp, rq_buff, - min((int)alloc_len, lun_alloc)); -} - - - -int __pre_do_emulation(pending_request_t *pending_req, void *data) + rq_buff[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff; + rq_buff[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff; + + err = __copy_to_sg(pending_req->sgl, nr_seg, rq_buff, buff_len); + if (err) + goto fail; + + memset(pending_req->sense_buffer, 0, VSCSIIF_SENSE_BUFFERSIZE); + pending_req->rslt = 0x00; + + kfree(rq_buff); + return; + +fail: + scsiback_mk_sense_buffer(pending_req->sense_buffer, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + pending_req->rslt = check_condition_result; + if (rq_buff) + kfree(rq_buff); + return; +} + + + +int __pre_do_emulation(pending_req_t *pending_req, void *data) { uint8_t op_code = pending_req->cmnd[0]; @@ -253,9 +273,9 @@ int __pre_do_emulation(pending_request_t return (bitmap[op_code] & VSCSIIF_NEED_CMD_EXEC); } -void scsiback_rsp_emulation(pending_request_t *pending_req) -{ - uint8_t op_code = pending_req->cdb[0]; +void scsiback_rsp_emulation(pending_req_t *pending_req) +{ + uint8_t op_code = pending_req->cmnd[0]; if ((bitmap[op_code] & VSCSIIF_NEED_EMULATE_RSPBUF) && post_function[op_code] != NULL) { @@ -268,8 +288,46 @@ void scsiback_rsp_emulation(pending_requ void scsiback_req_emulation_or_cmdexec(pending_req_t *pending_req) { - if (__pre_do_emulation(pending_req, NULL)) + if (__pre_do_emulation(pending_req, NULL)) { scsiback_cmd_exec(pending_req); - else - scsiback_do_resp_with_sense(pending_req); -} + } + else { + scsiback_fast_flush_area(pending_req); + scsiback_do_resp_with_sense(pending_req->sense_buffer, + pending_req->rslt, pending_req); + } +} + + +/* + Following are not customizable functions. +*/ +void scsiback_emulation_init(void) +{ + int i; + + /* Initialize to default state */ + for (i = 0; i < VSCSI_MAX_SCSI_OP_CODE; i++) { + bitmap[i] = VSCSIIF_NEED_CMD_EXEC; + pre_function[i] = NULL; + post_function[i] = NULL; + /* means, + - no need for pre-emulation + - no need for post-emulation + - call native driver + + (Current setting is black-list bases, white-list + bases may be appropriate for security.) + */ + } + + /* + Register appropriate functions below as you need. + (See scsi/scsi.h for definition of SCSI op_code.) + */ + pre_function[REPORT_LUNS] = __report_luns; + bitmap[REPORT_LUNS] = (VSCSIIF_NEED_EMULATE_REQBUF | + VSCSIIF_NEED_EMULATE_RSPBUF); + + return; +} diff -r ee72fd7d22c8 -r 3b045d92c4c0 drivers/xen/scsiback/scsiback.c --- a/drivers/xen/scsiback/scsiback.c Thu Jun 05 10:40:33 2008 +0100 +++ b/drivers/xen/scsiback/scsiback.c Thu Jun 05 10:40:54 2008 +0100 @@ -78,7 +78,7 @@ static unsigned long vaddr(pending_req_t (pending_grant_handles[vaddr_pagenr(_req, _seg)]) -static void fast_flush_area(pending_req_t *req) +void scsiback_fast_flush_area(pending_req_t *req) { struct gnttab_unmap_grant_ref unmap[VSCSIIF_SG_TABLESIZE]; unsigned int i, invcount = 0; @@ -141,7 +141,7 @@ static void scsiback_notify_work(struct wake_up(&info->wq); } -static void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result, +void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result, pending_req_t *pending_req) { vscsiif_response_t *ring_res; @@ -223,10 +223,8 @@ static void scsiback_cmd_done(void *data __scsi_print_sense("scsiback", sense_buffer, SCSI_SENSE_BUFFERSIZE); } -#if 0 /*SAMPLE CODING(tentative)*//*emulation*/ scsiback_rsp_emulation(pending_req); -#endif - fast_flush_area(pending_req); + scsiback_fast_flush_area(pending_req); scsiback_do_resp_with_sense(sense_buffer, errors, pending_req); @@ -303,7 +301,7 @@ static int scsiback_gnttab_data_map(vscs return 0; fail_flush: - fast_flush_area(pending_req); + scsiback_fast_flush_area(pending_req); return -ENOMEM; } @@ -622,11 +620,7 @@ static int scsiback_do_cmd_fn(struct vsc } if (pending_req->act == VSCSIIF_ACT_SCSI_CDB) { -#if 0 /*SAMPLE CODING(tentative)*//*emulation*/ - scsiback_req_emulation_or_through(pending_req); -#else - scsiback_cmd_exec(pending_req); -#endif + scsiback_req_emulation_or_cmdexec(pending_req); } else if (pending_req->act == VSCSIIF_ACT_SCSI_RESET) { scsiback_device_reset_exec(pending_req); } else { @@ -707,6 +701,8 @@ static int __init scsiback_init(void) if (scsiback_xenbus_init()) goto out_of_memory; + scsiback_emulation_init(); + return 0; out_of_memory: _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |