[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.