target: use ->exectute_task for all CDB emulation
authorChristoph Hellwig <hch@infradead.org>
Thu, 3 Nov 2011 21:50:45 +0000 (17:50 -0400)
committerNicholas Bellinger <nab@linux-iscsi.org>
Fri, 4 Nov 2011 10:44:35 +0000 (10:44 +0000)
Instead of calling into transport_emulate_control_cdb from
__transport_execute_tasks for some CDBs always set up ->exectute_tasks
in the command sequence and use it uniformly.

(nab: Add default passthrough break for SERVICE_ACTION_IN)

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
drivers/target/target_core_cdb.c
drivers/target/target_core_cdb.h [new file with mode: 0644]
drivers/target/target_core_transport.c

index 5a03085304e594066eb1da1fa70f1386c649d6ed..683ba02b8247feddd92777fc46824196e5a60180 100644 (file)
@@ -32,6 +32,7 @@
 #include <target/target_core_transport.h>
 #include <target/target_core_fabric_ops.h>
 #include "target_core_ua.h"
+#include "target_core_cdb.h"
 
 static void
 target_fill_alua_data(struct se_port *port, unsigned char *buf)
@@ -679,8 +680,7 @@ target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf)
        return 0;
 }
 
-static int
-target_emulate_inquiry(struct se_task *task)
+int target_emulate_inquiry(struct se_task *task)
 {
        struct se_cmd *cmd = task->task_se_cmd;
        struct se_device *dev = cmd->se_dev;
@@ -731,8 +731,7 @@ out:
        return ret;
 }
 
-static int
-target_emulate_readcapacity(struct se_task *task)
+int target_emulate_readcapacity(struct se_task *task)
 {
        struct se_cmd *cmd = task->task_se_cmd;
        struct se_device *dev = cmd->se_dev;
@@ -768,8 +767,7 @@ target_emulate_readcapacity(struct se_task *task)
        return 0;
 }
 
-static int
-target_emulate_readcapacity_16(struct se_task *task)
+int target_emulate_readcapacity_16(struct se_task *task)
 {
        struct se_cmd *cmd = task->task_se_cmd;
        struct se_device *dev = cmd->se_dev;
@@ -939,8 +937,7 @@ target_modesense_dpofua(unsigned char *buf, int type)
        }
 }
 
-static int
-target_emulate_modesense(struct se_task *task)
+int target_emulate_modesense(struct se_task *task)
 {
        struct se_cmd *cmd = task->task_se_cmd;
        struct se_device *dev = cmd->se_dev;
@@ -1019,8 +1016,7 @@ target_emulate_modesense(struct se_task *task)
        return 0;
 }
 
-static int
-target_emulate_request_sense(struct se_task *task)
+int target_emulate_request_sense(struct se_task *task)
 {
        struct se_cmd *cmd = task->task_se_cmd;
        unsigned char *cdb = cmd->t_task_cdb;
@@ -1090,8 +1086,7 @@ end:
  * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
  * Note this is not used for TCM/pSCSI passthrough
  */
-static int
-target_emulate_unmap(struct se_task *task)
+int target_emulate_unmap(struct se_task *task)
 {
        struct se_cmd *cmd = task->task_se_cmd;
        struct se_device *dev = cmd->se_dev;
@@ -1150,8 +1145,7 @@ err:
  * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
  * Note this is not used for TCM/pSCSI passthrough
  */
-static int
-target_emulate_write_same(struct se_task *task)
+int target_emulate_write_same(struct se_task *task)
 {
        struct se_cmd *cmd = task->task_se_cmd;
        struct se_device *dev = cmd->se_dev;
@@ -1196,8 +1190,7 @@ target_emulate_write_same(struct se_task *task)
        return 0;
 }
 
-static int
-target_emulate_synchronize_cache(struct se_task *task)
+int target_emulate_synchronize_cache(struct se_task *task)
 {
        struct se_device *dev = task->task_se_cmd->se_dev;
 
@@ -1211,97 +1204,13 @@ target_emulate_synchronize_cache(struct se_task *task)
        return 0;
 }
 
-static int
-target_emulate_noop(struct se_task *task)
+int target_emulate_noop(struct se_task *task)
 {
        task->task_scsi_status = GOOD;
        transport_complete_task(task, 1);
        return 0;
 }
 
-int
-transport_emulate_control_cdb(struct se_task *task)
-{
-       struct se_cmd *cmd = task->task_se_cmd;
-       struct se_device *dev = cmd->se_dev;
-       unsigned short service_action;
-       int ret = 0;
-
-       switch (cmd->t_task_cdb[0]) {
-       case INQUIRY:
-               ret = target_emulate_inquiry(task);
-               break;
-       case READ_CAPACITY:
-               ret = target_emulate_readcapacity(task);
-               break;
-       case MODE_SENSE:
-               ret = target_emulate_modesense(task);
-               break;
-       case MODE_SENSE_10:
-               ret = target_emulate_modesense(task);
-               break;
-       case SERVICE_ACTION_IN:
-               switch (cmd->t_task_cdb[1] & 0x1f) {
-               case SAI_READ_CAPACITY_16:
-                       ret = target_emulate_readcapacity_16(task);
-                       break;
-               default:
-                       pr_err("Unsupported SA: 0x%02x\n",
-                               cmd->t_task_cdb[1] & 0x1f);
-                       return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
-               }
-               break;
-       case REQUEST_SENSE:
-               ret = target_emulate_request_sense(task);
-               break;
-       case UNMAP:
-               ret = target_emulate_unmap(task);
-               break;
-       case WRITE_SAME:
-               ret = target_emulate_write_same(task);
-               break;
-       case WRITE_SAME_16:
-               ret = target_emulate_write_same(task);
-               break;
-       case VARIABLE_LENGTH_CMD:
-               service_action =
-                       get_unaligned_be16(&cmd->t_task_cdb[8]);
-               switch (service_action) {
-               case WRITE_SAME_32:
-                       ret = target_emulate_write_same(task);
-                       break;
-               default:
-                       pr_err("Unsupported VARIABLE_LENGTH_CMD SA:"
-                                       " 0x%02x\n", service_action);
-                       break;
-               }
-               break;
-       case SYNCHRONIZE_CACHE:
-       case 0x91: /* SYNCHRONIZE_CACHE_16: */
-               ret = target_emulate_synchronize_cache(task);
-               break;
-       case ALLOW_MEDIUM_REMOVAL:
-       case ERASE:
-       case REZERO_UNIT:
-       case SEEK_10:
-       case SPACE:
-       case START_STOP:
-       case TEST_UNIT_READY:
-       case VERIFY:
-       case WRITE_FILEMARKS:
-               ret = target_emulate_noop(task);
-               break;
-       default:
-               pr_err("Unsupported SCSI Opcode: 0x%02x for %s\n",
-                       cmd->t_task_cdb[0], dev->transport->name);
-               return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
-       }
-
-       if (ret < 0)
-               return ret;
-       return PYX_TRANSPORT_SENT_TO_TRANSPORT;
-}
-
 /*
  * Write a CDB into @cdb that is based on the one the intiator sent us,
  * but updated to only cover the sectors that the current task handles.
diff --git a/drivers/target/target_core_cdb.h b/drivers/target/target_core_cdb.h
new file mode 100644 (file)
index 0000000..ad6b1e3
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef TARGET_CORE_CDB_H
+#define TARGET_CORE_CDB_H
+
+int target_emulate_inquiry(struct se_task *task);
+int target_emulate_readcapacity(struct se_task *task);
+int target_emulate_readcapacity_16(struct se_task *task);
+int target_emulate_modesense(struct se_task *task);
+int target_emulate_request_sense(struct se_task *task);
+int target_emulate_unmap(struct se_task *task);
+int target_emulate_write_same(struct se_task *task);
+int target_emulate_synchronize_cache(struct se_task *task);
+int target_emulate_noop(struct se_task *task);
+
+#endif /* TARGET_CORE_CDB_H */
index 74015793c03a764c3b9d9d50a39df491da3c573d..f603b12485bd7b1b027682a0d7695baf4b9e0e92 100644 (file)
@@ -52,6 +52,7 @@
 #include <target/target_core_configfs.h>
 
 #include "target_core_alua.h"
+#include "target_core_cdb.h"
 #include "target_core_hba.h"
 #include "target_core_pr.h"
 #include "target_core_ua.h"
@@ -2155,31 +2156,11 @@ check_depth:
                atomic_set(&cmd->t_transport_sent, 1);
 
        spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-       /*
-        * The struct se_cmd->execute_task() function pointer is used
-        * to grab REPORT_LUNS and other CDBs we want to handle before they hit the
-        * struct se_subsystem_api->do_task() caller below.
-        */
-       if (cmd->execute_task) {
-               error = cmd->execute_task(task);
-       } else {
-               /*
-                * Currently for all virtual TCM plugins including IBLOCK, FILEIO and
-                * RAMDISK we use the internal transport_emulate_control_cdb() logic
-                * with struct se_subsystem_api callers for the primary SPC-3 TYPE_DISK
-                * LUN emulation code.
-                *
-                * For TCM/pSCSI and all other SCF_SCSI_DATA_SG_IO_CDB I/O tasks we
-                * call ->do_task() directly and let the underlying TCM subsystem plugin
-                * code handle the CDB emulation.
-                */
-               if ((dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) &&
-                   (!(task->task_se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)))
-                       error = transport_emulate_control_cdb(task);
-               else
-                       error = dev->transport->do_task(task);
-       }
 
+       if (cmd->execute_task)
+               error = cmd->execute_task(task);
+       else
+               error = dev->transport->do_task(task);
        if (error != 0) {
                cmd->transport_error_status = error;
                spin_lock_irqsave(&cmd->t_state_lock, flags);
@@ -2622,6 +2603,13 @@ static int transport_generic_cmd_sequencer(
                 */
        }
 
+       /*
+        * If we operate in passthrough mode we skip most CDB emulation and
+        * instead hand the commands down to the physical SCSI device.
+        */
+       passthrough =
+               (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV);
+
        switch (cdb[0]) {
        case READ_6:
                sectors = transport_get_sectors_6(cdb, cmd, &sector_ret);
@@ -2701,9 +2689,12 @@ static int transport_generic_cmd_sequencer(
                cmd->t_task_lba = transport_lba_32(cdb);
                cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
 
-               if (dev->transport->transport_type ==
-                               TRANSPORT_PLUGIN_PHBA_PDEV)
+               /*
+                * Do now allow BIDI commands for passthrough mode.
+                */
+               if (passthrough)
                        goto out_unsupported_cdb;
+
                /*
                 * Setup BIDI XOR callback to be run after I/O completion.
                 */
@@ -2712,13 +2703,6 @@ static int transport_generic_cmd_sequencer(
                break;
        case VARIABLE_LENGTH_CMD:
                service_action = get_unaligned_be16(&cdb[8]);
-               /*
-                * Determine if this is TCM/PSCSI device and we should disable
-                * internal emulation for this CDB.
-                */
-               passthrough = (dev->transport->transport_type ==
-                                       TRANSPORT_PLUGIN_PHBA_PDEV);
-
                switch (service_action) {
                case XDWRITEREAD_32:
                        sectors = transport_get_sectors_32(cdb, cmd, &sector_ret);
@@ -2732,8 +2716,12 @@ static int transport_generic_cmd_sequencer(
                        cmd->t_task_lba = transport_lba_64_ext(cdb);
                        cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
 
+                       /*
+                        * Do now allow BIDI commands for passthrough mode.
+                        */
                        if (passthrough)
                                goto out_unsupported_cdb;
+
                        /*
                         * Setup BIDI XOR callback to be run during after I/O
                         * completion.
@@ -2759,7 +2747,8 @@ static int transport_generic_cmd_sequencer(
 
                        if (target_check_write_same_discard(&cdb[10], dev) < 0)
                                goto out_invalid_cdb_field;
-
+                       if (!passthrough)
+                               cmd->execute_task = target_emulate_write_same;
                        break;
                default:
                        pr_err("VARIABLE_LENGTH_CMD service action"
@@ -2797,8 +2786,15 @@ static int transport_generic_cmd_sequencer(
        case MODE_SENSE:
                size = cdb[4];
                cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+               if (!passthrough)
+                       cmd->execute_task = target_emulate_modesense;
                break;
        case MODE_SENSE_10:
+               size = (cdb[7] << 8) + cdb[8];
+               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+               if (!passthrough)
+                       cmd->execute_task = target_emulate_modesense;
+               break;
        case GPCMD_READ_BUFFER_CAPACITY:
        case GPCMD_SEND_OPC:
        case LOG_SELECT:
@@ -2867,6 +2863,8 @@ static int transport_generic_cmd_sequencer(
                if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
                        cmd->sam_task_attr = MSG_HEAD_TAG;
                cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+               if (!passthrough)
+                       cmd->execute_task = target_emulate_inquiry;
                break;
        case READ_BUFFER:
                size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
@@ -2875,6 +2873,8 @@ static int transport_generic_cmd_sequencer(
        case READ_CAPACITY:
                size = READ_CAP_LEN;
                cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+               if (!passthrough)
+                       cmd->execute_task = target_emulate_readcapacity;
                break;
        case READ_MEDIA_SERIAL_NUMBER:
        case SECURITY_PROTOCOL_IN:
@@ -2883,6 +2883,21 @@ static int transport_generic_cmd_sequencer(
                cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
                break;
        case SERVICE_ACTION_IN:
+               switch (cmd->t_task_cdb[1] & 0x1f) {
+               case SAI_READ_CAPACITY_16:
+                       if (!passthrough)
+                               cmd->execute_task =
+                                       target_emulate_readcapacity_16;
+                       break;
+               default:
+                       if (passthrough)
+                               break;
+
+                       pr_err("Unsupported SA: 0x%02x\n",
+                               cmd->t_task_cdb[1] & 0x1f);
+                       goto out_unsupported_cdb;
+               }
+               /*FALLTHROUGH*/
        case ACCESS_CONTROL_IN:
        case ACCESS_CONTROL_OUT:
        case EXTENDED_COPY:
@@ -2913,6 +2928,8 @@ static int transport_generic_cmd_sequencer(
        case REQUEST_SENSE:
                size = cdb[4];
                cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+               if (!passthrough)
+                       cmd->execute_task = target_emulate_request_sense;
                break;
        case READ_ELEMENT_STATUS:
                size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9];
@@ -2977,8 +2994,9 @@ static int transport_generic_cmd_sequencer(
                size = transport_get_size(sectors, cdb, cmd);
                cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
 
-               if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)
+               if (passthrough)
                        break;
+
                /*
                 * Check to ensure that LBA + Range does not exceed past end of
                 * device for IBLOCK and FILEIO ->do_sync_cache() backend calls
@@ -2987,10 +3005,13 @@ static int transport_generic_cmd_sequencer(
                        if (transport_cmd_get_valid_sectors(cmd) < 0)
                                goto out_invalid_cdb_field;
                }
+               cmd->execute_task = target_emulate_synchronize_cache;
                break;
        case UNMAP:
                size = get_unaligned_be16(&cdb[7]);
                cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+               if (!passthrough)
+                       cmd->execute_task = target_emulate_unmap;
                break;
        case WRITE_SAME_16:
                sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
@@ -3009,6 +3030,8 @@ static int transport_generic_cmd_sequencer(
 
                if (target_check_write_same_discard(&cdb[1], dev) < 0)
                        goto out_invalid_cdb_field;
+               if (!passthrough)
+                       cmd->execute_task = target_emulate_write_same;
                break;
        case WRITE_SAME:
                sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
@@ -3030,20 +3053,26 @@ static int transport_generic_cmd_sequencer(
                 */
                if (target_check_write_same_discard(&cdb[1], dev) < 0)
                        goto out_invalid_cdb_field;
+               if (!passthrough)
+                       cmd->execute_task = target_emulate_write_same;
                break;
        case ALLOW_MEDIUM_REMOVAL:
-       case GPCMD_CLOSE_TRACK:
        case ERASE:
-       case INITIALIZE_ELEMENT_STATUS:
-       case GPCMD_LOAD_UNLOAD:
        case REZERO_UNIT:
        case SEEK_10:
-       case GPCMD_SET_SPEED:
        case SPACE:
        case START_STOP:
        case TEST_UNIT_READY:
        case VERIFY:
        case WRITE_FILEMARKS:
+               cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
+               if (!passthrough)
+                       cmd->execute_task = target_emulate_noop;
+               break;
+       case GPCMD_CLOSE_TRACK:
+       case INITIALIZE_ELEMENT_STATUS:
+       case GPCMD_LOAD_UNLOAD:
+       case GPCMD_SET_SPEED:
        case MOVE_MEDIUM:
                cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
                break;
@@ -3100,6 +3129,11 @@ static int transport_generic_cmd_sequencer(
                cmd->data_length = size;
        }
 
+       /* reject any command that we don't have a handler for */
+       if (!(passthrough || cmd->execute_task ||
+            (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)))
+               goto out_unsupported_cdb;
+
        /* Let's limit control cdbs to a page, for simplicity's sake. */
        if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) &&
            size > PAGE_SIZE)