]> Pileus Git - ~andy/linux/blobdiff - drivers/target/target_core_transport.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide
[~andy/linux] / drivers / target / target_core_transport.c
index 3ad8db2d3ad3ba11d49f844f5deeb8f7e95303d0..3400ae6e93f83d2ae5b25395b97bbd6158877ec0 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/kthread.h>
 #include <linux/in.h>
 #include <linux/cdrom.h>
+#include <linux/module.h>
 #include <asm/unaligned.h>
 #include <net/sock.h>
 #include <net/tcp.h>
@@ -52,6 +53,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,62 +2157,20 @@ 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);
-               if (error != 0) {
-                       cmd->transport_error_status = error;
-                       spin_lock_irqsave(&cmd->t_state_lock, flags);
-                       task->task_flags &= ~TF_ACTIVE;
-                       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-                       atomic_set(&cmd->t_transport_sent, 0);
-                       transport_stop_tasks_for_cmd(cmd);
-                       atomic_inc(&dev->depth_left);
-                       transport_generic_request_failure(cmd, 0, 1);
-                       goto check_depth;
-               }
-               /*
-                * Handle the successful completion for execute_task()
-                * for synchronous operation, following SCF_EMULATE_CDB_ASYNC
-                * Otherwise the caller is expected to complete the task with
-                * proper status.
-                */
-               if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) {
-                       cmd->scsi_status = SAM_STAT_GOOD;
-                       task->task_scsi_status = GOOD;
-                       transport_complete_task(task, 1);
-               }
-       } 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 (error != 0) {
-                       cmd->transport_error_status = error;
-                       spin_lock_irqsave(&cmd->t_state_lock, flags);
-                       task->task_flags &= ~TF_ACTIVE;
-                       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-                       atomic_set(&cmd->t_transport_sent, 0);
-                       transport_stop_tasks_for_cmd(cmd);
-                       atomic_inc(&dev->depth_left);
-                       transport_generic_request_failure(cmd, 0, 1);
-               }
+       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);
+               task->task_flags &= ~TF_ACTIVE;
+               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+               atomic_set(&cmd->t_transport_sent, 0);
+               transport_stop_tasks_for_cmd(cmd);
+               atomic_inc(&dev->depth_left);
+               transport_generic_request_failure(cmd, 0, 1);
        }
 
        goto check_depth;
@@ -2644,6 +2604,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);
@@ -2723,9 +2690,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.
                 */
@@ -2734,13 +2704,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);
@@ -2754,8 +2717,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.
@@ -2781,7 +2748,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"
@@ -2819,8 +2787,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:
@@ -2889,6 +2864,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];
@@ -2897,6 +2874,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:
@@ -2905,6 +2884,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:
@@ -2935,6 +2929,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];
@@ -2999,13 +2995,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;
-               /*
-                * Set SCF_EMULATE_CDB_ASYNC to ensure asynchronous operation
-                * for SYNCHRONIZE_CACHE* Immed=1 case in __transport_execute_tasks()
-                */
-               cmd->se_cmd_flags |= SCF_EMULATE_CDB_ASYNC;
+
                /*
                 * Check to ensure that LBA + Range does not exceed past end of
                 * device for IBLOCK and FILEIO ->do_sync_cache() backend calls
@@ -3014,10 +3006,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);
@@ -3036,6 +3031,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);
@@ -3057,20 +3054,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;
@@ -3127,6 +3130,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)