# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1216203554 -3600
# Node ID bd4b58143713a9d379570707a755079c7cb4f62d
# Parent a682229d0eacf0bdd25b87a27143d451792f251b
pvSCSI: Sanity check for REPORT_LUN emulation
- Sanity check for REPORT_LUN emulation.
- Return "residual" value from backend to frontend. The residual value
is used to represent difference between request size the frontend
requested and size backend actually responded.
Signed-off-by: Tomonari Horikoshi <t.horikoshi@xxxxxxxxxxxxxx>
Signed-off-by: Jun Kamada <kama@xxxxxxxxxxxxxx>
---
drivers/xen/scsiback/common.h | 3 -
drivers/xen/scsiback/emulate.c | 83 ++++++++++++++++++++++++++-----------
drivers/xen/scsiback/scsiback.c | 16 ++++---
drivers/xen/scsifront/scsifront.c | 2
include/xen/interface/io/vscsiif.h | 4 +
5 files changed, 76 insertions(+), 32 deletions(-)
diff -r a682229d0eac -r bd4b58143713 drivers/xen/scsiback/common.h
--- a/drivers/xen/scsiback/common.h Tue Jul 15 16:39:39 2008 +0100
+++ b/drivers/xen/scsiback/common.h Wed Jul 16 11:19:14 2008 +0100
@@ -124,6 +124,7 @@ typedef struct {
grant_ref_t gref[VSCSIIF_SG_TABLESIZE];
int32_t rslt;
+ uint32_t resid;
uint8_t sense_buffer[VSCSIIF_SENSE_BUFFERSIZE];
struct list_head free_list;
@@ -169,7 +170,7 @@ 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);
+ uint32_t resid, pending_req_t *pending_req);
void scsiback_fast_flush_area(pending_req_t *req);
void scsiback_rsp_emulation(pending_req_t *pending_req);
diff -r a682229d0eac -r bd4b58143713 drivers/xen/scsiback/emulate.c
--- a/drivers/xen/scsiback/emulate.c Tue Jul 15 16:39:39 2008 +0100
+++ b/drivers/xen/scsiback/emulate.c Wed Jul 16 11:19:14 2008 +0100
@@ -73,6 +73,10 @@
#define VSCSI_MAX_SCSI_OP_CODE 256
static unsigned char bitmap[VSCSI_MAX_SCSI_OP_CODE];
+/* REPORT LUNS Header*/
+#define VSCSI_REPORT_LUNS_HEADER 8
+
+
/*
Emulation routines for each SCSI op_code.
*/
@@ -97,7 +101,8 @@ static void resp_not_supported_cmd(pendi
{
scsiback_mk_sense_buffer(pending_req->sense_buffer, ILLEGAL_REQUEST,
INVALID_OPCODE, 0);
- pending_req->rslt = check_condition_result;
+ pending_req->resid = 0;
+ pending_req->rslt = check_condition_result;
}
@@ -180,6 +185,21 @@ static int __copy_from_sg(struct scatter
return 0;
}
+static int __nr_luns_under_host(struct vscsibk_info *info)
+{
+ struct v2p_entry *entry;
+ struct list_head *head = &(info->v2p_entry_lists);
+ unsigned long flags;
+ int lun_cnt = 0;
+
+ spin_lock_irqsave(&info->v2p_lock, flags);
+ list_for_each_entry(entry, head, l) {
+ lun_cnt++;
+ }
+ spin_unlock_irqrestore(&info->v2p_lock, flags);
+
+ return (lun_cnt);
+}
/* quoted scsi_debug.c/resp_report_luns() */
static void __report_luns(pending_req_t *pending_req, void *data)
@@ -190,9 +210,11 @@ static void __report_luns(pending_req_t
unsigned int nr_seg = pending_req->nr_segments;
unsigned char *cmd = (unsigned char *)pending_req->cmnd;
- unsigned char *rq_buff = NULL;
+ unsigned char *buff = NULL;
unsigned char alloc_len;
- unsigned int buff_len = 0;
+ unsigned int alloc_luns = 0;
+ unsigned int req_bufflen = 0;
+ unsigned int actual_len = 0;
int select_report = (int)cmd[2];
int i, lun_cnt = 0, lun, upper, err = 0;
@@ -202,25 +224,31 @@ static void __report_luns(pending_req_t
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))
+ req_bufflen = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
+ if ((req_bufflen < 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) {
+
+ alloc_luns = __nr_luns_under_host(info);
+ alloc_len = sizeof(struct scsi_lun) * alloc_luns
+ + VSCSI_REPORT_LUNS_HEADER;
+
+ if ((buff = kmalloc(alloc_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];
+ memset(buff, 0, alloc_len);
+
+ one_lun = (struct scsi_lun *) &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)) {
+
+ /* check overflow */
+ if (lun_cnt >= alloc_luns)
+ goto fail;
+
lun = entry->v.lun;
upper = (lun >> 8) & 0x3f;
if (upper)
@@ -232,25 +260,34 @@ static void __report_luns(pending_req_t
spin_unlock_irqrestore(&info->v2p_lock, flags);
- 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);
+ buff[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff;
+ buff[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff;
+
+ actual_len = lun_cnt * sizeof(struct scsi_lun)
+ + VSCSI_REPORT_LUNS_HEADER;
+ req_bufflen = 0;
+ for (i = 0; i < nr_seg; i++)
+ req_bufflen += pending_req->sgl[i].length;
+
+ err = __copy_to_sg(pending_req->sgl, nr_seg, buff,
+ min(req_bufflen, actual_len));
if (err)
goto fail;
memset(pending_req->sense_buffer, 0, VSCSIIF_SENSE_BUFFERSIZE);
pending_req->rslt = 0x00;
-
- kfree(rq_buff);
+ pending_req->resid = req_bufflen - min(req_bufflen, actual_len);
+
+ kfree(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);
+ pending_req->rslt = check_condition_result;
+ pending_req->resid = 0;
+ if (buff)
+ kfree(buff);
return;
}
@@ -294,7 +331,7 @@ void scsiback_req_emulation_or_cmdexec(p
else {
scsiback_fast_flush_area(pending_req);
scsiback_do_resp_with_sense(pending_req->sense_buffer,
- pending_req->rslt, pending_req);
+ pending_req->rslt, pending_req->resid, pending_req);
}
}
diff -r a682229d0eac -r bd4b58143713 drivers/xen/scsiback/scsiback.c
--- a/drivers/xen/scsiback/scsiback.c Tue Jul 15 16:39:39 2008 +0100
+++ b/drivers/xen/scsiback/scsiback.c Wed Jul 16 11:19:14 2008 +0100
@@ -142,7 +142,7 @@ static void scsiback_notify_work(struct
}
void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result,
- pending_req_t *pending_req)
+ uint32_t resid, pending_req_t *pending_req)
{
vscsiif_response_t *ring_res;
struct vscsibk_info *info = pending_req->info;
@@ -167,6 +167,8 @@ void scsiback_do_resp_with_sense(char *s
} else {
ring_res->sense_len = 0;
}
+
+ ring_res->residual_len = resid;
RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&info->ring, notify);
if (info->ring.rsp_prod_pvt == info->ring.req_cons) {
@@ -209,8 +211,10 @@ static void scsiback_cmd_done(struct req
{
pending_req_t *pending_req = req->end_io_data;
unsigned char *sense_buffer;
+ unsigned int resid;
sense_buffer = req->sense;
+ resid = req->data_len;
if (errors != 0) {
if (log_print_stat)
@@ -220,7 +224,7 @@ static void scsiback_cmd_done(struct req
scsiback_rsp_emulation(pending_req);
scsiback_fast_flush_area(pending_req);
- scsiback_do_resp_with_sense(sense_buffer, errors, pending_req);
+ scsiback_do_resp_with_sense(sense_buffer, errors, resid, pending_req);
scsiback_put(pending_req->info);
__blk_put_request(req->q, req);
@@ -473,7 +477,7 @@ static void scsiback_device_reset_exec(p
scsiback_get(info);
err = scsi_reset_provider(sdev, SCSI_TRY_RESET_DEVICE);
- scsiback_do_resp_with_sense(NULL, err, pending_req);
+ scsiback_do_resp_with_sense(NULL, err, 0, pending_req);
scsiback_put(info);
return;
@@ -592,11 +596,11 @@ static int scsiback_do_cmd_fn(struct vsc
pending_req);
if (err == -EINVAL) {
scsiback_do_resp_with_sense(NULL, (DRIVER_ERROR << 24),
- pending_req);
+ 0, pending_req);
continue;
} else if (err == -ENODEV) {
scsiback_do_resp_with_sense(NULL, (DID_NO_CONNECT <<
16),
- pending_req);
+ 0, pending_req);
continue;
}
@@ -607,7 +611,7 @@ static int scsiback_do_cmd_fn(struct vsc
} else {
printk(KERN_ERR "scsiback: invalid parameter for
request\n");
scsiback_do_resp_with_sense(NULL, (DRIVER_ERROR << 24),
- pending_req);
+ 0, pending_req);
continue;
}
}
diff -r a682229d0eac -r bd4b58143713 drivers/xen/scsifront/scsifront.c
--- a/drivers/xen/scsifront/scsifront.c Tue Jul 15 16:39:39 2008 +0100
+++ b/drivers/xen/scsifront/scsifront.c Wed Jul 16 11:19:14 2008 +0100
@@ -147,7 +147,7 @@ static void scsifront_cdb_cmd_done(struc
add_id_to_freelist(info, id);
sc->result = ring_res->rslt;
- sc->resid = 0;
+ sc->resid = ring_res->residual_len;
if (ring_res->sense_len > VSCSIIF_SENSE_BUFFERSIZE)
sense_len = VSCSIIF_SENSE_BUFFERSIZE;
diff -r a682229d0eac -r bd4b58143713 include/xen/interface/io/vscsiif.h
--- a/include/xen/interface/io/vscsiif.h Tue Jul 15 16:39:39 2008 +0100
+++ b/include/xen/interface/io/vscsiif.h Wed Jul 16 11:19:14 2008 +0100
@@ -84,7 +84,9 @@ struct vscsiif_response {
uint8_t sense_len;
uint8_t sense_buffer[VSCSIIF_SENSE_BUFFERSIZE];
int32_t rslt;
- uint32_t reserved[37];
+ uint32_t residual_len; /* request bufflen -
+ return the value from physical device */
+ uint32_t reserved[36];
};
typedef struct vscsiif_response vscsiif_response_t;
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|