# 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
|