]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/scsi_debug.c
[SCSI] consolidate command allocation in a single place
[linux-2.6-omap-h63xx.git] / drivers / scsi / scsi_debug.c
index 46cae5a212ded1df5e85b607119335065206dc98..7a2a3edcc723bbcda2621e341669b782ec78be25 100644 (file)
 #include <linux/vmalloc.h>
 #include <linux/moduleparam.h>
 #include <linux/scatterlist.h>
-
 #include <linux/blkdev.h>
-#include "scsi.h"
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsicam.h>
 
 #include <linux/stat.h>
 
 #include "scsi_logging.h"
-#include "scsi_debug.h"
 
 #define SCSI_DEBUG_VERSION "1.81"
 static const char * scsi_debug_version_date = "20070104";
@@ -165,6 +166,9 @@ static int sdebug_sectors_per;              /* sectors per cylinder */
 
 #define SDEBUG_SENSE_LEN 32
 
+#define SCSI_DEBUG_CANQUEUE  255
+#define SCSI_DEBUG_MAX_CMD_LEN 16
+
 struct sdebug_dev_info {
        struct list_head dev_list;
        unsigned char sense_buff[SDEBUG_SENSE_LEN];     /* weak nexus */
@@ -202,30 +206,6 @@ struct sdebug_queued_cmd {
 };
 static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
 
-static struct scsi_host_template sdebug_driver_template = {
-       .proc_info =            scsi_debug_proc_info,
-       .name =                 "SCSI DEBUG",
-       .info =                 scsi_debug_info,
-       .slave_alloc =          scsi_debug_slave_alloc,
-       .slave_configure =      scsi_debug_slave_configure,
-       .slave_destroy =        scsi_debug_slave_destroy,
-       .ioctl =                scsi_debug_ioctl,
-       .queuecommand =         scsi_debug_queuecommand,
-       .eh_abort_handler =     scsi_debug_abort,
-       .eh_bus_reset_handler = scsi_debug_bus_reset,
-       .eh_device_reset_handler = scsi_debug_device_reset,
-       .eh_host_reset_handler = scsi_debug_host_reset,
-       .bios_param =           scsi_debug_biosparam,
-       .can_queue =            SCSI_DEBUG_CANQUEUE,
-       .this_id =              7,
-       .sg_tablesize =         256,
-       .cmd_per_lun =          16,
-       .max_sectors =          0xffff,
-       .unchecked_isa_dma =    0,
-       .use_clustering =       ENABLE_CLUSTERING,
-       .module =               THIS_MODULE,
-};
-
 static unsigned char * fake_storep;    /* ramdisk storage */
 
 static int num_aborts = 0;
@@ -280,6 +260,8 @@ static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
                      unsigned int num, struct sdebug_dev_info * devip);
 static int resp_report_luns(struct scsi_cmnd * SCpnt,
                            struct sdebug_dev_info * devip);
+static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
+                           unsigned int num, struct sdebug_dev_info *devip);
 static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
                                 int arr_len);
 static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
@@ -311,12 +293,48 @@ static void sdebug_max_tgts_luns(void);
 static struct device pseudo_primary;
 static struct bus_type pseudo_lld_bus;
 
+static void get_data_transfer_info(unsigned char *cmd,
+                                  unsigned long long *lba, unsigned int *num)
+{
+       int i;
+
+       switch (*cmd) {
+       case WRITE_16:
+       case READ_16:
+               for (*lba = 0, i = 0; i < 8; ++i) {
+                       if (i > 0)
+                               *lba <<= 8;
+                       *lba += cmd[2 + i];
+               }
+               *num = cmd[13] + (cmd[12] << 8) +
+                       (cmd[11] << 16) + (cmd[10] << 24);
+               break;
+       case WRITE_12:
+       case READ_12:
+               *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
+               *num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
+               break;
+       case WRITE_10:
+       case READ_10:
+       case XDWRITEREAD_10:
+               *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
+               *num = cmd[8] + (cmd[7] << 8);
+               break;
+       case WRITE_6:
+       case READ_6:
+               *lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
+               *num = (0 == cmd[4]) ? 256 : cmd[4];
+               break;
+       default:
+               break;
+       }
+}
 
 static
 int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
 {
        unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
-       int len, k, j;
+       int len, k;
        unsigned int num;
        unsigned long long lba;
        int errsts = 0;
@@ -326,17 +344,15 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
        int inj_transport = 0;
        int delay_override = 0;
 
-       if (done == NULL)
-               return 0;       /* assume mid level reprocessing command */
-
-       SCpnt->resid = 0;
+       scsi_set_resid(SCpnt, 0);
        if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
                printk(KERN_INFO "scsi_debug: cmd ");
                for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
                        printk("%02x ", (int)cmd[k]);
                printk("\n");
        }
-        if(target == sdebug_driver_template.this_id) {
+
+       if (target == SCpnt->device->host->hostt->this_id) {
                printk(KERN_INFO "scsi_debug: initiator's id used as "
                       "target!\n");
                return schedule_resp(SCpnt, NULL, done,
@@ -452,28 +468,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
                        break;
                if (scsi_debug_fake_rw)
                        break;
-               if ((*cmd) == READ_16) {
-                       for (lba = 0, j = 0; j < 8; ++j) {
-                               if (j > 0)
-                                       lba <<= 8;
-                               lba += cmd[2 + j];
-                       }
-                       num = cmd[13] + (cmd[12] << 8) +
-                               (cmd[11] << 16) + (cmd[10] << 24);
-               } else if ((*cmd) == READ_12) {
-                       lba = cmd[5] + (cmd[4] << 8) +
-                               (cmd[3] << 16) + (cmd[2] << 24);
-                       num = cmd[9] + (cmd[8] << 8) +
-                               (cmd[7] << 16) + (cmd[6] << 24);
-               } else if ((*cmd) == READ_10) {
-                       lba = cmd[5] + (cmd[4] << 8) +
-                               (cmd[3] << 16) + (cmd[2] << 24);
-                       num = cmd[8] + (cmd[7] << 8);
-               } else {        /* READ (6) */
-                       lba = cmd[3] + (cmd[2] << 8) +
-                               ((cmd[1] & 0x1f) << 16);
-                       num = (0 == cmd[4]) ? 256 : cmd[4];
-               }
+               get_data_transfer_info(cmd, &lba, &num);
                errsts = resp_read(SCpnt, lba, num, devip);
                if (inj_recovered && (0 == errsts)) {
                        mk_sense_buffer(devip, RECOVERED_ERROR,
@@ -500,28 +495,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
                        break;
                if (scsi_debug_fake_rw)
                        break;
-               if ((*cmd) == WRITE_16) {
-                       for (lba = 0, j = 0; j < 8; ++j) {
-                               if (j > 0)
-                                       lba <<= 8;
-                               lba += cmd[2 + j];
-                       }
-                       num = cmd[13] + (cmd[12] << 8) +
-                               (cmd[11] << 16) + (cmd[10] << 24);
-               } else if ((*cmd) == WRITE_12) {
-                       lba = cmd[5] + (cmd[4] << 8) +
-                               (cmd[3] << 16) + (cmd[2] << 24);
-                       num = cmd[9] + (cmd[8] << 8) +
-                               (cmd[7] << 16) + (cmd[6] << 24);
-               } else if ((*cmd) == WRITE_10) {
-                       lba = cmd[5] + (cmd[4] << 8) +
-                               (cmd[3] << 16) + (cmd[2] << 24);
-                       num = cmd[8] + (cmd[7] << 8);
-               } else {        /* WRITE (6) */
-                       lba = cmd[3] + (cmd[2] << 8) +
-                               ((cmd[1] & 0x1f) << 16);
-                       num = (0 == cmd[4]) ? 256 : cmd[4];
-               }
+               get_data_transfer_info(cmd, &lba, &num);
                errsts = resp_write(SCpnt, lba, num, devip);
                if (inj_recovered && (0 == errsts)) {
                        mk_sense_buffer(devip, RECOVERED_ERROR,
@@ -549,6 +523,28 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
        case WRITE_BUFFER:
                errsts = check_readiness(SCpnt, 1, devip);
                break;
+       case XDWRITEREAD_10:
+               if (!scsi_bidi_cmnd(SCpnt)) {
+                       mk_sense_buffer(devip, ILLEGAL_REQUEST,
+                                       INVALID_FIELD_IN_CDB, 0);
+                       errsts = check_condition_result;
+                       break;
+               }
+
+               errsts = check_readiness(SCpnt, 0, devip);
+               if (errsts)
+                       break;
+               if (scsi_debug_fake_rw)
+                       break;
+               get_data_transfer_info(cmd, &lba, &num);
+               errsts = resp_read(SCpnt, lba, num, devip);
+               if (errsts)
+                       break;
+               errsts = resp_write(SCpnt, lba, num, devip);
+               if (errsts)
+                       break;
+               errsts = resp_xdwriteread(SCpnt, lba, num, devip);
+               break;
        default:
                if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
                        printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
@@ -595,99 +591,37 @@ static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
 }
 
 /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
-static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
+static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
                                int arr_len)
 {
-       int k, req_len, act_len, len, active;
-       void * kaddr;
-       void * kaddr_off;
-       struct scatterlist * sg;
+       int act_len;
+       struct scsi_data_buffer *sdb = scsi_in(scp);
 
-       if (0 == scp->request_bufflen)
+       if (!sdb->length)
                return 0;
-       if (NULL == scp->request_buffer)
+       if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
                return (DID_ERROR << 16);
-       if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
-             (scp->sc_data_direction == DMA_FROM_DEVICE)))
-               return (DID_ERROR << 16);
-       if (0 == scp->use_sg) {
-               req_len = scp->request_bufflen;
-               act_len = (req_len < arr_len) ? req_len : arr_len;
-               memcpy(scp->request_buffer, arr, act_len);
-               if (scp->resid)
-                       scp->resid -= act_len;
-               else
-                       scp->resid = req_len - act_len;
-               return 0;
-       }
-       active = 1;
-       req_len = act_len = 0;
-       scsi_for_each_sg(scp, sg, scp->use_sg, k) {
-               if (active) {
-                       kaddr = (unsigned char *)
-                               kmap_atomic(sg_page(sg), KM_USER0);
-                       if (NULL == kaddr)
-                               return (DID_ERROR << 16);
-                       kaddr_off = (unsigned char *)kaddr + sg->offset;
-                       len = sg->length;
-                       if ((req_len + len) > arr_len) {
-                               active = 0;
-                               len = arr_len - req_len;
-                       }
-                       memcpy(kaddr_off, arr + req_len, len);
-                       kunmap_atomic(kaddr, KM_USER0);
-                       act_len += len;
-               }
-               req_len += sg->length;
-       }
-       if (scp->resid)
-               scp->resid -= act_len;
+
+       act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
+                                     arr, arr_len);
+       if (sdb->resid)
+               sdb->resid -= act_len;
        else
-               scp->resid = req_len - act_len;
+               sdb->resid = scsi_bufflen(scp) - act_len;
+
        return 0;
 }
 
 /* Returns number of bytes fetched into 'arr' or -1 if error. */
-static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
-                              int max_arr_len)
+static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
+                              int arr_len)
 {
-       int k, req_len, len, fin;
-       void * kaddr;
-       void * kaddr_off;
-       struct scatterlist * sg;
-
-       if (0 == scp->request_bufflen)
+       if (!scsi_bufflen(scp))
                return 0;
-       if (NULL == scp->request_buffer)
-               return -1;
-       if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
-             (scp->sc_data_direction == DMA_TO_DEVICE)))
+       if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
                return -1;
-       if (0 == scp->use_sg) {
-               req_len = scp->request_bufflen;
-               len = (req_len < max_arr_len) ? req_len : max_arr_len;
-               memcpy(arr, scp->request_buffer, len);
-               return len;
-       }
-       sg = scsi_sglist(scp);
-       req_len = fin = 0;
-       for (k = 0; k < scp->use_sg; ++k, sg = sg_next(sg)) {
-               kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
-               if (NULL == kaddr)
-                       return -1;
-               kaddr_off = (unsigned char *)kaddr + sg->offset;
-               len = sg->length;
-               if ((req_len + len) > max_arr_len) {
-                       len = max_arr_len - req_len;
-                       fin = 1;
-               }
-               memcpy(arr + req_len, kaddr_off, len);
-               kunmap_atomic(kaddr, KM_USER0);
-               if (fin)
-                       return req_len + len;
-               req_len += sg->length;
-       }
-       return req_len;
+
+       return scsi_sg_copy_to_buffer(scp, arr, arr_len);
 }
 
 
@@ -1973,6 +1907,41 @@ static int resp_report_luns(struct scsi_cmnd * scp,
                                    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
 }
 
+static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
+                           unsigned int num, struct sdebug_dev_info *devip)
+{
+       int i, j, ret = -1;
+       unsigned char *kaddr, *buf;
+       unsigned int offset;
+       struct scatterlist *sg;
+       struct scsi_data_buffer *sdb = scsi_in(scp);
+
+       /* better not to use temporary buffer. */
+       buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
+       if (!buf)
+               return ret;
+
+       scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
+
+       offset = 0;
+       for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
+               kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
+               if (!kaddr)
+                       goto out;
+
+               for (j = 0; j < sg->length; j++)
+                       *(kaddr + sg->offset + j) ^= *(buf + offset + j);
+
+               offset += sg->length;
+               kunmap_atomic(kaddr, KM_USER0);
+       }
+       ret = 0;
+out:
+       kfree(buf);
+
+       return ret;
+}
+
 /* When timer goes off this function is called. */
 static void timer_intr_handler(unsigned long indx)
 {
@@ -2006,6 +1975,7 @@ static int scsi_debug_slave_alloc(struct scsi_device * sdp)
        if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
                printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
                       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
+       set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
        return 0;
 }
 
@@ -2053,8 +2023,8 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
 
        if (devip)
                return devip;
-       sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata;
-        if(! sdbg_host) {
+       sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
+       if (!sdbg_host) {
                 printk(KERN_ERR "Host info NULL\n");
                return NULL;
         }
@@ -2181,7 +2151,7 @@ static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
                printk(KERN_INFO "scsi_debug: bus_reset\n");
        ++num_bus_resets;
        if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
-               sdbg_host = *(struct sdebug_host_info **) hp->hostdata;
+               sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
                if (sdbg_host) {
                        list_for_each_entry(dev_info,
                                             &sdbg_host->dev_info_list,
@@ -2877,8 +2847,6 @@ static int __init scsi_debug_init(void)
 
        init_all_queued();
 
-       sdebug_driver_template.proc_name = sdebug_proc_name;
-
        host_to_add = scsi_debug_add_host;
         scsi_debug_add_host = 0;
 
@@ -3038,6 +3006,30 @@ static void sdebug_remove_adapter(void)
         --scsi_debug_add_host;
 }
 
+static struct scsi_host_template sdebug_driver_template = {
+       .proc_info =            scsi_debug_proc_info,
+       .proc_name =            sdebug_proc_name,
+       .name =                 "SCSI DEBUG",
+       .info =                 scsi_debug_info,
+       .slave_alloc =          scsi_debug_slave_alloc,
+       .slave_configure =      scsi_debug_slave_configure,
+       .slave_destroy =        scsi_debug_slave_destroy,
+       .ioctl =                scsi_debug_ioctl,
+       .queuecommand =         scsi_debug_queuecommand,
+       .eh_abort_handler =     scsi_debug_abort,
+       .eh_bus_reset_handler = scsi_debug_bus_reset,
+       .eh_device_reset_handler = scsi_debug_device_reset,
+       .eh_host_reset_handler = scsi_debug_host_reset,
+       .bios_param =           scsi_debug_biosparam,
+       .can_queue =            SCSI_DEBUG_CANQUEUE,
+       .this_id =              7,
+       .sg_tablesize =         256,
+       .cmd_per_lun =          16,
+       .max_sectors =          0xffff,
+       .use_clustering =       DISABLE_CLUSTERING,
+       .module =               THIS_MODULE,
+};
+
 static int sdebug_driver_probe(struct device * dev)
 {
         int error = 0;